diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-01-13 17:03:53 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-01-13 17:03:53 +0000 |
commit | 251dc056b0b8441208dc294de1d5d3537061b7e8 (patch) | |
tree | 2720bbe8c2043fa0e9f5f78413a8d97831c90329 | |
parent | 51362d059d4d2814bcf02ba08ab543da56467f7a (diff) | |
download | gdb-251dc056b0b8441208dc294de1d5d3537061b7e8.zip gdb-251dc056b0b8441208dc294de1d5d3537061b7e8.tar.gz gdb-251dc056b0b8441208dc294de1d5d3537061b7e8.tar.bz2 |
2003-01-13 Andrew Cagney <ac131313@redhat.com>
* d10v-tdep.c: Include "d10v-tdep.h". Update to use D10V_
prefixed enums.
(do_d10v_pop_frame): Delete. Use version in d10v-frame.c.
* frame.c (frame_read_unsigned_register): Do not use
get_next_frame.
(frame_read_signed_register): Do not use get_next_frame.
(get_frame_base): Use frame_id_unwind.
* d10v-tdep.h: New file.
* d10v-frame.h: New file.
* d10v-frame.c: New file.
* frame.c (frame_id_unwind): Update.
(create_sentinel_frame): Update.
(legacy_get_prev_frame): Use frame_unwind_find_by_pc.
(get_prev_frame): Ditto.
* frame.h (struct frame_info): Replace pc_unwind, id_unwind and
register_unwind with unwind structure.
* frame.c (set_unwind_by_pc): Delete function.
(create_new_frame): Use frame_unwind_find_by_pc;
* Makefile.in (frame_h): Add $(frame_unwind_h).
* frame.h: Include "frame-unwind.h".
(frame_register_unwind_ftype): Delete.
(frame_id_unwind_ftype): Delete.
(frame_pc_unwind_ftype): Delete.
* Makefile.in (dummy-frame.o): Update dependencies.
(legacy-frame.o): Update dependencies.
* dummy-frame.c: Include "frame-unwind.h".
(dummy_frame_unwind): New static variable.
(dummy_frame_p): New function.
* legacy-frame.c: Include "frame-unwind.h".
(legacy_frame_unwind): New static variable.
(legacy_frame_p): New function.
* legacy-frame.h (legacy_frame_p): Declare.
* dummy-frame.h (dummy_frame_p): Declare.
* Makefile.in (frame_unwind_h): Define.
* frame-unwind.h: New file.
* frame-unwind.c: New file.
-rw-r--r-- | gdb/ChangeLog | 48 | ||||
-rw-r--r-- | gdb/Makefile.in | 17 | ||||
-rw-r--r-- | gdb/d10v-frame.c | 392 | ||||
-rw-r--r-- | gdb/d10v-frame.h | 28 | ||||
-rw-r--r-- | gdb/d10v-tdep.c | 222 | ||||
-rw-r--r-- | gdb/d10v-tdep.h | 62 | ||||
-rw-r--r-- | gdb/dummy-frame.c | 19 | ||||
-rw-r--r-- | gdb/dummy-frame.h | 7 | ||||
-rw-r--r-- | gdb/frame-unwind.c | 102 | ||||
-rw-r--r-- | gdb/frame-unwind.h | 92 | ||||
-rw-r--r-- | gdb/frame.c | 66 | ||||
-rw-r--r-- | gdb/frame.h | 50 | ||||
-rw-r--r-- | gdb/legacy-frame.c | 16 | ||||
-rw-r--r-- | gdb/legacy-frame.h | 5 | ||||
-rw-r--r-- | gdb/sentinel-frame.c | 107 | ||||
-rw-r--r-- | gdb/sentinel-frame.h | 65 |
16 files changed, 1052 insertions, 246 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7e4be3e..1ab5710 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,51 @@ +2003-01-13 Andrew Cagney <ac131313@redhat.com> + + * d10v-tdep.c: Include "d10v-tdep.h". Update to use D10V_ + prefixed enums. + (do_d10v_pop_frame): Delete. Use version in d10v-frame.c. + + * frame.c (frame_read_unsigned_register): Do not use + get_next_frame. + (frame_read_signed_register): Do not use get_next_frame. + (get_frame_base): Use frame_id_unwind. + + * d10v-tdep.h: New file. + * d10v-frame.h: New file. + * d10v-frame.c: New file. + + * frame.c (frame_id_unwind): Update. + (create_sentinel_frame): Update. + (legacy_get_prev_frame): Use frame_unwind_find_by_pc. + (get_prev_frame): Ditto. + + * frame.h (struct frame_info): Replace pc_unwind, id_unwind and + register_unwind with unwind structure. + + * frame.c (set_unwind_by_pc): Delete function. + (create_new_frame): Use frame_unwind_find_by_pc; + + * Makefile.in (frame_h): Add $(frame_unwind_h). + * frame.h: Include "frame-unwind.h". + (frame_register_unwind_ftype): Delete. + (frame_id_unwind_ftype): Delete. + (frame_pc_unwind_ftype): Delete. + + * Makefile.in (dummy-frame.o): Update dependencies. + (legacy-frame.o): Update dependencies. + + * dummy-frame.c: Include "frame-unwind.h". + (dummy_frame_unwind): New static variable. + (dummy_frame_p): New function. + * legacy-frame.c: Include "frame-unwind.h". + (legacy_frame_unwind): New static variable. + (legacy_frame_p): New function. + * legacy-frame.h (legacy_frame_p): Declare. + * dummy-frame.h (dummy_frame_p): Declare. + + * Makefile.in (frame_unwind_h): Define. + * frame-unwind.h: New file. + * frame-unwind.c: New file. + 2003-01-12 Andrew Cagney <ac131313@redhat.com> * d10v-tdep.c (d10v_init_extra_frame_info): Remove checks for a diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7fb480f..4f13051 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -500,6 +500,7 @@ TARGET_FLAGS_TO_PASS = \ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ ax-general.c ax-gdb.c \ bcache.c blockframe.c breakpoint.c buildsym.c builtin-regs.c \ + d10v-frame.c \ c-exp.y c-lang.c c-typeprint.c c-valprint.c \ charset.c cli-out.c coffread.c complaints.c completer.c corefile.c \ cp-abi.c cp-support.c cp-valprint.c \ @@ -507,6 +508,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ dummy-frame.c dwarfread.c dwarf2read.c \ elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \ f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \ + frame-unwind.c \ gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \ hpacc-abi.c \ inf-loop.c infcmd.c inflow.c infrun.c \ @@ -619,7 +621,8 @@ event_loop_h = event-loop.h event_top_h = event-top.h expression_h = expression.h $(symtab_h) $(doublest_h) f_lang_h = f-lang.h -frame_h = frame.h +frame_h = frame.h $(frame_unwind_h) +frame_unwind_h = frame-unwind.h gdb_events_h = gdb-events.h gdb_stabs_h = gdb-stabs.h gdb_h = gdb.h @@ -807,7 +810,7 @@ TAGFILES_NO_SRCDIR = $(SFILES) $(HFILES_NO_SRCDIR) $(ALLDEPFILES) \ TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR) COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ - charset.o disasm.o dummy-frame.o \ + charset.o disasm.o dummy-frame.o d10v-frame.o \ source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \ symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \ expprint.o environ.o stack.o thread.o \ @@ -832,7 +835,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o \ nlmread.o serial.o mdebugread.o top.o utils.o \ ui-file.o \ - frame.o doublest.o \ + frame.o doublest.o frame-unwind.o \ gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \ sentinel-frame.o \ reggroups.o legacy-frame.o @@ -1605,6 +1608,7 @@ cris-tdep.o: cris-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(inferior_h) \ $(gdbtypes_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(value_h) \ $(opcode_cris_h) $(arch_utils_h) $(regcache_h) $(symfile_h) \ $(solib_h) $(solib_svr4_h) $(gdb_string_h) +d10v-frame.o: d10v-frame.c $(defs_h) $(frame_unwind_h) d10v-tdep.o: d10v-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(gdbtypes_h) \ $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) $(value_h) $(inferior_h) \ $(dis_asm_h) $(symfile_h) $(objfiles_h) $(language_h) \ @@ -1631,7 +1635,7 @@ doublest.o: doublest.c $(defs_h) $(doublest_h) $(floatformat_h) \ dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h) dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h) dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ - $(frame_h) $(inferior_h) $(gdb_assert_h) + $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ $(serial_h) $(inferior_h) $(command_h) $(gdb_string_h) $(regcache_h) dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \ @@ -1685,6 +1689,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \ $(gdb_obstack_h) $(dummy_frame_h) $(sentinel_frame_h) \ $(legacy_frame_h) $(gdbcore_h) $(annotate_h) $(language_h) \ $(ui_out_h) +frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \ + $(gdb_assert_h) $(dummy_frame_h) $(legacy_frame_h) frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \ $(arch_utils_h) $(regcache_h) gcore.o: gcore.c $(defs_h) $(cli_decode_h) $(inferior_h) $(gdbcore_h) \ @@ -1835,7 +1841,8 @@ language.o: language.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ lin-lwp.o: lin-lwp.c $(defs_h) $(gdb_assert_h) $(gdb_string_h) $(gdb_wait_h) \ $(gdbthread_h) $(inferior_h) $(target_h) $(regcache_h) $(gdbcmd_h) legacy-frame.o: legacy-frame.c $(defs_h) $(legacy_frame_h) $(gdb_assert_h) \ - $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h) + $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h) \ + $(frame_unwind_h) linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \ $(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(completer_h) \ $(cp_abi_h) $(source_h) $(parser_defs_h) diff --git a/gdb/d10v-frame.c b/gdb/d10v-frame.c new file mode 100644 index 0000000..5b29545 --- /dev/null +++ b/gdb/d10v-frame.c @@ -0,0 +1,392 @@ +/* Frame unwinder for Mitsubishi D10V, for GDB, the GNU Debugger. + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 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 "frame.h" +#include "frame-unwind.h" +#include "d10v-tdep.h" +#include "gdbcore.h" +#include "regcache.h" +#include "target.h" +#include "gdb_assert.h" + +struct frame_unwind_cache +{ + CORE_ADDR return_pc; + int frameless; + int size; + CORE_ADDR *saved_regs; + CORE_ADDR next_addr; + int uses_frame; + void **regs; +}; + + +static int +prologue_find_regs (unsigned short op, struct frame_unwind_cache *info, + CORE_ADDR addr) +{ + int n; + + /* st rn, @-sp */ + if ((op & 0x7E1F) == 0x6C1F) + { + n = (op & 0x1E0) >> 5; + info->next_addr -= 2; + info->saved_regs[n] = info->next_addr; + return 1; + } + + /* st2w rn, @-sp */ + else if ((op & 0x7E3F) == 0x6E1F) + { + n = (op & 0x1E0) >> 5; + info->next_addr -= 4; + info->saved_regs[n] = info->next_addr; + info->saved_regs[n + 1] = info->next_addr + 2; + return 1; + } + + /* subi sp, n */ + if ((op & 0x7FE1) == 0x01E1) + { + n = (op & 0x1E) >> 1; + if (n == 0) + n = 16; + info->next_addr -= n; + return 1; + } + + /* mv r11, sp */ + if (op == 0x417E) + { + info->uses_frame = 1; + return 1; + } + + /* nop */ + if (op == 0x5E00) + return 1; + + /* st rn, @sp */ + if ((op & 0x7E1F) == 0x681E) + { + n = (op & 0x1E0) >> 5; + info->saved_regs[n] = info->next_addr; + return 1; + } + + /* st2w rn, @sp */ + if ((op & 0x7E3F) == 0x3A1E) + { + n = (op & 0x1E0) >> 5; + info->saved_regs[n] = info->next_addr; + info->saved_regs[n + 1] = info->next_addr + 2; + return 1; + } + + return 0; +} + +struct frame_unwind_cache * +d10v_frame_unwind_cache (struct frame_info *fi, + struct frame_unwind_cache **cache) +{ + CORE_ADDR fp, pc; + unsigned long op; + unsigned short op1, op2; + int i; + struct frame_unwind_cache *info; + + if ((*cache)) + return (*cache); + + info = FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache); + (*cache) = info; + info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); + + info->frameless = 0; + info->size = 0; + info->return_pc = 0; + + fp = get_frame_base (fi); + info->next_addr = 0; + + pc = get_pc_function_start (get_frame_pc (fi)); + + info->uses_frame = 0; + while (1) + { + op = (unsigned long) read_memory_integer (pc, 4); + if ((op & 0xC0000000) == 0xC0000000) + { + /* long instruction */ + if ((op & 0x3FFF0000) == 0x01FF0000) + { + /* add3 sp,sp,n */ + short n = op & 0xFFFF; + info->next_addr += n; + } + else if ((op & 0x3F0F0000) == 0x340F0000) + { + /* st rn, @(offset,sp) */ + short offset = op & 0xFFFF; + short n = (op >> 20) & 0xF; + info->saved_regs[n] = info->next_addr + offset; + } + else if ((op & 0x3F1F0000) == 0x350F0000) + { + /* st2w rn, @(offset,sp) */ + short offset = op & 0xFFFF; + short n = (op >> 20) & 0xF; + info->saved_regs[n] = info->next_addr + offset; + info->saved_regs[n + 1] = info->next_addr + offset + 2; + } + else + break; + } + else + { + /* short instructions */ + if ((op & 0xC0000000) == 0x80000000) + { + op2 = (op & 0x3FFF8000) >> 15; + op1 = op & 0x7FFF; + } + else + { + op1 = (op & 0x3FFF8000) >> 15; + op2 = op & 0x7FFF; + } + if (!prologue_find_regs (op1, (*cache), pc) + || !prologue_find_regs (op2, (*cache), pc)) + break; + } + pc += 4; + } + + info->size = -info->next_addr; + + if (!(fp & 0xffff)) + fp = d10v_read_sp (); + + for (i = 0; i < NUM_REGS - 1; i++) + if (info->saved_regs[i]) + { + info->saved_regs[i] = fp - (info->next_addr - info->saved_regs[i]); + } + + if (info->saved_regs[D10V_LR_REGNUM]) + { + CORE_ADDR return_pc + = read_memory_unsigned_integer (info->saved_regs[D10V_LR_REGNUM], + REGISTER_RAW_SIZE (D10V_LR_REGNUM)); + info->return_pc = d10v_make_iaddr (return_pc); + } + else + { + ULONGEST return_pc; + frame_read_unsigned_register (fi, D10V_LR_REGNUM, &return_pc); + info->return_pc = d10v_make_iaddr (return_pc); + } + + /* The SP is not normally (ever?) saved, but check anyway */ + if (!info->saved_regs[D10V_SP_REGNUM]) + { + /* if the FP was saved, that means the current FP is valid, */ + /* otherwise, it isn't being used, so we use the SP instead */ + if (info->uses_frame) + info->saved_regs[D10V_SP_REGNUM] + = d10v_read_fp () + info->size; + else + { + info->saved_regs[SP_REGNUM] = fp + info->size; + info->frameless = 1; + info->saved_regs[FP_REGNUM] = 0; + } + } + + return info; +} + +static CORE_ADDR +d10v_frame_pc_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache) +{ + struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache); + return info->return_pc; +} + +static void +d10v_frame_id_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache, + struct frame_id *id) +{ + struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache); + CORE_ADDR addr; + + /* Start with a NULL frame ID. */ + (*id) = null_frame_id; + + if (info->return_pc == D10V_IMEM_START + || inside_entry_file (info->return_pc)) + { + /* This is meant to halt the backtrace at "_start". + Make sure we don't halt it at a generic dummy frame. */ + return; + } + + if (!info->saved_regs[FP_REGNUM]) + { + if (!info->saved_regs[SP_REGNUM] + || info->saved_regs[SP_REGNUM] == D10V_STACK_START) + return; + + id->base = info->saved_regs[SP_REGNUM]; + id->pc = info->return_pc; + } + + addr = read_memory_unsigned_integer (info->saved_regs[FP_REGNUM], + REGISTER_RAW_SIZE (FP_REGNUM)); + if (addr == 0) + return; + + id->base = d10v_make_daddr (addr); + id->pc = info->return_pc; +} + +static void +saved_regs_unwinder (struct frame_info *frame, + CORE_ADDR *saved_regs, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + /* If we're using generic dummy frames, we'd better not be in a call + dummy. (generic_call_dummy_register_unwind ought to have been called + instead.) */ + gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES + && (get_frame_type (frame) == DUMMY_FRAME))); + + if (saved_regs[regnum] != 0) + { + if (regnum == SP_REGNUM) + { + /* SP register treated specially. */ + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_address (bufferp, REGISTER_RAW_SIZE (regnum), + saved_regs[regnum]); + } + else + { + /* Any other register is saved in memory, fetch it but cache + a local copy of its value. */ + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = saved_regs[regnum]; + *realnump = -1; + if (bufferp != NULL) + { + /* Read the value in from memory. */ + read_memory (get_frame_saved_regs (frame)[regnum], bufferp, + REGISTER_RAW_SIZE (regnum)); + } + } + return; + } + + /* No luck, assume this and the next frame have the same register + value. If a value is needed, pass the request on down the chain; + otherwise just return an indication that the value is in the same + register as the next frame. */ + frame_register (frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); +} + + +static void +d10v_frame_register_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache); + saved_regs_unwinder (frame, info->saved_regs, regnum, optimizedp, + lvalp, addrp, realnump, bufferp); +} + + +void +do_d10v_pop_frame (struct frame_info *fi) +{ + struct frame_unwind_cache *info = + d10v_frame_unwind_cache (fi, &fi->unwind_cache); + CORE_ADDR fp; + int regnum; + char raw_buffer[8]; + + fp = get_frame_base (fi); + + /* now update the current registers with the old values */ + for (regnum = d10v_a0_regnum (current_gdbarch); regnum < d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS; regnum++) + { + if (info->saved_regs[regnum]) + { + read_memory (info->saved_regs[regnum], raw_buffer, REGISTER_RAW_SIZE (regnum)); + deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, + REGISTER_RAW_SIZE (regnum)); + } + } + for (regnum = 0; regnum < D10V_SP_REGNUM; regnum++) + { + if (info->saved_regs[regnum]) + { + write_register (regnum, read_memory_unsigned_integer (info->saved_regs[regnum], REGISTER_RAW_SIZE (regnum))); + } + } + if (info->saved_regs[D10V_PSW_REGNUM]) + { + write_register (D10V_PSW_REGNUM, read_memory_unsigned_integer (info->saved_regs[D10V_PSW_REGNUM], REGISTER_RAW_SIZE (D10V_PSW_REGNUM))); + } + + write_register (D10V_PC_REGNUM, read_register (D10V_LR_REGNUM)); + write_register (D10V_SP_REGNUM, fp + info->size); + target_store_registers (-1); + flush_cached_frames (); +} + +static struct frame_unwind d10v_frame_unwind = { + d10v_frame_pc_unwind, + d10v_frame_id_unwind, + d10v_frame_register_unwind +}; + +const struct frame_unwind * +d10v_frame_p (CORE_ADDR pc) +{ + return &d10v_frame_unwind; +} diff --git a/gdb/d10v-frame.h b/gdb/d10v-frame.h new file mode 100644 index 0000000..c05c4fb --- /dev/null +++ b/gdb/d10v-frame.h @@ -0,0 +1,28 @@ +/* Definitions for a d10v frame unwinder, for GDB, the GNU debugger. + + Copyright 2003 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. */ + +#if !defined (D10V_FRAME_H) +#define D10V_UNWIND_H 1 + +struct frame_unwind; +extern const struct frame_unwind *d10v_frame_p (CORE_ADDR pc); + +#endif diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c index 63efe4c..e6152e4 100644 --- a/gdb/d10v-tdep.c +++ b/gdb/d10v-tdep.c @@ -38,10 +38,14 @@ #include "arch-utils.h" #include "regcache.h" +#include "d10v-tdep.h" #include "floatformat.h" #include "gdb/sim-d10v.h" #include "sim-regno.h" +#include "frame-unwind.h" +#include "d10v-frame.h" + #include "gdb_assert.h" struct frame_extra_info @@ -59,47 +63,18 @@ struct gdbarch_tdep unsigned long (*imap_register) (int nr); }; -/* These are the addresses the D10V-EVA board maps data and - instruction memory to. */ - -enum memspace { - DMEM_START = 0x2000000, - IMEM_START = 0x1000000, - STACK_START = 0x200bffe -}; - -/* d10v register names. */ - -enum - { - R0_REGNUM = 0, - R3_REGNUM = 3, - _FP_REGNUM = 11, - LR_REGNUM = 13, - _SP_REGNUM = 15, - PSW_REGNUM = 16, - _PC_REGNUM = 18, - NR_IMAP_REGS = 2, - NR_A_REGS = 2, - TS2_NUM_REGS = 37, - TS3_NUM_REGS = 42, - /* d10v calling convention. */ - ARG1_REGNUM = R0_REGNUM, - ARGN_REGNUM = R3_REGNUM, - RET1_REGNUM = R0_REGNUM, - }; - #define NR_DMAP_REGS (gdbarch_tdep (current_gdbarch)->nr_dmap_regs) -#define A0_REGNUM (gdbarch_tdep (current_gdbarch)->a0_regnum) + +int +d10v_a0_regnum (struct gdbarch *gdbarch) +{ + return (gdbarch_tdep (current_gdbarch)->a0_regnum); +} /* Local functions */ extern void _initialize_d10v_tdep (void); -static CORE_ADDR d10v_read_sp (void); - -static CORE_ADDR d10v_read_fp (void); - static void d10v_eva_prepare_to_trace (void); static void d10v_eva_get_trace_data (void); @@ -109,12 +84,12 @@ static int prologue_find_regs (unsigned short op, struct frame_info *fi, static void d10v_frame_init_saved_regs (struct frame_info *); -static void do_d10v_pop_frame (struct frame_info *fi); +void do_d10v_pop_frame (struct frame_info *fi); static int d10v_frame_chain_valid (CORE_ADDR chain, struct frame_info *frame) { - return (get_frame_pc (frame) > IMEM_START); + return (get_frame_pc (frame) > D10V_IMEM_START); } static CORE_ADDR @@ -298,12 +273,12 @@ d10v_ts2_register_sim_regno (int nr) if (legacy_register_sim_regno (nr) < 0) return legacy_register_sim_regno (nr); if (nr >= TS2_IMAP0_REGNUM - && nr < TS2_IMAP0_REGNUM + NR_IMAP_REGS) + && nr < TS2_IMAP0_REGNUM + D10V_NR_IMAP_REGS) return nr - TS2_IMAP0_REGNUM + SIM_D10V_IMAP0_REGNUM; if (nr == TS2_DMAP_REGNUM) return nr - TS2_DMAP_REGNUM + SIM_D10V_TS2_DMAP_REGNUM; if (nr >= TS2_A0_REGNUM - && nr < TS2_A0_REGNUM + NR_A_REGS) + && nr < TS2_A0_REGNUM + D10V_NR_A_REGS) return nr - TS2_A0_REGNUM + SIM_D10V_A0_REGNUM; return nr; } @@ -314,13 +289,13 @@ d10v_ts3_register_sim_regno (int nr) if (legacy_register_sim_regno (nr) < 0) return legacy_register_sim_regno (nr); if (nr >= TS3_IMAP0_REGNUM - && nr < TS3_IMAP0_REGNUM + NR_IMAP_REGS) + && nr < TS3_IMAP0_REGNUM + D10V_NR_IMAP_REGS) return nr - TS3_IMAP0_REGNUM + SIM_D10V_IMAP0_REGNUM; if (nr >= TS3_DMAP0_REGNUM && nr < TS3_DMAP0_REGNUM + TS3_NR_DMAP_REGS) return nr - TS3_DMAP0_REGNUM + SIM_D10V_DMAP0_REGNUM; if (nr >= TS3_A0_REGNUM - && nr < TS3_A0_REGNUM + NR_A_REGS) + && nr < TS3_A0_REGNUM + D10V_NR_A_REGS) return nr - TS3_A0_REGNUM + SIM_D10V_A0_REGNUM; return nr; } @@ -331,15 +306,15 @@ d10v_ts3_register_sim_regno (int nr) static int d10v_register_byte (int reg_nr) { - if (reg_nr < A0_REGNUM) + if (reg_nr < d10v_a0_regnum (current_gdbarch)) return (reg_nr * 2); - else if (reg_nr < (A0_REGNUM + NR_A_REGS)) - return (A0_REGNUM * 2 - + (reg_nr - A0_REGNUM) * 8); + else if (reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS)) + return (d10v_a0_regnum (current_gdbarch) * 2 + + (reg_nr - d10v_a0_regnum (current_gdbarch)) * 8); else - return (A0_REGNUM * 2 - + NR_A_REGS * 8 - + (reg_nr - A0_REGNUM - NR_A_REGS) * 2); + return (d10v_a0_regnum (current_gdbarch) * 2 + + D10V_NR_A_REGS * 8 + + (reg_nr - d10v_a0_regnum (current_gdbarch) - D10V_NR_A_REGS) * 2); } /* Number of bytes of storage in the actual machine representation for @@ -348,9 +323,9 @@ d10v_register_byte (int reg_nr) static int d10v_register_raw_size (int reg_nr) { - if (reg_nr < A0_REGNUM) + if (reg_nr < d10v_a0_regnum (current_gdbarch)) return 2; - else if (reg_nr < (A0_REGNUM + NR_A_REGS)) + else if (reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS)) return 8; else return 2; @@ -362,12 +337,12 @@ d10v_register_raw_size (int reg_nr) static struct type * d10v_register_virtual_type (int reg_nr) { - if (reg_nr == PC_REGNUM) + if (reg_nr == D10V_PC_REGNUM) return builtin_type_void_func_ptr; - if (reg_nr == _SP_REGNUM || reg_nr == _FP_REGNUM) + if (reg_nr == D10V_SP_REGNUM || reg_nr == D10V_FP_REGNUM) return builtin_type_void_data_ptr; - else if (reg_nr >= A0_REGNUM - && reg_nr < (A0_REGNUM + NR_A_REGS)) + else if (reg_nr >= d10v_a0_regnum (current_gdbarch) + && reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS)) return builtin_type_int64; else return builtin_type_int16; @@ -376,28 +351,28 @@ d10v_register_virtual_type (int reg_nr) static int d10v_daddr_p (CORE_ADDR x) { - return (((x) & 0x3000000) == DMEM_START); + return (((x) & 0x3000000) == D10V_DMEM_START); } static int d10v_iaddr_p (CORE_ADDR x) { - return (((x) & 0x3000000) == IMEM_START); + return (((x) & 0x3000000) == D10V_IMEM_START); } -static CORE_ADDR +CORE_ADDR d10v_make_daddr (CORE_ADDR x) { - return ((x) | DMEM_START); + return ((x) | D10V_DMEM_START); } -static CORE_ADDR +CORE_ADDR d10v_make_iaddr (CORE_ADDR x) { if (d10v_iaddr_p (x)) return x; /* Idempotency -- x is already in the IMEM space. */ else - return (((x) << 2) | IMEM_START); + return (((x) << 2) | D10V_IMEM_START); } static CORE_ADDR @@ -465,7 +440,7 @@ d10v_integer_to_address (struct type *type, void *buf) static void d10v_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) { - write_register (ARG1_REGNUM, (addr)); + write_register (D10V_ARG1_REGNUM, (addr)); } /* Write into appropriate registers a function return value @@ -531,8 +506,8 @@ d10v_frame_saved_pc (struct frame_info *frame) static CORE_ADDR d10v_saved_pc_after_call (struct frame_info *frame) { - return ((read_register (LR_REGNUM) << 2) - | IMEM_START); + return ((read_register (D10V_LR_REGNUM) << 2) + | D10V_IMEM_START); } /* Discard from the stack the innermost frame, restoring all saved @@ -544,46 +519,6 @@ d10v_pop_frame (void) generic_pop_current_frame (do_d10v_pop_frame); } -static void -do_d10v_pop_frame (struct frame_info *fi) -{ - CORE_ADDR fp; - int regnum; - char raw_buffer[8]; - - fp = get_frame_base (fi); - /* fill out fsr with the address of where each */ - /* register was stored in the frame */ - d10v_frame_init_saved_regs (fi); - - /* now update the current registers with the old values */ - for (regnum = A0_REGNUM; regnum < A0_REGNUM + NR_A_REGS; regnum++) - { - if (get_frame_saved_regs (fi)[regnum]) - { - read_memory (get_frame_saved_regs (fi)[regnum], raw_buffer, REGISTER_RAW_SIZE (regnum)); - deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, - REGISTER_RAW_SIZE (regnum)); - } - } - for (regnum = 0; regnum < SP_REGNUM; regnum++) - { - if (get_frame_saved_regs (fi)[regnum]) - { - write_register (regnum, read_memory_unsigned_integer (get_frame_saved_regs (fi)[regnum], REGISTER_RAW_SIZE (regnum))); - } - } - if (get_frame_saved_regs (fi)[PSW_REGNUM]) - { - write_register (PSW_REGNUM, read_memory_unsigned_integer (get_frame_saved_regs (fi)[PSW_REGNUM], REGISTER_RAW_SIZE (PSW_REGNUM))); - } - - write_register (PC_REGNUM, read_register (LR_REGNUM)); - write_register (SP_REGNUM, fp + get_frame_extra_info (fi)->size); - target_store_registers (-1); - flush_cached_frames (); -} - static int check_prologue (unsigned short op) { @@ -695,7 +630,7 @@ d10v_frame_chain (struct frame_info *fi) d10v_frame_init_saved_regs (fi); - if (get_frame_extra_info (fi)->return_pc == IMEM_START + if (get_frame_extra_info (fi)->return_pc == D10V_IMEM_START || inside_entry_file (get_frame_extra_info (fi)->return_pc)) { /* This is meant to halt the backtrace at "_start". @@ -703,17 +638,17 @@ d10v_frame_chain (struct frame_info *fi) return (CORE_ADDR) 0; } - if (!get_frame_saved_regs (fi)[FP_REGNUM]) + if (!get_frame_saved_regs (fi)[D10V_FP_REGNUM]) { - if (!get_frame_saved_regs (fi)[SP_REGNUM] - || get_frame_saved_regs (fi)[SP_REGNUM] == STACK_START) + if (!get_frame_saved_regs (fi)[D10V_SP_REGNUM] + || get_frame_saved_regs (fi)[D10V_SP_REGNUM] == D10V_STACK_START) return (CORE_ADDR) 0; - return get_frame_saved_regs (fi)[SP_REGNUM]; + return get_frame_saved_regs (fi)[D10V_SP_REGNUM]; } - addr = read_memory_unsigned_integer (get_frame_saved_regs (fi)[FP_REGNUM], - REGISTER_RAW_SIZE (FP_REGNUM)); + addr = read_memory_unsigned_integer (get_frame_saved_regs (fi)[D10V_FP_REGNUM], + REGISTER_RAW_SIZE (D10V_FP_REGNUM)); if (addr == 0) return (CORE_ADDR) 0; @@ -869,31 +804,31 @@ d10v_frame_init_saved_regs (struct frame_info *fi) get_frame_saved_regs (fi)[i] = fp - (next_addr - get_frame_saved_regs (fi)[i]); } - if (get_frame_saved_regs (fi)[LR_REGNUM]) + if (get_frame_saved_regs (fi)[D10V_LR_REGNUM]) { CORE_ADDR return_pc - = read_memory_unsigned_integer (get_frame_saved_regs (fi)[LR_REGNUM], - REGISTER_RAW_SIZE (LR_REGNUM)); + = read_memory_unsigned_integer (get_frame_saved_regs (fi)[D10V_LR_REGNUM], + REGISTER_RAW_SIZE (D10V_LR_REGNUM)); get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (return_pc); } else { - get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (read_register (LR_REGNUM)); + get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (read_register (D10V_LR_REGNUM)); } /* The SP is not normally (ever?) saved, but check anyway */ - if (!get_frame_saved_regs (fi)[SP_REGNUM]) + if (!get_frame_saved_regs (fi)[D10V_SP_REGNUM]) { /* if the FP was saved, that means the current FP is valid, */ /* otherwise, it isn't being used, so we use the SP instead */ if (uses_frame) - get_frame_saved_regs (fi)[SP_REGNUM] + get_frame_saved_regs (fi)[D10V_SP_REGNUM] = d10v_read_fp () + get_frame_extra_info (fi)->size; else { - get_frame_saved_regs (fi)[SP_REGNUM] = fp + get_frame_extra_info (fi)->size; + get_frame_saved_regs (fi)[D10V_SP_REGNUM] = fp + get_frame_extra_info (fi)->size; get_frame_extra_info (fi)->frameless = 1; - get_frame_saved_regs (fi)[FP_REGNUM] = 0; + get_frame_saved_regs (fi)[D10V_FP_REGNUM] = 0; } } } @@ -925,9 +860,9 @@ show_regs (char *args, int from_tty) { int a; printf_filtered ("PC=%04lx (0x%lx) PSW=%04lx RPT_S=%04lx RPT_E=%04lx RPT_C=%04lx\n", - (long) read_register (PC_REGNUM), - (long) d10v_make_iaddr (read_register (PC_REGNUM)), - (long) read_register (PSW_REGNUM), + (long) read_register (D10V_PC_REGNUM), + (long) d10v_make_iaddr (read_register (D10V_PC_REGNUM)), + (long) read_register (D10V_PSW_REGNUM), (long) read_register (24), (long) read_register (25), (long) read_register (23)); @@ -949,7 +884,7 @@ show_regs (char *args, int from_tty) (long) read_register (13), (long) read_register (14), (long) read_register (15)); - for (a = 0; a < NR_IMAP_REGS; a++) + for (a = 0; a < D10V_NR_IMAP_REGS; a++) { if (a > 0) printf_filtered (" "); @@ -965,8 +900,8 @@ show_regs (char *args, int from_tty) } printf_filtered ("\n"); } - printf_filtered ("A0-A%d", NR_A_REGS - 1); - for (a = A0_REGNUM; a < A0_REGNUM + NR_A_REGS; a++) + printf_filtered ("A0-A%d", D10V_NR_A_REGS - 1); + for (a = d10v_a0_regnum (current_gdbarch); a < d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS; a++) { char num[MAX_REGISTER_RAW_SIZE]; int i; @@ -989,7 +924,7 @@ d10v_read_pc (ptid_t ptid) save_ptid = inferior_ptid; inferior_ptid = ptid; - pc = (int) read_register (PC_REGNUM); + pc = (int) read_register (D10V_PC_REGNUM); inferior_ptid = save_ptid; retval = d10v_make_iaddr (pc); return retval; @@ -1002,26 +937,26 @@ d10v_write_pc (CORE_ADDR val, ptid_t ptid) save_ptid = inferior_ptid; inferior_ptid = ptid; - write_register (PC_REGNUM, d10v_convert_iaddr_to_raw (val)); + write_register (D10V_PC_REGNUM, d10v_convert_iaddr_to_raw (val)); inferior_ptid = save_ptid; } -static CORE_ADDR +CORE_ADDR d10v_read_sp (void) { - return (d10v_make_daddr (read_register (SP_REGNUM))); + return (d10v_make_daddr (read_register (D10V_SP_REGNUM))); } static void d10v_write_sp (CORE_ADDR val) { - write_register (SP_REGNUM, d10v_convert_daddr_to_raw (val)); + write_register (D10V_SP_REGNUM, d10v_convert_daddr_to_raw (val)); } -static CORE_ADDR +CORE_ADDR d10v_read_fp (void) { - return (d10v_make_daddr (read_register (FP_REGNUM))); + return (d10v_make_daddr (read_register (D10V_FP_REGNUM))); } /* Function: push_return_address (pc) @@ -1031,7 +966,7 @@ d10v_read_fp (void) static CORE_ADDR d10v_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { - write_register (LR_REGNUM, d10v_convert_iaddr_to_raw (CALL_DUMMY_ADDRESS ())); + write_register (D10V_LR_REGNUM, d10v_convert_iaddr_to_raw (CALL_DUMMY_ADDRESS ())); return sp; } @@ -1077,7 +1012,7 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { int i; - int regnum = ARG1_REGNUM; + int regnum = D10V_ARG1_REGNUM; struct stack_item *si = NULL; long val; @@ -1099,13 +1034,13 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp, int aligned_regnum = (regnum + 1) & ~1; /* printf ("push: type=%d len=%d\n", TYPE_CODE (type), len); */ - if (len <= 2 && regnum <= ARGN_REGNUM) + if (len <= 2 && regnum <= D10V_ARGN_REGNUM) /* fits in a single register, do not align */ { val = extract_unsigned_integer (contents, len); write_register (regnum++, val); } - else if (len <= (ARGN_REGNUM - aligned_regnum + 1) * 2) + else if (len <= (D10V_ARGN_REGNUM - aligned_regnum + 1) * 2) /* value fits in remaining registers, store keeping left aligned */ { @@ -1125,7 +1060,7 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp, else { /* arg will go onto stack */ - regnum = ARGN_REGNUM + 1; + regnum = D10V_ARGN_REGNUM + 1; si = push_stack_item (si, contents, len); } } @@ -1151,9 +1086,9 @@ d10v_extract_return_value (struct type *type, struct regcache *regcache, int len; #if 0 printf("RET: TYPE=%d len=%d r%d=0x%x\n", TYPE_CODE (type), - TYPE_LENGTH (type), RET1_REGNUM - R0_REGNUM, - (int) extract_unsigned_integer (regbuf + REGISTER_BYTE(RET1_REGNUM), - REGISTER_RAW_SIZE (RET1_REGNUM))); + TYPE_LENGTH (type), D10V_RET1_REGNUM - R0_REGNUM, + (int) extract_unsigned_integer (regbuf + REGISTER_BYTE(D10V_RET1_REGNUM), + REGISTER_RAW_SIZE (D10V_RET1_REGNUM))); #endif if (TYPE_LENGTH (type) == 1) { @@ -1338,7 +1273,7 @@ d10v_eva_prepare_to_trace (void) if (!tracing) return; - last_pc = read_register (PC_REGNUM); + last_pc = read_register (D10V_PC_REGNUM); } /* Collect trace data from the target board and format it into a form @@ -1520,10 +1455,6 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep = XMALLOC (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); - /* NOTE: cagney/2002-12-06: This can be deleted when this arch is - ready to unwind the PC first (see frame.c:get_prev_frame()). */ - set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default); - switch (info.bfd_arch_info->mach) { case bfd_mach_d10v_ts2: @@ -1620,7 +1551,6 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_use_struct_convention (gdbarch, d10v_use_struct_convention); set_gdbarch_frame_init_saved_regs (gdbarch, d10v_frame_init_saved_regs); - set_gdbarch_init_extra_frame_info (gdbarch, d10v_init_extra_frame_info); set_gdbarch_pop_frame (gdbarch, d10v_pop_frame); @@ -1645,6 +1575,8 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_register_sim_regno (gdbarch, d10v_register_sim_regno); set_gdbarch_extra_stack_alignment_needed (gdbarch, 0); + frame_unwind_append_predicate (gdbarch, d10v_frame_p); + return gdbarch; } diff --git a/gdb/d10v-tdep.h b/gdb/d10v-tdep.h new file mode 100644 index 0000000..4535c2a --- /dev/null +++ b/gdb/d10v-tdep.h @@ -0,0 +1,62 @@ +/* Target-dependent code for Mitsubishi D10V, for GDB. + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 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 D10V_TDEP_H +#define D10V_TDEP_H + +/* d10v register names. */ + +enum +{ + D10V_R0_REGNUM = 0, + D10V_R3_REGNUM = 3, + D10V_FP_REGNUM = 11, + D10V_LR_REGNUM = 13, + D10V_SP_REGNUM = 15, + D10V_PSW_REGNUM = 16, + D10V_PC_REGNUM = 18, + D10V_NR_IMAP_REGS = 2, + D10V_NR_A_REGS = 2, + D10V_TS2_NUM_REGS = 37, + D10V_TS3_NUM_REGS = 42, + /* d10v calling convention. */ + D10V_ARG1_REGNUM = D10V_R0_REGNUM, + D10V_ARGN_REGNUM = D10V_R3_REGNUM, + D10V_RET1_REGNUM = D10V_R0_REGNUM, +}; + +/* These are the addresses the D10V-EVA board maps data and + instruction memory to. */ + +enum memspace { + D10V_DMEM_START = 0x2000000, + D10V_IMEM_START = 0x1000000, + D10V_STACK_START = 0x200bffe +}; + +extern CORE_ADDR d10v_make_iaddr (CORE_ADDR x); +extern CORE_ADDR d10v_make_daddr (CORE_ADDR x); +extern CORE_ADDR d10v_read_sp (void); +extern CORE_ADDR d10v_read_fp (void); +extern int d10v_a0_regnum (struct gdbarch *gdbarch); + +#endif diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index a1abc29..8374812 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -24,6 +24,7 @@ #include "defs.h" #include "dummy-frame.h" +#include "frame-unwind.h" #include "regcache.h" #include "frame.h" #include "inferior.h" @@ -362,3 +363,21 @@ dummy_frame_id_unwind (struct frame_info *frame, *id = dummy->id; } +static struct frame_unwind dummy_frame_unwind = +{ + dummy_frame_pc_unwind, + dummy_frame_id_unwind, + dummy_frame_register_unwind +}; + +const struct frame_unwind * +dummy_frame_p (CORE_ADDR pc) +{ + if (DEPRECATED_PC_IN_CALL_DUMMY_P () + ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0) + : pc_in_dummy_frame (pc)) + return &dummy_frame_unwind; + else + return NULL; +} + diff --git a/gdb/dummy-frame.h b/gdb/dummy-frame.h index 7743c8e..39bf1a9 100644 --- a/gdb/dummy-frame.h +++ b/gdb/dummy-frame.h @@ -22,6 +22,13 @@ #if !defined (DUMMY_FRAME_H) #define DUMMY_FRAME_H 1 +/* Does the PC belong to a dummy frame? If it does, return a dummy + frame unwind descriptor. */ + +struct frame_unwind; +extern const struct frame_unwind *dummy_frame_p (CORE_ADDR pc); + + struct frame_info; struct regcache; struct frame_id; diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c new file mode 100644 index 0000000..a08bcf0 --- /dev/null +++ b/gdb/frame-unwind.c @@ -0,0 +1,102 @@ +/* Definitions for a frame unwinder, for GDB, the GNU debugger. + + Copyright 2003 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 "frame.h" +#include "frame-unwind.h" +#include "gdb_assert.h" +#include "dummy-frame.h" +#include "legacy-frame.h" + +static struct gdbarch_data *frame_unwind_data; + +struct frame_unwind_table +{ + frame_unwind_p_ftype **p; + int middle; + int nr; +}; + +/* Append a predicate to the end of the table. */ +static void +append_predicate (struct frame_unwind_table *table, + frame_unwind_p_ftype *p) +{ + table->p = xrealloc (table->p, + (table->nr + 1) * sizeof (frame_unwind_p_ftype *)); + table->p[table->nr] = p; + table->nr++; +} + +static void * +frame_unwind_init (struct gdbarch *gdbarch) +{ + struct frame_unwind_table *table = XCALLOC (1, struct frame_unwind_table); + append_predicate (table, dummy_frame_p); + return table; +} + +static void +frame_unwind_free (struct gdbarch *gdbarch, void *data) +{ + struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); + xfree (table->p); + xfree (table); +} + +void +frame_unwind_append_predicate (struct gdbarch *gdbarch, + frame_unwind_p_ftype *p) +{ + struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); + if (table == NULL) + { + /* ULGH, called during architecture initialization. Patch + things up. */ + table = frame_unwind_init (gdbarch); + set_gdbarch_data (gdbarch, frame_unwind_data, table); + } + append_predicate (table, p); +} + +const struct frame_unwind * +frame_unwind_find_by_pc (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + int i; + struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); + /* Seriously old code. Don't even try to use this new mechanism. */ + if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES) + return legacy_frame_unwind_p (pc); + for (i = 0; i < table->nr; i++) + { + const struct frame_unwind *desc = table->p[i] (pc); + if (desc != NULL) + return desc; + } + return legacy_frame_unwind_p (pc); +} + +void +_initialize_frame_unwind (void) +{ + frame_unwind_data = register_gdbarch_data (frame_unwind_init, + frame_unwind_free); +} diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h new file mode 100644 index 0000000..5c82b6d --- /dev/null +++ b/gdb/frame-unwind.h @@ -0,0 +1,92 @@ +/* Definitions for a frame unwinder, for GDB, the GNU debugger. + + Copyright 2003 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. */ + +#if !defined (FRAME_UNWIND_H) +#define FRAME_UNWIND_H 1 + +struct frame_info; +struct frame_unwind_cache; +struct frame_unwind; +struct frame_id; +struct gdbarch; + +/* Return the corresponding frame descriptor this method is capable of + unwinding the frame containing PC. */ + +typedef const struct frame_unwind *(frame_unwind_p_ftype) (CORE_ADDR pc); + +/* Append a descriptor predicate. Descriptors are polled in append + order. The list is initialized with just the dummy frame. */ + +extern void frame_unwind_append_predicate (struct gdbarch *gdbarch, + frame_unwind_p_ftype *p); + +/* Iterate through the list of frame descriptor predicates for the + first one to return a frame descriptor. */ + +extern const struct frame_unwind *frame_unwind_find_by_pc (struct gdbarch *gdbarch, + CORE_ADDR pc); + +/* Return the location (and possibly value) of REGNUM for the previous + (older, up) frame. All parameters except VALUEP can be assumed to + be non NULL. When VALUEP is NULL, just the location of the + register should be returned. + + UNWIND_CACHE is provided as mechanism for implementing a per-frame + local cache. It's initial value being NULL. Memory for that cache + should be allocated using frame_obstack_zalloc(). + + Register window architectures (eg SPARC) should note that REGNUM + identifies the register for the previous frame. For instance, a + request for the value of "o1" for the previous frame would be found + in the register "i1" in this FRAME. */ + +typedef void (frame_register_unwind_ftype) (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + int regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep); + +/* Same as for registers above, but return the address at which the + calling frame would resume. */ + +typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache); + +/* Same as for registers above, but return the ID of the frame that + called this one. */ + +typedef void (frame_id_unwind_ftype) (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + struct frame_id *id); + +struct frame_unwind +{ + /* FIXME: Should the frame's type go here? */ + frame_pc_unwind_ftype *pc; + frame_id_unwind_ftype *id; + frame_register_unwind_ftype *reg; +}; + +#endif diff --git a/gdb/frame.c b/gdb/frame.c index daa243a..2a35a8c 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -62,7 +62,7 @@ frame_id_unwind (struct frame_info *frame) { if (!frame->id_unwind_cache_p) { - frame->id_unwind (frame, &frame->unwind_cache, &frame->id_unwind_cache); + frame->unwind->id (frame, &frame->unwind_cache, &frame->id_unwind_cache); frame->id_unwind_cache_p = 1; } return frame->id_unwind_cache; @@ -171,8 +171,8 @@ frame_register_unwind (struct frame_info *frame, int regnum, gdb_assert (frame != NULL); /* Ask this frame to unwind its register. */ - frame->register_unwind (frame, &frame->unwind_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + frame->unwind->reg (frame, &frame->unwind_cache, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); } void @@ -271,7 +271,7 @@ frame_read_unsigned_register (struct frame_info *frame, int regnum, on recursive frame calls (like the below code) when manipulating a frame chain. */ gdb_assert (frame != NULL); - frame_unwind_unsigned_register (get_next_frame (frame), regnum, val); + frame_unwind_unsigned_register (frame->next, regnum, val); } void @@ -280,7 +280,7 @@ frame_read_signed_register (struct frame_info *frame, int regnum, { /* See note in frame_read_unsigned_register(). */ gdb_assert (frame != NULL); - frame_unwind_signed_register (get_next_frame (frame), regnum, val); + frame_unwind_signed_register (frame->next, regnum, val); } static void @@ -409,9 +409,7 @@ create_sentinel_frame (struct regcache *regcache) frame->type = SENTINEL_FRAME; frame->level = -1; frame->unwind_cache = sentinel_frame_cache (regcache); - frame->pc_unwind = sentinel_frame_pc_unwind; - frame->id_unwind = sentinel_frame_id_unwind; - frame->register_unwind = sentinel_frame_register_unwind; + frame->unwind = sentinel_frame_unwind_p (0/* dummy value*/); /* Link this frame back to itself. The frame is self referential (the unwound PC is the same as the pc for instance, so make it so. */ @@ -554,42 +552,6 @@ select_frame (struct frame_info *fi) } } -/* Using the PC, select a mechanism for unwinding a frame returning - the previous frame. The register unwind function should, on - demand, initialize the ->context object. */ - -static void -set_unwind_by_pc (CORE_ADDR pc, - frame_register_unwind_ftype **unwind_register, - frame_pc_unwind_ftype **unwind_pc, - frame_id_unwind_ftype **unwind_id) -{ - if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES) - { - /* Still need to set this to something. The ``info frame'' code - calls this function to find out where the saved registers are. - Hopefully this is robust enough to stop any core dumps and - return vaguely correct values.. */ - *unwind_register = legacy_frame_register_unwind; - *unwind_pc = legacy_frame_pc_unwind; - *unwind_id = legacy_frame_id_unwind; - } - else if (DEPRECATED_PC_IN_CALL_DUMMY_P () - ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0) - : pc_in_dummy_frame (pc)) - { - *unwind_register = dummy_frame_register_unwind; - *unwind_pc = dummy_frame_pc_unwind; - *unwind_id = dummy_frame_id_unwind; - } - else - { - *unwind_register = legacy_frame_register_unwind; - *unwind_pc = legacy_frame_pc_unwind; - *unwind_id = legacy_frame_id_unwind; - } -} - /* Determine the frame's type based on its PC. */ static enum frame_type @@ -633,8 +595,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) INIT_EXTRA_FRAME_INFO (0, fi); /* Select/initialize an unwind function. */ - set_unwind_by_pc (fi->pc, &fi->register_unwind, &fi->pc_unwind, - &fi->id_unwind); + fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc); return fi; } @@ -857,8 +818,8 @@ legacy_get_prev_frame (struct frame_info *next_frame) (and probably other architectural information). The PC lets you check things like the debug info at that point (dwarf2cfi?) and use that to decide how the frame should be unwound. */ - set_unwind_by_pc (get_frame_pc (prev), &prev->register_unwind, - &prev->pc_unwind, &prev->id_unwind); + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, + get_frame_pc (prev)); /* NOTE: cagney/2002-11-18: The code segments, found in create_new_frame and get_prev_frame(), that initializes the @@ -1007,8 +968,8 @@ get_prev_frame (struct frame_info *next_frame) prev_frame->type = frame_type_from_pc (prev_frame->pc); /* Set the unwind functions based on that identified PC. */ - set_unwind_by_pc (prev_frame->pc, &prev_frame->register_unwind, - &prev_frame->pc_unwind, &prev_frame->id_unwind); + prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch, + prev_frame->pc); /* Now figure out how to initialize this new frame. Perhaphs one day, this will too, be selected by set_unwind_by_pc(). */ @@ -1062,7 +1023,7 @@ frame_pc_unwind (struct frame_info *frame) { if (!frame->pc_unwind_cache_p) { - frame->pc_unwind_cache = frame->pc_unwind (frame, &frame->unwind_cache); + frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache); frame->pc_unwind_cache_p = 1; } return frame->pc_unwind_cache; @@ -1114,7 +1075,8 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) CORE_ADDR get_frame_base (struct frame_info *fi) { - return fi->frame; + struct frame_id id = frame_id_unwind (fi->next); + return id.base; } /* Level of the selected frame: 0 for innermost, 1 for its caller, ... diff --git a/gdb/frame.h b/gdb/frame.h index f77a05e..6b80afc 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -309,41 +309,9 @@ extern CORE_ADDR frame_pc_unwind (struct frame_info *frame); extern struct frame_id frame_id_unwind (struct frame_info *frame); -/* Return the location (and possibly value) of REGNUM for the previous - (older, up) frame. All parameters except VALUEP can be assumed to - be non NULL. When VALUEP is NULL, just the location of the - register should be returned. - - UNWIND_CACHE is provided as mechanism for implementing a per-frame - local cache. It's initial value being NULL. Memory for that cache - should be allocated using frame_obstack_zalloc(). - - Register window architectures (eg SPARC) should note that REGNUM - identifies the register for the previous frame. For instance, a - request for the value of "o1" for the previous frame would be found - in the register "i1" in this FRAME. */ - -typedef void (frame_register_unwind_ftype) (struct frame_info *frame, - struct frame_unwind_cache **unwind_cache, - int regnum, - int *optimized, - enum lval_type *lvalp, - CORE_ADDR *addrp, - int *realnump, - void *valuep); - -/* Same as for registers above, but return the address at which the - calling frame would resume. */ - -typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame, - struct frame_unwind_cache **unwind_cache); - -/* Same as for registers above, but return the ID of the frame that - called this one. */ - -typedef void (frame_id_unwind_ftype) (struct frame_info *frame, - struct frame_unwind_cache **unwind_cache, - struct frame_id *id); +/* FIXME: cagney/2003-01-12: Once `struct frame_info' has been made + opaque, this include can go. */ +#include "frame-unwind.h" /* Describe the saved registers of a frame. */ @@ -431,19 +399,13 @@ struct frame_info /* Unwind cache shared between the unwind functions - they had better all agree as to the contents. */ struct frame_unwind_cache *unwind_cache; + const struct frame_unwind *unwind; - /* See description above. The previous frame's registers. */ - frame_register_unwind_ftype *register_unwind; - - /* See description above. The previous frame's resume address. - Save the previous PC in a local cache. */ - frame_pc_unwind_ftype *pc_unwind; + /* Cache for the unwound PC value. */ int pc_unwind_cache_p; CORE_ADDR pc_unwind_cache; - /* See description above. The previous frame's resume address. - Save the previous PC in a local cache. */ - frame_id_unwind_ftype *id_unwind; + /* Cache for the unwound frame ID value. */ int id_unwind_cache_p; struct frame_id id_unwind_cache; diff --git a/gdb/legacy-frame.c b/gdb/legacy-frame.c index 9922780..b22e6a3 100644 --- a/gdb/legacy-frame.c +++ b/gdb/legacy-frame.c @@ -28,6 +28,8 @@ #include "regcache.h" #include "target.h" #include "dummy-frame.h" /* For generic_find_dummy_frame. */ +#include "frame-unwind.h" + /* Legacy frame. This saves the processor state just prior to setting up the inferior function call. Older targets save the registers @@ -299,3 +301,17 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized, if (raw_buffer) deprecated_read_register_gen (regnum, raw_buffer); } + + +const struct frame_unwind legacy_frame_unwind = +{ + legacy_frame_pc_unwind, + legacy_frame_id_unwind, + legacy_frame_register_unwind +}; + +const struct frame_unwind * +legacy_frame_unwind_p (CORE_ADDR pc) +{ + return &legacy_frame_unwind; +} diff --git a/gdb/legacy-frame.h b/gdb/legacy-frame.h index 999e76a..909893a 100644 --- a/gdb/legacy-frame.h +++ b/gdb/legacy-frame.h @@ -22,6 +22,11 @@ #if !defined (LEGACY_FRAME_H) #define LEGACY_FRAME_H 1 +/* Frame unwinder for legacy code. */ + +const struct frame_unwind *legacy_frame_unwind_p (CORE_ADDR pc); + + struct frame_info; struct regcache; struct frame_id; diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c new file mode 100644 index 0000000..036c318 --- /dev/null +++ b/gdb/sentinel-frame.c @@ -0,0 +1,107 @@ +/* Code dealing with register stack frames, for GDB, the GNU debugger. + + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 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 "regcache.h" +#include "sentinel-frame.h" +#include "inferior.h" + +struct frame_unwind_cache +{ + struct regcache *regcache; +}; + +struct frame_unwind_cache * +sentinel_frame_cache (struct regcache *regcache) +{ + struct frame_unwind_cache *cache = + FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache); + cache->regcache = regcache; + return cache; +} + +/* Here the register value is taken direct from the register cache. */ + +void +sentinel_frame_register_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + int regnum, int *optimized, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnum, void *bufferp) +{ + struct frame_unwind_cache *cache = *unwind_cache; + /* Describe the register's location. A reg-frame maps all registers + onto the corresponding hardware register. */ + *optimized = 0; + *lvalp = lval_register; + *addrp = REGISTER_BYTE (regnum); + *realnum = regnum; + + /* If needed, find and return the value of the register. */ + if (bufferp != NULL) + { + /* Return the actual value. */ + /* Use the regcache_cooked_read() method so that it, on the fly, + constructs either a raw or pseudo register from the raw + register cache. */ + regcache_cooked_read (cache->regcache, regnum, bufferp); + } +} + +CORE_ADDR +sentinel_frame_pc_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache) +{ + /* FIXME: cagney/2003-01-08: This should be using a per-architecture + method that doesn't suffer from DECR_PC_AFTER_BREAK problems. + Such a method would take unwind_cache, regcache and stop reason + parameters. */ + return read_pc (); +} + +void +sentinel_frame_id_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache, + struct frame_id *id) +{ + /* FIXME: cagney/2003-01-08: This should be using a per-architecture + method that doesn't suffer from DECR_PC_AFTER_BREAK problems. + Such a method would take unwind_cache, regcache and stop reason + parameters. */ + id->base = read_fp (); + id->pc = read_pc (); +} + +const struct frame_unwind sentinel_frame_unwind = +{ + sentinel_frame_pc_unwind, + sentinel_frame_id_unwind, + sentinel_frame_register_unwind +}; + +const struct frame_unwind * +sentinel_frame_unwind_p (CORE_ADDR pc) +{ + return &sentinel_frame_unwind; +} diff --git a/gdb/sentinel-frame.h b/gdb/sentinel-frame.h new file mode 100644 index 0000000..a7d2187 --- /dev/null +++ b/gdb/sentinel-frame.h @@ -0,0 +1,65 @@ +/* Code dealing with register stack frames, for GDB, the GNU debugger. + + Copyright 2002 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. */ + +#if !defined (SENTINEL_FRAME_H) +#define SENTINEL_FRAME_H 1 + +struct frame_info; +struct frame_id; +struct frame_unwind_cache; + +/* Implement the sentinel frame. The sentinel frame terminates the + inner most end of the frame chain. If unwound, it returns the + information need to construct an inner-most frame. */ + +/* Pump prime the sentinel frame's cache. Since this needs the + REGCACHE provide that here. */ + +struct frame_unwind_cache *sentinel_frame_cache (struct regcache *regcache); + +/* Return the previous frames register value. For a sentinel-frame, + it is the value found in the register cache. */ + +extern void sentinel_frame_register_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + int regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep); + +/* Return the resume address of the previous frame. For the + sentinel-frame, it is the threads resume address. */ + +extern CORE_ADDR sentinel_frame_pc_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache); + +/* Return the frame ID of the previous frame. For the sentinel-frame, + it is the ID of the inner most frame. */ + +extern void sentinel_frame_id_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + struct frame_id *id); + +extern const struct frame_unwind *sentinel_frame_unwind_p (CORE_ADDR pc); + +#endif /* !defined (SENTINEL_FRAME_H) */ |