/* Target-dependent code for Xilinx MicroBlaze. Copyright 2009 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" #include "frame.h" #include "inferior.h" #include "symtab.h" #include "target.h" #include "gdbcore.h" #include "gdbcmd.h" #include "symfile.h" #include "objfiles.h" #include "regcache.h" #include "value.h" #include "osabi.h" #include "regset.h" #include "solib-svr4.h" #include "microblaze-tdep.h" #include "trad-frame.h" #include "frame-unwind.h" #include "tramp-frame.h" static int microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; const gdb_byte *bp; int val; int bplen; gdb_byte old_contents[BREAKPOINT_MAX]; /* Determine appropriate breakpoint contents and size for this address. */ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen); if (bp == NULL) error (_("Software breakpoints not implemented for this target.")); val = target_read_memory (addr, old_contents, bplen); /* If our breakpoint is no longer at the address, this means that the program modified the code on us, so it is wrong to put back the old value. */ if (val == 0 && memcmp (bp, old_contents, bplen) == 0) val = target_write_memory (addr, bp_tgt->shadow_contents, bplen); return val; } static void microblaze_linux_sigtramp_cache (struct frame_info *next_frame, struct trad_frame_cache *this_cache, CORE_ADDR func, LONGEST offset, int bias) { CORE_ADDR base; CORE_ADDR gpregs; int regnum; struct gdbarch *gdbarch = get_frame_arch (next_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); base = frame_unwind_register_unsigned (next_frame, MICROBLAZE_SP_REGNUM); if (bias > 0 && get_frame_address_in_block (next_frame) != func) /* See below, some signal trampolines increment the stack as their first instruction, need to compensate for that. */ base -= bias; /* Find the address of the register buffer. */ gpregs = base + offset; /* Registers saved on stack. */ for (regnum = 0; regnum < MICROBLAZE_BTR_REGNUM; regnum++) trad_frame_set_reg_addr (this_cache, regnum, gpregs + regnum * MICROBLAZE_REGISTER_SIZE); trad_frame_set_id (this_cache, frame_id_build (base, func)); } static void microblaze_linux_sighandler_cache_init (const struct tramp_frame *self, struct frame_info *next_frame, struct trad_frame_cache *this_cache, CORE_ADDR func) { microblaze_linux_sigtramp_cache (next_frame, this_cache, func, 0 /* Offset to ucontext_t. */ + 24 /* Offset to .reg. */, 0); } static struct tramp_frame microblaze_linux_sighandler_tramp_frame = { SIGTRAMP_FRAME, 4, { { 0x31800077, -1 }, /* addik R12,R0,119. */ { 0xb9cc0008, -1 }, /* brki R14,8. */ { TRAMP_SENTINEL_INSN }, }, microblaze_linux_sighandler_cache_init }; static void microblaze_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); set_gdbarch_memory_remove_breakpoint (gdbarch, microblaze_linux_memory_remove_breakpoint); /* Shared library handling. */ set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); /* Trampolines. */ tramp_frame_prepend_unwinder (gdbarch, µblaze_linux_sighandler_tramp_frame); } void _initialize_microblaze_linux_tdep (void) { gdbarch_register_osabi (bfd_arch_microblaze, 0, GDB_OSABI_LINUX, microblaze_linux_init_abi); }