diff options
-rw-r--r-- | gdb/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/Makefile.in | 8 | ||||
-rw-r--r-- | gdb/tramp-frame.c | 162 | ||||
-rw-r--r-- | gdb/tramp-frame.h | 64 |
4 files changed, 237 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5345794..9fd43ae 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,9 @@ 2004-03-23 Andrew Cagney <cagney@redhat.com> + * tramp-frame.h, tramp-frame.h: New files. + * Makefile.in (SFILES, tramp_frame_h, COMMON_OBS, tramp-frame.o): + Update rules to include "tramp-frame.h" and "tramp-frame.c". + * Makefile.in: Update all dependencies. 2004-03-23 Andrew Cagney <cagney@redhat.com> diff --git a/gdb/Makefile.in b/gdb/Makefile.in index a649085..e2105e5 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -541,6 +541,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ stabsread.c stack.c std-regs.c symfile.c symmisc.c symtab.c \ target.c thread.c top.c tracepoint.c \ trad-frame.c \ + tramp-frame.c \ typeprint.c \ ui-out.c utils.c ui-file.h ui-file.c \ user-regs.c \ @@ -757,6 +758,7 @@ terminal_h = terminal.h top_h = top.h tracepoint_h = tracepoint.h trad_frame_h = trad-frame.h $(frame_h) +tramp_frame_h = tramp-frame.h typeprint_h = typeprint.h ui_file_h = ui-file.h ui_out_h = ui-out.h @@ -905,7 +907,8 @@ COMMON_OBS = $(DEPFILES) $(YYOBJ) \ gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \ cp-namespace.o \ reggroups.o \ - trad-frame.o + trad-frame.o \ + tramp-frame.o TSOBS = inflow.o @@ -2444,6 +2447,9 @@ tracepoint.o: tracepoint.c $(defs_h) $(symtab_h) $(frame_h) $(gdbtypes_h) \ $(readline_history_h) trad-frame.o: trad-frame.c $(defs_h) $(frame_h) $(trad_frame_h) \ $(regcache_h) +tramp-frame.o: tramp-frame.c $(defs_h) $(tramp_frame_h) $(frame_unwind_h) \ + $(gdbcore_h) $(symtab_h) $(objfiles_h) $(target_h) $(trad_frame_h) \ + $(frame_base_h) typeprint.o: typeprint.c $(defs_h) $(gdb_obstack_h) $(bfd_h) $(symtab_h) \ $(gdbtypes_h) $(expression_h) $(value_h) $(gdbcore_h) $(command_h) \ $(gdbcmd_h) $(target_h) $(language_h) $(cp_abi_h) $(typeprint_h) \ diff --git a/gdb/tramp-frame.c b/gdb/tramp-frame.c new file mode 100644 index 0000000..7a8057e --- /dev/null +++ b/gdb/tramp-frame.c @@ -0,0 +1,162 @@ +/* Signal trampoline unwinder, for GDB the GNU Debugger. + + 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 "tramp-frame.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "symtab.h" +#include "objfiles.h" +#include "target.h" +#include "trad-frame.h" +#include "frame-base.h" + +struct frame_data +{ + const struct tramp_frame *tramp_frame; +}; + +struct tramp_frame_cache +{ + CORE_ADDR func; + const struct tramp_frame *tramp_frame; + struct trad_frame_cache *trad_cache; +}; + +static struct trad_frame_cache * +tramp_frame_cache (struct frame_info *next_frame, + void **this_cache) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + struct tramp_frame_cache *tramp_cache = (*this_cache); + if (tramp_cache->trad_cache == NULL) + { + tramp_cache->trad_cache = trad_frame_cache_zalloc (next_frame); + tramp_cache->tramp_frame->init (tramp_cache->tramp_frame, + next_frame, + tramp_cache->trad_cache, + tramp_cache->func); + } + return tramp_cache->trad_cache; +} + +static void +tramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct trad_frame_cache *trad_cache + = tramp_frame_cache (next_frame, this_cache); + trad_frame_get_id (trad_cache, this_id); +} + +static void +tramp_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int prev_regnum, + int *optimizedp, + enum lval_type * lvalp, + CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct trad_frame_cache *trad_cache + = tramp_frame_cache (next_frame, this_cache); + trad_frame_get_register (trad_cache, next_frame, prev_regnum, optimizedp, + lvalp, addrp, realnump, valuep); +} + +static CORE_ADDR +tramp_frame_start (CORE_ADDR pc, const struct tramp_frame *tramp) +{ + int ti; + /* Search through the trampoline for one that matches the + instruction sequence around PC. */ + for (ti = 0; tramp->insn[ti] != 0; ti++) + { + CORE_ADDR func = pc - tramp->insn_size * ti; + int i; + for (i = 0; 1; i++) + { + bfd_byte buf[sizeof (LONGEST)]; + CORE_ADDR insn; + if (tramp->insn[i] == 0) + return func; + if (target_read_memory (func + i * tramp->insn_size, buf, + tramp->insn_size) != 0) + break; + insn = extract_unsigned_integer (buf, tramp->insn_size); + if (tramp->insn[i] != insn) + break; + } + } + /* Trampoline doesn't match. */ + return 0; +} + +static int +tramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *next_frame, + void **this_cache) +{ + const struct tramp_frame *tramp = self->unwind_data->tramp_frame; + CORE_ADDR pc = frame_pc_unwind (next_frame); + CORE_ADDR func; + char *name; + struct tramp_frame_cache *tramp_cache; + + /* If the function has a valid symbol name, it isn't a + trampoline. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (name != NULL) + return 0; + /* If the function lives in a valid section (even without a starting + point) it isn't a trampoline. */ + if (find_pc_section (pc) != NULL) + return 0; + /* Finally, check that the trampoline matches at PC. */ + func = tramp_frame_start (pc, tramp); + if (func == 0) + return 0; + tramp_cache = FRAME_OBSTACK_ZALLOC (struct tramp_frame_cache); + tramp_cache->func = func; + tramp_cache->tramp_frame = tramp; + (*this_cache) = tramp_cache; + return 1; +} + +void +tramp_frame_append (struct gdbarch *gdbarch, + const struct tramp_frame *tramp_frame) +{ + struct frame_data *data; + struct frame_unwind *unwinder; + + data = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_data); + unwinder = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind); + + data->tramp_frame = tramp_frame; + unwinder->type = SIGTRAMP_FRAME; + unwinder->unwind_data = data; + unwinder->sniffer = tramp_frame_sniffer; + unwinder->this_id = tramp_frame_this_id; + unwinder->prev_register = tramp_frame_prev_register; + frame_unwind_register_unwinder (gdbarch, unwinder); +} diff --git a/gdb/tramp-frame.h b/gdb/tramp-frame.h new file mode 100644 index 0000000..44e266e --- /dev/null +++ b/gdb/tramp-frame.h @@ -0,0 +1,64 @@ +/* Signal trampoline unwinder, for GDB the GNU Debugger. + + 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 TRAMP_FRAME_H +#define TRAMP_FRAME_H + +struct trad_frame; +struct frame_info; +struct trad_frame_cache; + +/* A trampoline consists of a small sequence of instructions placed at + an unspecified location in the inferior's address space. The only + identifying attribute of the trampoline's address is that it does + not fall inside an object file's section. + + The only way to identify a trampoline is to perform a brute force + examination of the instructions at and around the PC. + + This module provides a convent interface for performing that + operation. */ + +/* A trampoline descriptor. */ + +struct tramp_frame +{ + /* The trampoline's entire instruction sequence. Search for this in + the inferior at or around the frame's PC. It is assumed that the + PC is INSN_SIZE aligned, and that each element of TRAMP contains + one INSN_SIZE instruction. It is also assumed that TRAMP[0] + contains the first instruction of the trampoline and hence the + address of the instruction matching TRAMP[0] is the trampoline's + "func" address. */ + int insn_size; + ULONGEST insn[8]; + /* Initialize a trad-frame cache corresponding to the tramp-frame. + FUNC is the address of the instruction TRAMP[0] in memory. */ + void (*init) (const struct tramp_frame *self, + struct frame_info *next_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func); +}; + +void tramp_frame_append (struct gdbarch *gdbarch, + const struct tramp_frame *tramp); + +#endif |