* config/djgpp/fnchange.lst: Add translations for cpu-microblaze.c,
[external/binutils.git] / gdb / microblaze-linux-tdep.c
1 /* Target-dependent code for Xilinx MicroBlaze.
2
3    Copyright 2009 Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include "defs.h"
21 #include "frame.h"
22 #include "inferior.h"
23 #include "symtab.h"
24 #include "target.h"
25 #include "gdbcore.h"
26 #include "gdbcmd.h"
27 #include "symfile.h"
28 #include "objfiles.h"
29 #include "regcache.h"
30 #include "value.h"
31 #include "osabi.h"
32 #include "regset.h"
33 #include "solib-svr4.h"
34 #include "microblaze-tdep.h"
35 #include "trad-frame.h"
36 #include "frame-unwind.h"
37 #include "tramp-frame.h"
38
39
40 static int
41 microblaze_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
42 {
43   CORE_ADDR addr = bp_tgt->placed_address;
44   const gdb_byte *bp;
45   int val;
46   int bplen;
47   gdb_byte old_contents[BREAKPOINT_MAX];
48
49   /* Determine appropriate breakpoint contents and size for this address.  */
50   bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
51   if (bp == NULL)
52     error (_("Software breakpoints not implemented for this target."));
53
54   val = target_read_memory (addr, old_contents, bplen);
55
56   /* If our breakpoint is no longer at the address, this means that the
57      program modified the code on us, so it is wrong to put back the
58      old value.  */
59   if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
60     val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
61
62   return val;
63 }
64
65 static void
66 microblaze_linux_sigtramp_cache (struct frame_info *next_frame,
67                                  struct trad_frame_cache *this_cache,
68                                  CORE_ADDR func, LONGEST offset,
69                                  int bias)
70 {
71   CORE_ADDR base;
72   CORE_ADDR gpregs;
73   int regnum;
74   struct gdbarch *gdbarch = get_frame_arch (next_frame);
75   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
76
77   base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
78   if (bias > 0 && frame_pc_unwind (next_frame) != func)
79     /* See below, some signal trampolines increment the stack as their
80        first instruction, need to compensate for that.  */
81     base -= bias;
82
83   /* Find the address of the register buffer.  */
84   gpregs = base + offset;
85
86   /* Registers saved on stack.  */
87   for (regnum = 0; regnum < MICROBLAZE_BTR_REGNUM; regnum++)
88     trad_frame_set_reg_addr (this_cache, regnum, 
89                              gpregs + regnum * MICROBLAZE_REGISTER_SIZE);
90   trad_frame_set_id (this_cache, frame_id_build (base, func));
91 }
92
93
94 static void
95 microblaze_linux_sighandler_cache_init (const struct tramp_frame *self,
96                                         struct frame_info *next_frame,
97                                         struct trad_frame_cache *this_cache,
98                                         CORE_ADDR func)
99 {
100   microblaze_linux_sigtramp_cache (next_frame, this_cache, func,
101                                    0 /* Offset to ucontext_t.  */
102                                    + 24 /* Offset to .reg.  */,
103                                    0);
104 }
105
106 static struct tramp_frame microblaze_linux_sighandler_tramp_frame = 
107 {
108   SIGTRAMP_FRAME,
109   4,
110   {
111     { 0x31800077, -1 }, /* addik R12,R0,119.  */
112     { 0xb9cc0008, -1 }, /* brki R14,8.  */
113     { TRAMP_SENTINEL_INSN },
114   },
115   microblaze_linux_sighandler_cache_init
116 };
117
118
119 static void
120 microblaze_linux_init_abi (struct gdbarch_info info,
121                            struct gdbarch *gdbarch)
122 {
123   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
124
125   set_gdbarch_memory_remove_breakpoint (gdbarch,
126                                         microblaze_linux_memory_remove_breakpoint);
127
128   /* Shared library handling.  */
129   set_solib_svr4_fetch_link_map_offsets (gdbarch,
130                                          svr4_ilp32_fetch_link_map_offsets);
131
132   /* Trampolines.  */
133   tramp_frame_prepend_unwinder (gdbarch,
134                                 &microblaze_linux_sighandler_tramp_frame);
135 }
136
137 void
138 _initialize_microblaze_linux_tdep (void)
139 {
140   gdbarch_register_osabi (bfd_arch_microblaze, 0, GDB_OSABI_LINUX, 
141                           microblaze_linux_init_abi);
142 }