X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fm32r-linux-tdep.c;h=83d31fd3fc72bc86efcb5b7f8f3ac7d9010c706d;hb=4bd7dc42558fcf53bb0c783f852f03dcac38866f;hp=d2ca1a928f4eb2692f139781247f24738c0ed431;hpb=9b32d5267e5b0e0eb9100353a7b555c06a817466;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/m32r-linux-tdep.c b/gdb/m32r-linux-tdep.c index d2ca1a928f..83d31fd3fc 100644 --- a/gdb/m32r-linux-tdep.c +++ b/gdb/m32r-linux-tdep.c @@ -1,12 +1,12 @@ /* Target-dependent code for GNU/Linux m32r. - Copyright 2004 Free Software Foundation, Inc. + Copyright (C) 2004-2015 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 2 of the License, or + 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, @@ -15,9 +15,7 @@ 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, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "gdbcore.h" @@ -27,16 +25,18 @@ #include "inferior.h" #include "osabi.h" #include "reggroups.h" - -#include "gdb_string.h" +#include "regset.h" #include "glibc-tdep.h" #include "solib-svr4.h" +#include "symtab.h" #include "trad-frame.h" #include "frame-unwind.h" #include "m32r-tdep.h" +#include "linux-tdep.h" + /* Recognizing signal handler frames. */ @@ -76,7 +76,7 @@ to the ones used by the kernel. Therefore, these trampolines are supported too. */ -static const unsigned char linux_sigtramp_code[] = { +static const gdb_byte linux_sigtramp_code[] = { 0x67, 0x77, 0x10, 0xf2, }; @@ -84,9 +84,9 @@ static const unsigned char linux_sigtramp_code[] = { the routine. Otherwise, return 0. */ static CORE_ADDR -m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) +m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *this_frame) { - unsigned char buf[4]; + gdb_byte buf[4]; /* We only recognize a signal trampoline if PC is at the start of one of the instructions. We optimize for finding the PC at the @@ -98,7 +98,7 @@ m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) if (pc % 2 != 0) { - if (!safe_frame_unwind_memory (next_frame, pc, buf, 2)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, 2)) return 0; if (memcmp (buf, linux_sigtramp_code, 2) == 0) @@ -107,7 +107,7 @@ m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) return 0; } - if (!safe_frame_unwind_memory (next_frame, pc, buf, 4)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, 4)) return 0; if (memcmp (buf, linux_sigtramp_code, 4) != 0) @@ -124,7 +124,7 @@ m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) The effect is to call the system call rt_sigreturn. */ -static const unsigned char linux_rt_sigtramp_code[] = { +static const gdb_byte linux_rt_sigtramp_code[] = { 0x97, 0xf0, 0x00, 0xad, 0x10, 0xf2, 0xf0, 0x00, }; @@ -132,9 +132,9 @@ static const unsigned char linux_rt_sigtramp_code[] = { of the routine. Otherwise, return 0. */ static CORE_ADDR -m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) +m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *this_frame) { - unsigned char buf[4]; + gdb_byte buf[4]; /* We only recognize a signal trampoline if PC is at the start of one of the instructions. We optimize for finding the PC at the @@ -147,12 +147,12 @@ m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) if (pc % 2 != 0) return 0; - if (!safe_frame_unwind_memory (next_frame, pc, buf, 4)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, 4)) return 0; if (memcmp (buf, linux_rt_sigtramp_code, 4) == 0) { - if (!safe_frame_unwind_memory (next_frame, pc + 4, buf, 4)) + if (!safe_frame_unwind_memory (this_frame, pc + 4, buf, 4)) return 0; if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0) @@ -160,7 +160,7 @@ m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) } else if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0) { - if (!safe_frame_unwind_memory (next_frame, pc - 4, buf, 4)) + if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, 4)) return 0; if (memcmp (buf, linux_rt_sigtramp_code, 4) == 0) @@ -171,8 +171,8 @@ m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) } static int -m32r_linux_pc_in_sigtramp (CORE_ADDR pc, char *name, - struct frame_info *next_frame) +m32r_linux_pc_in_sigtramp (CORE_ADDR pc, const char *name, + struct frame_info *this_frame) { /* If we have NAME, we can optimize the search. The trampolines are named __restore and __restore_rt. However, they aren't dynamically @@ -180,8 +180,8 @@ m32r_linux_pc_in_sigtramp (CORE_ADDR pc, char *name, be part of the preceding function. This should always be sigaction, __sigaction, or __libc_sigaction (all aliases to the same function). */ if (name == NULL || strstr (name, "sigaction") != NULL) - return (m32r_linux_sigtramp_start (pc, next_frame) != 0 - || m32r_linux_rt_sigtramp_start (pc, next_frame) != 0); + return (m32r_linux_sigtramp_start (pc, this_frame) != 0 + || m32r_linux_rt_sigtramp_start (pc, this_frame) != 0); return (strcmp ("__restore", name) == 0 || strcmp ("__restore_rt", name) == 0); @@ -222,7 +222,7 @@ struct m32r_frame_cache }; static struct m32r_frame_cache * -m32r_linux_sigtramp_frame_cache (struct frame_info *next_frame, +m32r_linux_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache) { struct m32r_frame_cache *cache; @@ -233,26 +233,26 @@ m32r_linux_sigtramp_frame_cache (struct frame_info *next_frame, return (*this_cache); cache = FRAME_OBSTACK_ZALLOC (struct m32r_frame_cache); (*this_cache) = cache; - cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - cache->base = frame_unwind_register_unsigned (next_frame, M32R_SP_REGNUM); + cache->base = get_frame_register_unsigned (this_frame, M32R_SP_REGNUM); sigcontext_addr = cache->base + 4; - cache->pc = frame_pc_unwind (next_frame); - addr = m32r_linux_sigtramp_start (cache->pc, next_frame); + cache->pc = get_frame_pc (this_frame); + addr = m32r_linux_sigtramp_start (cache->pc, this_frame); if (addr == 0) { /* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR accordingly. */ - addr = m32r_linux_rt_sigtramp_start (cache->pc, next_frame); + addr = m32r_linux_rt_sigtramp_start (cache->pc, this_frame); if (addr) sigcontext_addr += 128; else - addr = frame_func_unwind (next_frame); + addr = get_frame_func (this_frame); } cache->pc = addr; - cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); for (regnum = 0; regnum < sizeof (m32r_linux_sc_reg_offset) / 4; regnum++) { @@ -265,48 +265,183 @@ m32r_linux_sigtramp_frame_cache (struct frame_info *next_frame, } static void -m32r_linux_sigtramp_frame_this_id (struct frame_info *next_frame, +m32r_linux_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { struct m32r_frame_cache *cache = - m32r_linux_sigtramp_frame_cache (next_frame, this_cache); + m32r_linux_sigtramp_frame_cache (this_frame, this_cache); (*this_id) = frame_id_build (cache->base, cache->pc); } -static void -m32r_linux_sigtramp_frame_prev_register (struct frame_info *next_frame, - void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, - CORE_ADDR *addrp, - int *realnump, void *valuep) +static struct value * +m32r_linux_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) { struct m32r_frame_cache *cache = - m32r_linux_sigtramp_frame_cache (next_frame, this_cache); + m32r_linux_sigtramp_frame_cache (this_frame, this_cache); + + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum); +} + +static int +m32r_linux_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (m32r_linux_pc_in_sigtramp (pc, name, this_frame)) + return 1; - trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum, - optimizedp, lvalp, addrp, realnump, valuep); + return 0; } static const struct frame_unwind m32r_linux_sigtramp_frame_unwind = { SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, m32r_linux_sigtramp_frame_this_id, - m32r_linux_sigtramp_frame_prev_register + m32r_linux_sigtramp_frame_prev_register, + NULL, + m32r_linux_sigtramp_frame_sniffer }; -static const struct frame_unwind * -m32r_linux_sigtramp_frame_sniffer (struct frame_info *next_frame) +/* Mapping between the registers in `struct pt_regs' + format and GDB's register array layout. */ + +static int m32r_pt_regs_offset[] = { + 4 * 4, /* r0 */ + 4 * 5, /* r1 */ + 4 * 6, /* r2 */ + 4 * 7, /* r3 */ + 4 * 0, /* r4 */ + 4 * 1, /* r5 */ + 4 * 2, /* r6 */ + 4 * 8, /* r7 */ + 4 * 9, /* r8 */ + 4 * 10, /* r9 */ + 4 * 11, /* r10 */ + 4 * 12, /* r11 */ + 4 * 13, /* r12 */ + 4 * 24, /* fp */ + 4 * 25, /* lr */ + 4 * 23, /* sp */ + 4 * 19, /* psw */ + 4 * 19, /* cbr */ + 4 * 26, /* spi */ + 4 * 23, /* spu */ + 4 * 22, /* bpc */ + 4 * 20, /* pc */ + 4 * 16, /* accl */ + 4 * 15 /* acch */ +}; + +#define PSW_OFFSET (4 * 19) +#define BBPSW_OFFSET (4 * 21) +#define SPU_OFFSET (4 * 23) +#define SPI_OFFSET (4 * 26) + +#define M32R_LINUX_GREGS_SIZE (4 * 28) + +static void +m32r_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *gregs, size_t size) +{ + const gdb_byte *regs = gregs; + enum bfd_endian byte_order = + gdbarch_byte_order (get_regcache_arch (regcache)); + ULONGEST psw, bbpsw; + gdb_byte buf[4]; + const gdb_byte *p; + int i; + + psw = extract_unsigned_integer (regs + PSW_OFFSET, 4, byte_order); + bbpsw = extract_unsigned_integer (regs + BBPSW_OFFSET, 4, byte_order); + psw = ((0x00c1 & bbpsw) << 8) | ((0xc100 & psw) >> 8); + + for (i = 0; i < ARRAY_SIZE (m32r_pt_regs_offset); i++) + { + if (regnum != -1 && regnum != i) + continue; + + switch (i) + { + case PSW_REGNUM: + store_unsigned_integer (buf, 4, byte_order, psw); + p = buf; + break; + case CBR_REGNUM: + store_unsigned_integer (buf, 4, byte_order, psw & 1); + p = buf; + break; + case M32R_SP_REGNUM: + p = regs + ((psw & 0x80) ? SPU_OFFSET : SPI_OFFSET); + break; + default: + p = regs + m32r_pt_regs_offset[i]; + } + + regcache_raw_supply (regcache, i, p); + } +} + +static void +m32r_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t size) { - CORE_ADDR pc = frame_pc_unwind (next_frame); - char *name; + gdb_byte *regs = gregs; + int i; + enum bfd_endian byte_order = + gdbarch_byte_order (get_regcache_arch (regcache)); + ULONGEST psw; + gdb_byte buf[4]; - find_pc_partial_function (pc, &name, NULL, NULL); - if (m32r_linux_pc_in_sigtramp (pc, name, next_frame)) - return &m32r_linux_sigtramp_frame_unwind; + regcache_raw_collect (regcache, PSW_REGNUM, buf); + psw = extract_unsigned_integer (buf, 4, byte_order); + + for (i = 0; i < ARRAY_SIZE (m32r_pt_regs_offset); i++) + { + if (regnum != -1 && regnum != i) + continue; + + switch (i) + { + case PSW_REGNUM: + store_unsigned_integer (regs + PSW_OFFSET, 4, byte_order, + (psw & 0xc1) << 8); + store_unsigned_integer (regs + BBPSW_OFFSET, 4, byte_order, + (psw >> 8) & 0xc1); + break; + case CBR_REGNUM: + break; + case M32R_SP_REGNUM: + regcache_raw_collect (regcache, i, regs + + ((psw & 0x80) ? SPU_OFFSET : SPI_OFFSET)); + break; + default: + regcache_raw_collect (regcache, i, + regs + m32r_pt_regs_offset[i]); + } + } +} - return NULL; +static const struct regset m32r_linux_gregset = { + NULL, + m32r_linux_supply_gregset, m32r_linux_collect_gregset +}; + +static void +m32r_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + cb (".reg", M32R_LINUX_GREGS_SIZE, &m32r_linux_gregset, NULL, cb_data); } static void @@ -314,15 +449,26 @@ m32r_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + linux_init_abi (info, gdbarch); + /* Since EVB register is not available for native debug, we reduce the number of registers. */ set_gdbarch_num_regs (gdbarch, M32R_NUM_REGS - 1); - frame_unwind_append_sniffer (gdbarch, m32r_linux_sigtramp_frame_sniffer); + frame_unwind_append_unwinder (gdbarch, &m32r_linux_sigtramp_frame_unwind); /* GNU/Linux uses SVR4-style shared libraries. */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); + + /* Core file support. */ + set_gdbarch_iterate_over_regset_sections + (gdbarch, m32r_linux_iterate_over_regset_sections); + + /* Enable TLS support. */ + set_gdbarch_fetch_tls_load_module_address (gdbarch, + svr4_fetch_objfile_link_map); } /* Provide a prototype to silence -Wmissing-prototypes. */