From 9b32d5267e5b0e0eb9100353a7b555c06a817466 Mon Sep 17 00:00:00 2001 From: Kazuhiro Inaoka Date: Fri, 1 Oct 2004 07:29:34 +0000 Subject: [PATCH] 2004-09-30 Kei Sakamoto Add m32r-linux support. * configure.tgt: Add m32r*-*-linux*. * Makefile.in (ALLDEPFILES): Add m32r-tdep.c, m32r-linux-nat.c and m32r-linux-tdep.c. (m32r-linux-nat.o, m32r-linux-tdep.o): New dependencies. * m32r-tdep.c: Move some definitions to m32r-tdep.h. * config/djgpp/fnchange.lst: Add m32r-linux-nat.c and m32r-linux-tdep.c. * m32r-tdep.h, m32r-linux-nat.c, m32r-linux-tdep.c, config/m32r/linux.mh, config/m32r/linux.mt, config/m32r/nm-linux.h: New files. --- gdb/ChangeLog | 14 ++ gdb/Makefile.in | 11 +- gdb/config/djgpp/fnchange.lst | 2 + gdb/config/m32r/linux.mh | 8 + gdb/config/m32r/linux.mt | 6 + gdb/config/m32r/nm-linux.h | 29 +++ gdb/configure.tgt | 3 +- gdb/m32r-linux-nat.c | 235 ++++++++++++++++++++++++ gdb/m32r-linux-tdep.c | 336 ++++++++++++++++++++++++++++++++++ gdb/m32r-tdep.c | 38 +--- gdb/m32r-tdep.h | 52 ++++++ 11 files changed, 701 insertions(+), 33 deletions(-) create mode 100644 gdb/config/m32r/linux.mh create mode 100644 gdb/config/m32r/linux.mt create mode 100644 gdb/config/m32r/nm-linux.h create mode 100644 gdb/m32r-linux-nat.c create mode 100644 gdb/m32r-linux-tdep.c create mode 100644 gdb/m32r-tdep.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a2aeda23fca..95b5c605671 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2004-09-30 Kei Sakamoto + + Add m32r-linux support. + * configure.tgt: Add m32r*-*-linux*. + * Makefile.in (ALLDEPFILES): Add m32r-tdep.c, m32r-linux-nat.c + and m32r-linux-tdep.c. + (m32r-linux-nat.o, m32r-linux-tdep.o): New dependencies. + * m32r-tdep.c: Move some definitions to m32r-tdep.h. + * config/djgpp/fnchange.lst: Add m32r-linux-nat.c and + m32r-linux-tdep.c. + * m32r-tdep.h, m32r-linux-nat.c, m32r-linux-tdep.c, + config/m32r/linux.mh, config/m32r/linux.mt, + config/m32r/nm-linux.h: New files. + 2004-09-30 Joel Brobecker * mips-tdep.c (mips32_decode_reg_save): Remove, unused. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7b9ed712f3d..f4b73a42e39 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -720,6 +720,7 @@ libunwind_frame_h = libunwind-frame.h $(libunwind_h) linespec_h = linespec.h linux_nat_h = linux-nat.h $(target_h) m2_lang_h = m2-lang.h +m32r_tdep_h = m32r-tdep.h m68k_tdep_h = m68k-tdep.h m88k_tdep_h = m88k-tdep.h macroexp_h = macroexp.h @@ -1382,6 +1383,8 @@ ALLDEPFILES = \ libunwind-frame.c \ lynx-nat.c m3-nat.c \ m68hc11-tdep.c \ + m32r-tdep.c \ + m32r-linux-nat.c m32r-linux-tdep.c \ m68k-tdep.c \ m68kbsd-nat.c m68kbsd-tdep.c \ m88k-tdep.c m88kbsd-nat.c \ @@ -2131,6 +2134,12 @@ m2-typeprint.o: m2-typeprint.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(value_h) $(gdbcore_h) $(target_h) $(m2_lang_h) m2-valprint.o: m2-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \ $(m2_lang_h) +m32r-linux-nat.o: m32r-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ + $(regcache_h) $(linux_nat_h) $(gdb_assert_h) $(gdb_string_h) \ + $(m32r_tdep_h) +m32r-linux-tdep.o: m32r-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \ + $(value_h) $(regcache_h) $(inferior_h) $(osabi_h) $(reggroups_h) \ + $(gdb_string_h) $(glibc_tdep_h) $(solib_svr4_h) $(m32r_tdep_h) m32r-rom.o: m32r-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ $(serial_h) $(symtab_h) $(command_h) $(gdbcmd_h) $(symfile_h) \ $(gdb_string_h) $(objfiles_h) $(inferior_h) $(regcache_h) @@ -2139,7 +2148,7 @@ m32r-tdep.o: m32r-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) \ $(frame_base_h) $(symtab_h) $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) \ $(gdb_string_h) $(value_h) $(inferior_h) $(symfile_h) $(objfiles_h) \ $(language_h) $(arch_utils_h) $(regcache_h) $(trad_frame_h) \ - $(dis_asm_h) $(gdb_assert_h) + $(dis_asm_h) $(gdb_assert_h) $(m32r_tdep_h) m68hc11-tdep.o: m68hc11-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) \ $(frame_base_h) $(dwarf2_frame_h) $(trad_frame_h) $(symtab_h) \ $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) $(value_h) \ diff --git a/gdb/config/djgpp/fnchange.lst b/gdb/config/djgpp/fnchange.lst index 4337b7261a0..a63c9d6b0a2 100644 --- a/gdb/config/djgpp/fnchange.lst +++ b/gdb/config/djgpp/fnchange.lst @@ -138,6 +138,8 @@ @V@/gdb/ia64-linux-nat.c @V@/gdb/ia64lx-tdep.c @V@/gdb/jv-exp.tab.c @V@/gdb/jv-exp_tab.c @V@/gdb/m2-exp.tab.c @V@/gdb/m2-exp_tab.c +@V@/gdb/m32r-linux-nat.c @V@/gdb/m32rlnxnat.c +@V@/gdb/m32r-linux-tdep.c @V@/gdb/m32rlnxtdep.c @V@/gdb/m68klinux-nat.c @V@/gdb/m68kl-nat.c @V@/gdb/m68klinux-tdep.c @V@/gdb/m68kl-tdep.c @V@/gdb/m68kbsd-nat.c @V@/gdb/m68bsd-nat.c diff --git a/gdb/config/m32r/linux.mh b/gdb/config/m32r/linux.mh new file mode 100644 index 00000000000..bfa8cf60fe8 --- /dev/null +++ b/gdb/config/m32r/linux.mh @@ -0,0 +1,8 @@ +# Host: M32R based machine running GNU/Linux + +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \ + m32r-linux-nat.o gcore.o proc-service.o thread-db.o \ + linux-nat.o + +LOADLIBES= -ldl -rdynamic diff --git a/gdb/config/m32r/linux.mt b/gdb/config/m32r/linux.mt new file mode 100644 index 00000000000..09e5630f8fb --- /dev/null +++ b/gdb/config/m32r/linux.mt @@ -0,0 +1,6 @@ +# Target: Renesas M32R running GNU/Linux +TDEPFILES= m32r-tdep.o m32r-linux-tdep.o remote-m32r-sdi.o glibc-tdep.o solib.o solib-svr4.o solib-legacy.o +DEPRECATED_TM_FILE= config/tm-linux.h + +SIM_OBS = remote-sim.o +SIM = ../sim/m32r/libsim.a diff --git a/gdb/config/m32r/nm-linux.h b/gdb/config/m32r/nm-linux.h new file mode 100644 index 00000000000..ecfeebad88a --- /dev/null +++ b/gdb/config/m32r/nm-linux.h @@ -0,0 +1,29 @@ +/* Definitions to make GDB run on an M32R based machine under GNU/Linux. + Copyright 2004 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 + (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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef NM_M32R_LINUX_H +#define NM_M32R_LINUX_H + +#include "config/nm-linux.h" + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +#endif /* NM_M32R_LINUX_H */ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index cb2427e8e09..0b1f627960e 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -106,7 +106,8 @@ ia64-*-linux*) gdb_target=linux ;; ia64*-*-*) gdb_target=ia64 ;; -m32r-*-*) gdb_target=m32r ;; +m32r*-*-linux*) gdb_target=linux ;; +m32r*-*-*) gdb_target=m32r ;; m68hc11*-*-*|m6811*-*-*) gdb_target=m68hc11 ;; diff --git a/gdb/m32r-linux-nat.c b/gdb/m32r-linux-nat.c new file mode 100644 index 00000000000..7b35087319e --- /dev/null +++ b/gdb/m32r-linux-nat.c @@ -0,0 +1,235 @@ +/* Native-dependent code for GNU/Linux m32r. + + Copyright 2004 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 + (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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "regcache.h" +#include "linux-nat.h" + +#include "gdb_assert.h" +#include "gdb_string.h" +#include +#include +#include + +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" + +#include "m32r-tdep.h" + + + + +/* Since EVB register is not available for native debug, we reduce + the number of registers. */ +#define M32R_LINUX_NUM_REGS (M32R_NUM_REGS - 1) + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. */ +static int regmap[] = { + 4, 5, 6, 7, 0, 1, 2, 8, + 9, 10, 11, 12, 13, 24, 25, 23, + 19, 19, 26, 23, 22, 20, 16, 15 +}; + +#define PSW_REGMAP 19 +#define BBPSW_REGMAP 21 +#define SPU_REGMAP 23 +#define SPI_REGMAP 26 + +/* Doee apply to the corresponding SET requests as well. */ +#define GETREGS_SUPPLIES(regno) (0 <= (regno) && (regno) <= M32R_LINUX_NUM_REGS) + + + +/* Transfering the general-purpose registers between GDB, inferiors + and core files. */ + +/* Fill GDB's register array with the general-purpose register values + in *GREGSETP. */ + +void +supply_gregset (elf_gregset_t * gregsetp) +{ + elf_greg_t *regp = (elf_greg_t *) gregsetp; + int i; + unsigned long psw, bbpsw; + + psw = *(regp + PSW_REGMAP); + bbpsw = *(regp + BBPSW_REGMAP); + + for (i = 0; i < M32R_LINUX_NUM_REGS; i++) + { + switch (i) + { + case PSW_REGNUM: + *(regp + regmap[i]) = + ((0x00c1 & bbpsw) << 8) | ((0xc100 & psw) >> 8); + break; + case CBR_REGNUM: + *(regp + regmap[i]) = ((psw >> 8) & 1); + break; + } + + if (i != M32R_SP_REGNUM) + regcache_raw_supply (current_regcache, i, regp + regmap[i]); + else if (psw & 0x8000) + regcache_raw_supply (current_regcache, i, regp + SPU_REGMAP); + else + regcache_raw_supply (current_regcache, i, regp + SPI_REGMAP); + } +} + +/* Fetch all general-purpose registers from process/thread TID and + store their values in GDB's register array. */ + +static void +fetch_regs (int tid) +{ + elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0) + perror_with_name ("Couldn't get registers"); + + supply_gregset (®s); +} + +/* Fill register REGNO (if it is a general-purpose register) in + *GREGSETPS with the value in GDB's register array. If REGNO is -1, + do this for all registers. */ + +void +fill_gregset (elf_gregset_t * gregsetp, int regno) +{ + elf_greg_t *regp = (elf_greg_t *) gregsetp; + int i; + unsigned long psw, bbpsw, tmp; + + psw = *(regp + PSW_REGMAP); + bbpsw = *(regp + BBPSW_REGMAP); + + for (i = 0; i < M32R_LINUX_NUM_REGS; i++) + { + if (regno != -1 && regno != i) + continue; + + if (i == CBR_REGNUM || i == PSW_REGNUM) + continue; + + if (i == SPU_REGNUM || i == SPI_REGNUM) + continue; + + if (i != M32R_SP_REGNUM) + regcache_raw_collect (current_regcache, i, regp + regmap[i]); + else if (psw & 0x8000) + regcache_raw_collect (current_regcache, i, regp + SPU_REGMAP); + else + regcache_raw_collect (current_regcache, i, regp + SPI_REGMAP); + } +} + +/* Store all valid general-purpose registers in GDB's register array + into the process/thread specified by TID. */ + +static void +store_regs (int tid, int regno) +{ + elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0) + perror_with_name ("Couldn't get registers"); + + fill_gregset (®s, regno); + + if (ptrace (PTRACE_SETREGS, tid, 0, (int) ®s) < 0) + perror_with_name ("Couldn't write registers"); +} + + + +/* Transfering floating-point registers between GDB, inferiors and cores. + Since M32R has no floating-point registers, these functions do nothing. */ + +void +supply_fpregset (gdb_fpregset_t *fpregs) +{ +} + +void +fill_fpregset (gdb_fpregset_t *fpregs, int regno) +{ +} + + + +/* Transferring arbitrary registers between GDB and inferior. */ + +/* Fetch register REGNO from the child process. If REGNO is -1, do + this for all registers (including the floating point and SSE + registers). */ + +void +fetch_inferior_registers (int regno) +{ + int tid; + + /* GNU/Linux LWP ID's are process ID's. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + + /* Use the PTRACE_GETREGS request whenever possible, since it + transfers more registers in one system call, and we'll cache the + results. */ + if (regno == -1 || GETREGS_SUPPLIES (regno)) + { + fetch_regs (tid); + return; + } + + internal_error (__FILE__, __LINE__, + "Got request for bad register number %d.", regno); +} + +/* Store register REGNO back into the child process. If REGNO is -1, + do this for all registers (including the floating point and SSE + registers). */ +void +store_inferior_registers (int regno) +{ + int tid; + + /* GNU/Linux LWP ID's are process ID's. */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + + /* Use the PTRACE_SETREGS request whenever possible, since it + transfers more registers in one system call. */ + if (regno == -1 || GETREGS_SUPPLIES (regno)) + { + store_regs (tid, regno); + return; + } + + internal_error (__FILE__, __LINE__, + "Got request to store bad register number %d.", regno); +} diff --git a/gdb/m32r-linux-tdep.c b/gdb/m32r-linux-tdep.c new file mode 100644 index 00000000000..d2ca1a928f4 --- /dev/null +++ b/gdb/m32r-linux-tdep.c @@ -0,0 +1,336 @@ +/* Target-dependent code for GNU/Linux m32r. + + Copyright 2004 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 + (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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "frame.h" +#include "value.h" +#include "regcache.h" +#include "inferior.h" +#include "osabi.h" +#include "reggroups.h" + +#include "gdb_string.h" + +#include "glibc-tdep.h" +#include "solib-svr4.h" + +#include "trad-frame.h" +#include "frame-unwind.h" + +#include "m32r-tdep.h" + + +/* Recognizing signal handler frames. */ + +/* GNU/Linux has two flavors of signals. Normal signal handlers, and + "realtime" (RT) signals. The RT signals can provide additional + information to the signal handler if the SA_SIGINFO flag is set + when establishing a signal handler using `sigaction'. It is not + unlikely that future versions of GNU/Linux will support SA_SIGINFO + for normal signals too. */ + +/* When the m32r Linux kernel calls a signal handler and the + SA_RESTORER flag isn't set, the return address points to a bit of + code on the stack. This function returns whether the PC appears to + be within this bit of code. + + The instruction sequence for normal signals is + ldi r7, #__NR_sigreturn + trap #2 + or 0x67 0x77 0x10 0xf2. + + Checking for the code sequence should be somewhat reliable, because + the effect is to call the system call sigreturn. This is unlikely + to occur anywhere other than in a signal trampoline. + + It kind of sucks that we have to read memory from the process in + order to identify a signal trampoline, but there doesn't seem to be + any other way. Therefore we only do the memory reads if no + function name could be identified, which should be the case since + the code is on the stack. + + Detection of signal trampolines for handlers that set the + SA_RESTORER flag is in general not possible. Unfortunately this is + what the GNU C Library has been doing for quite some time now. + However, as of version 2.1.2, the GNU C Library uses signal + trampolines (named __restore and __restore_rt) that are identical + to the ones used by the kernel. Therefore, these trampolines are + supported too. */ + +static const unsigned char linux_sigtramp_code[] = { + 0x67, 0x77, 0x10, 0xf2, +}; + +/* If PC is in a sigtramp routine, return the address of the start of + the routine. Otherwise, return 0. */ + +static CORE_ADDR +m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) +{ + unsigned char 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 + start of the instruction sequence, as will be the case when the + trampoline is not the first frame on the stack. We assume that + in the case where the PC is not at the start of the instruction + sequence, there will be a few trailing readable bytes on the + stack. */ + + if (pc % 2 != 0) + { + if (!safe_frame_unwind_memory (next_frame, pc, buf, 2)) + return 0; + + if (memcmp (buf, linux_sigtramp_code, 2) == 0) + pc -= 2; + else + return 0; + } + + if (!safe_frame_unwind_memory (next_frame, pc, buf, 4)) + return 0; + + if (memcmp (buf, linux_sigtramp_code, 4) != 0) + return 0; + + return pc; +} + +/* This function does the same for RT signals. Here the instruction + sequence is + ldi r7, #__NR_rt_sigreturn + trap #2 + or 0x97 0xf0 0x00 0xad 0x10 0xf2 0xf0 0x00. + + The effect is to call the system call rt_sigreturn. */ + +static const unsigned char linux_rt_sigtramp_code[] = { + 0x97, 0xf0, 0x00, 0xad, 0x10, 0xf2, 0xf0, 0x00, +}; + +/* If PC is in a RT sigtramp routine, return the address of the start + of the routine. Otherwise, return 0. */ + +static CORE_ADDR +m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame) +{ + unsigned char 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 + start of the instruction sequence, as will be the case when the + trampoline is not the first frame on the stack. We assume that + in the case where the PC is not at the start of the instruction + sequence, there will be a few trailing readable bytes on the + stack. */ + + if (pc % 2 != 0) + return 0; + + if (!safe_frame_unwind_memory (next_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)) + return 0; + + if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0) + return pc; + } + else if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0) + { + if (!safe_frame_unwind_memory (next_frame, pc - 4, buf, 4)) + return 0; + + if (memcmp (buf, linux_rt_sigtramp_code, 4) == 0) + return pc - 4; + } + + return 0; +} + +static int +m32r_linux_pc_in_sigtramp (CORE_ADDR pc, char *name, + struct frame_info *next_frame) +{ + /* If we have NAME, we can optimize the search. The trampolines are + named __restore and __restore_rt. However, they aren't dynamically + exported from the shared C library, so the trampoline may appear to + 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 (strcmp ("__restore", name) == 0 + || strcmp ("__restore_rt", name) == 0); +} + +/* From . */ +static int m32r_linux_sc_reg_offset[] = { + 4 * 4, /* r0 */ + 5 * 4, /* r1 */ + 6 * 4, /* r2 */ + 7 * 4, /* r3 */ + 0 * 4, /* r4 */ + 1 * 4, /* r5 */ + 2 * 4, /* r6 */ + 8 * 4, /* r7 */ + 9 * 4, /* r8 */ + 10 * 4, /* r9 */ + 11 * 4, /* r10 */ + 12 * 4, /* r11 */ + 13 * 4, /* r12 */ + 21 * 4, /* fp */ + 22 * 4, /* lr */ + -1 * 4, /* sp */ + 16 * 4, /* psw */ + -1 * 4, /* cbr */ + 23 * 4, /* spi */ + 20 * 4, /* spu */ + 19 * 4, /* bpc */ + 17 * 4, /* pc */ + 15 * 4, /* accl */ + 14 * 4 /* acch */ +}; + +struct m32r_frame_cache +{ + CORE_ADDR base, pc; + struct trad_frame_saved_reg *saved_regs; +}; + +static struct m32r_frame_cache * +m32r_linux_sigtramp_frame_cache (struct frame_info *next_frame, + void **this_cache) +{ + struct m32r_frame_cache *cache; + CORE_ADDR sigcontext_addr, addr; + int regnum; + + if ((*this_cache) != NULL) + 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->base = frame_unwind_register_unsigned (next_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); + if (addr == 0) + { + /* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR + accordingly. */ + addr = m32r_linux_rt_sigtramp_start (cache->pc, next_frame); + if (addr) + sigcontext_addr += 128; + else + addr = frame_func_unwind (next_frame); + } + cache->pc = addr; + + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + for (regnum = 0; regnum < sizeof (m32r_linux_sc_reg_offset) / 4; regnum++) + { + if (m32r_linux_sc_reg_offset[regnum] >= 0) + cache->saved_regs[regnum].addr = + sigcontext_addr + m32r_linux_sc_reg_offset[regnum]; + } + + return cache; +} + +static void +m32r_linux_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct m32r_frame_cache *cache = + m32r_linux_sigtramp_frame_cache (next_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) +{ + struct m32r_frame_cache *cache = + m32r_linux_sigtramp_frame_cache (next_frame, this_cache); + + trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind m32r_linux_sigtramp_frame_unwind = { + SIGTRAMP_FRAME, + m32r_linux_sigtramp_frame_this_id, + m32r_linux_sigtramp_frame_prev_register +}; + +static const struct frame_unwind * +m32r_linux_sigtramp_frame_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (m32r_linux_pc_in_sigtramp (pc, name, next_frame)) + return &m32r_linux_sigtramp_frame_unwind; + + return NULL; +} + +static void +m32r_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (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); + + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern void _initialize_m32r_linux_tdep (void); + +void +_initialize_m32r_linux_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_m32r, 0, GDB_OSABI_LINUX, + m32r_linux_init_abi); +} diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c index fd5e9dc836a..73dce73b6c7 100644 --- a/gdb/m32r-tdep.c +++ b/gdb/m32r-tdep.c @@ -41,27 +41,7 @@ #include "gdb_assert.h" -struct gdbarch_tdep -{ - /* gdbarch target dependent data here. Currently unused for M32R. */ -}; - -/* m32r register names. */ - -enum -{ - R0_REGNUM = 0, - R3_REGNUM = 3, - M32R_FP_REGNUM = 13, - LR_REGNUM = 14, - M32R_SP_REGNUM = 15, - PSW_REGNUM = 16, - M32R_PC_REGNUM = 21, - /* m32r calling convention. */ - ARG1_REGNUM = R0_REGNUM, - ARGN_REGNUM = R3_REGNUM, - RET1_REGNUM = R0_REGNUM, -}; +#include "m32r-tdep.h" /* Local functions */ @@ -238,18 +218,12 @@ char *m32r_register_names[] = { "evb" }; -static int -m32r_num_regs (void) -{ - return (sizeof (m32r_register_names) / sizeof (m32r_register_names[0])); -} - static const char * m32r_register_name (int reg_nr) { if (reg_nr < 0) return NULL; - if (reg_nr >= m32r_num_regs ()) + if (reg_nr >= M32R_NUM_REGS) return NULL; return m32r_register_names[reg_nr]; } @@ -921,7 +895,7 @@ m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_write_pc (gdbarch, m32r_write_pc); set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp); - set_gdbarch_num_regs (gdbarch, m32r_num_regs ()); + set_gdbarch_num_regs (gdbarch, M32R_NUM_REGS); set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM); set_gdbarch_register_name (gdbarch, m32r_register_name); set_gdbarch_register_type (gdbarch, m32r_register_type); @@ -929,8 +903,10 @@ m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_extract_return_value (gdbarch, m32r_extract_return_value); set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call); set_gdbarch_store_return_value (gdbarch, m32r_store_return_value); - set_gdbarch_deprecated_extract_struct_value_address (gdbarch, m32r_extract_struct_value_address); - set_gdbarch_deprecated_use_struct_convention (gdbarch, m32r_use_struct_convention); + set_gdbarch_deprecated_extract_struct_value_address (gdbarch, + m32r_extract_struct_value_address); + set_gdbarch_deprecated_use_struct_convention (gdbarch, + m32r_use_struct_convention); set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue); set_gdbarch_inner_than (gdbarch, core_addr_lessthan); diff --git a/gdb/m32r-tdep.h b/gdb/m32r-tdep.h new file mode 100644 index 00000000000..60da0d61d5f --- /dev/null +++ b/gdb/m32r-tdep.h @@ -0,0 +1,52 @@ +/* Target-dependent code for Renesas M32R, for GDB. + + Copyright 2004 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 + (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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef M32R_TDEP_H +#define M32R_TDEP_H + +struct gdbarch_tdep +{ + /* gdbarch target dependent data here. Currently unused for M32R. */ +}; + +/* m32r register names. */ + +enum m32r_regnum +{ + R0_REGNUM = 0, + R3_REGNUM = 3, + M32R_FP_REGNUM = 13, + LR_REGNUM = 14, + M32R_SP_REGNUM = 15, + PSW_REGNUM = 16, + CBR_REGNUM = 17, + SPU_REGNUM = 18, + SPI_REGNUM = 19, + M32R_PC_REGNUM = 21, + /* m32r calling convention. */ + ARG1_REGNUM = R0_REGNUM, + ARGN_REGNUM = R3_REGNUM, + RET1_REGNUM = R0_REGNUM, +}; + +#define M32R_NUM_REGS 25 + +#endif /* m32r-tdep.h */ -- 2.30.2