From 669fac235d5edab8e2f33c4f3382f3b61671dc8e Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 30 Apr 2008 21:16:46 +0000 Subject: [PATCH] Convert frame unwinders to use the current frame and "struct value". * frame.c (frame_debug): Make global. (get_frame_id): Pass this frame to unwinder routines. (frame_pc_unwind): Remove unused unwind->prev_pc support. (do_frame_register_read): Do not discard the return value of frame_register_read. (frame_register_unwind): Remove debug messages. Use frame_unwind_register_value. (frame_unwind_register_value, get_frame_register_value): New functions. (create_new_frame, get_frame_base_address, get_frame_locals_address) (get_frame_args_address, get_frame_type): Pass this frame to unwinder routines. (frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New functions. * frame.h: Update comments. (frame_debug, frame_unwind_register_value, get_frame_register_value) (frame_prepare_for_sniffer): Declare. * frame-unwind.h: Update comments and parameter names. (default_frame_sniffer): Declare. (frame_prev_register_ftype): Return a struct value *. (struct frame_unwind): Remove prev_pc member. (frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete. (frame_unwind_append_unwinder, frame_unwind_got_optimized) (frame_unwind_got_register, frame_unwind_got_memory) (frame_unwind_got_constant, frame_unwind_got_address): Declare. * frame-base.h: Update comments and parameter names. * valops.c (value_fetch_lazy): Use get_frame_register_value. Iterate if necessary. Add debugging output. * sentinel-frame.c (sentinel_frame_prev_register) (sentinel_frame_this_id): Update for new signature. (sentinel_frame_prev_pc): Delete. (sentinel_frame_unwinder): Remove prev_pc. * ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize prev_pc. * libunwind-frame.c (libunwind_frame_unwind): Likewise. * frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer. (frame_unwind_append_sniffer): Delete. (frame_unwind_append_unwinder): New function. (frame_unwind_find_by_frame): Take this frame. Only use sniffers from unwinders. Use frame_prepare_for_sniffer. (default_frame_sniffer, frame_unwind_got_optimized) (frame_unwind_got_register, frame_unwind_got_memory) (frame_unwind_got_constant, frame_unwind_got_address): New functions. * dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id. (dummy_frame_prev_register, dummy_frame_this_id): Update for new signature. * gdbarch.sh: Replace unwind_dummy_id with dummy_id. * gdbarch.c, gdbarch.c: Regenerated. * frame-base.c (default_frame_base_address) (default_frame_locals_address, default_frame_args_address): Update for new signature. (frame_base_find_by_frame): Pass this frame to unwinder routines. * infcall.c (call_function_by_hand): Update comments. * Makefile.in (frame-unwind.o): Update dependencies. * gdbint.texinfo (Stack Frames): New chapter. (Algorithms): Move Frames text to the new chapter. (Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS. Document gdbarch_dummy_id instead of gdbarch_unwind_dummy_id. --- gdb/ChangeLog | 60 ++++++++++++ gdb/Makefile.in | 3 +- gdb/doc/ChangeLog | 17 +++- gdb/doc/gdbint.texinfo | 172 +++++++++++++++++++++++++--------- gdb/dummy-frame.c | 55 +++++------ gdb/frame-base.c | 17 ++-- gdb/frame-base.h | 18 ++-- gdb/frame-unwind.c | 136 +++++++++++++++++++++------ gdb/frame-unwind.h | 107 ++++++++++++--------- gdb/frame.c | 208 +++++++++++++++++++++++++++-------------- gdb/frame.h | 18 +++- gdb/gdbarch.c | 36 +++---- gdb/gdbarch.h | 10 +- gdb/gdbarch.sh | 4 +- gdb/ia64-tdep.c | 1 - gdb/infcall.c | 6 +- gdb/libunwind-frame.c | 1 - gdb/sentinel-frame.c | 54 ++++------- gdb/valops.c | 89 +++++++++++++++--- 19 files changed, 689 insertions(+), 323 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7dbdef07e5..ec0e06c3e1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,63 @@ +2008-04-30 Daniel Jacobowitz + + Convert frame unwinders to use the current frame and + "struct value". + + * frame.c (frame_debug): Make global. + (get_frame_id): Pass this frame to unwinder routines. + (frame_pc_unwind): Remove unused unwind->prev_pc support. + (do_frame_register_read): Do not discard the return value of + frame_register_read. + (frame_register_unwind): Remove debug messages. Use + frame_unwind_register_value. + (frame_unwind_register_value, get_frame_register_value): New + functions. + (create_new_frame, get_frame_base_address, get_frame_locals_address) + (get_frame_args_address, get_frame_type): Pass this frame to + unwinder routines. + (frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New + functions. + * frame.h: Update comments. + (frame_debug, frame_unwind_register_value, get_frame_register_value) + (frame_prepare_for_sniffer): Declare. + * frame-unwind.h: Update comments and parameter names. + (default_frame_sniffer): Declare. + (frame_prev_register_ftype): Return a struct value *. + (struct frame_unwind): Remove prev_pc member. + (frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete. + (frame_unwind_append_unwinder, frame_unwind_got_optimized) + (frame_unwind_got_register, frame_unwind_got_memory) + (frame_unwind_got_constant, frame_unwind_got_address): Declare. + * frame-base.h: Update comments and parameter names. + * valops.c (value_fetch_lazy): Use get_frame_register_value. Iterate + if necessary. Add debugging output. + * sentinel-frame.c (sentinel_frame_prev_register) + (sentinel_frame_this_id): Update for new signature. + (sentinel_frame_prev_pc): Delete. + (sentinel_frame_unwinder): Remove prev_pc. + * ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize + prev_pc. + * libunwind-frame.c (libunwind_frame_unwind): Likewise. + * frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer. + (frame_unwind_append_sniffer): Delete. + (frame_unwind_append_unwinder): New function. + (frame_unwind_find_by_frame): Take this frame. Only use sniffers + from unwinders. Use frame_prepare_for_sniffer. + (default_frame_sniffer, frame_unwind_got_optimized) + (frame_unwind_got_register, frame_unwind_got_memory) + (frame_unwind_got_constant, frame_unwind_got_address): New functions. + * dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id. + (dummy_frame_prev_register, dummy_frame_this_id): Update for new + signature. + * gdbarch.sh: Replace unwind_dummy_id with dummy_id. + * gdbarch.c, gdbarch.c: Regenerated. + * frame-base.c (default_frame_base_address) + (default_frame_locals_address, default_frame_args_address): Update + for new signature. + (frame_base_find_by_frame): Pass this frame to unwinder routines. + * infcall.c (call_function_by_hand): Update comments. + * Makefile.in (frame-unwind.o): Update dependencies. + 2008-04-30 Daniel Jacobowitz * ada-lang.c (ada_value_primitive_packed_val): Only check diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9304bc2f58..98ae55892f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2143,7 +2143,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \ $(annotate_h) $(language_h) $(frame_unwind_h) $(frame_base_h) \ $(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h) frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \ - $(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h) + $(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h) $(value_h) \ + $(regcache_h) frv-linux-tdep.o: frv-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \ $(frame_h) $(osabi_h) $(regcache_h) $(elf_bfd_h) $(elf_frv_h) \ $(frv_tdep_h) $(trad_frame_h) $(frame_unwind_h) $(regset_h) \ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 9cdf5d9809..2285c835ce 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,6 +1,13 @@ +2008-04-30 Daniel Jacobowitz + + * gdbint.texinfo (Stack Frames): New chapter. + (Algorithms): Move Frames text to the new chapter. + (Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS. Document + gdbarch_dummy_id instead of gdbarch_unwind_dummy_id. + 2008-04-24 Vladimir Prus - * doc/gdb.texinfo (GDB/MI Output Syntax): Clarify that async + * gdb.texinfo (GDB/MI Output Syntax): Clarify that async output does not necessary include any tokens. 2008-04-22 Corinna Vinschen @@ -223,7 +230,7 @@ 2007-12-17 Luis Machado - * doc/gdb.texinfo: Add new parameter's description. + * gdb.texinfo: Add new parameter's description. 2007-12-16 Daniel Jacobowitz @@ -715,7 +722,7 @@ 2007-02-26 Daniel Jacobowitz - * src/gdb/doc/gdb.texinfo (Standard Target Features): Mention + * gdb.texinfo (Standard Target Features): Mention case insensitivity. (ARM Features): Describe org.gnu.gdb.xscale.iwmmxt. @@ -744,7 +751,7 @@ (Target Description Format): Document new elements. Use @smallexample. (Predefined Target Types, Standard Target Features): New sections. - * doc/gdbint.texinfo (Target Descriptions): New section. + * gdbint.texinfo (Target Descriptions): New section. 2007-02-07 Daniel Jacobowitz @@ -1017,7 +1024,7 @@ 2006-07-05 Daniel Jacobowitz - * doc/gdb.texinfo (KOD): Remove node. + * gdb.texinfo (KOD): Remove node. (GDB/MI Kod Commands): Remove commented out node. 2006-07-01 Eli Zaretskii diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index d578347b96..39cb031c38 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets. * Algorithms:: * User Interface:: * libgdb:: +* Stack Frames:: * Symbol Handling:: * Language Support:: * Host Definition:: @@ -273,39 +274,6 @@ cases and real-world issues. This chapter describes the basic algorithms and mentions some of the specific target definitions that they use. -@section Frames - -@cindex frame -@cindex call stack frame -A frame is a construct that @value{GDBN} uses to keep track of calling -and called functions. - -@cindex frame, unwind -@value{GDBN}'s frame model, a fresh design, was implemented with the -need to support @sc{dwarf}'s Call Frame Information in mind. In fact, -the term ``unwind'' is taken directly from that specification. -Developers wishing to learn more about unwinders, are encouraged to -read the @sc{dwarf} specification. - -@findex frame_register_unwind -@findex get_frame_register -@value{GDBN}'s model is that you find a frame's registers by -``unwinding'' them from the next younger frame. That is, -@samp{get_frame_register} which returns the value of a register in -frame #1 (the next-to-youngest frame), is implemented by calling frame -#0's @code{frame_register_unwind} (the youngest frame). But then the -obvious question is: how do you access the registers of the youngest -frame itself? - -@cindex sentinel frame -@findex get_frame_type -@vindex SENTINEL_FRAME -To answer this question, GDB has the @dfn{sentinel} frame, the -``-1st'' frame. Unwinding registers from the sentinel frame gives you -the current values of the youngest real frame's registers. If @var{f} -is a sentinel frame, then @code{get_frame_type (@var{f}) == -SENTINEL_FRAME}. - @section Prologue Analysis @cindex prologue analysis @@ -1853,6 +1821,127 @@ the query interface. Each function is parameterized by a @code{ui-out} builder. The result of the query is constructed using that builder before the query function returns. +@node Stack Frames +@chapter Stack Frames + +@cindex frame +@cindex call stack frame +A frame is a construct that @value{GDBN} uses to keep track of calling +and called functions. + +@cindex unwind frame +@value{GDBN}'s frame model, a fresh design, was implemented with the +need to support @sc{dwarf}'s Call Frame Information in mind. In fact, +the term ``unwind'' is taken directly from that specification. +Developers wishing to learn more about unwinders, are encouraged to +read the @sc{dwarf} specification, available from +@url{http://www.dwarfstd.org}. + +@findex frame_register_unwind +@findex get_frame_register +@value{GDBN}'s model is that you find a frame's registers by +``unwinding'' them from the next younger frame. That is, +@samp{get_frame_register} which returns the value of a register in +frame #1 (the next-to-youngest frame), is implemented by calling frame +#0's @code{frame_register_unwind} (the youngest frame). But then the +obvious question is: how do you access the registers of the youngest +frame itself? + +@cindex sentinel frame +@findex get_frame_type +@vindex SENTINEL_FRAME +To answer this question, GDB has the @dfn{sentinel} frame, the +``-1st'' frame. Unwinding registers from the sentinel frame gives you +the current values of the youngest real frame's registers. If @var{f} +is a sentinel frame, then @code{get_frame_type (@var{f}) @equiv{} +SENTINEL_FRAME}. + +@section Selecting an Unwinder + +@findex frame_unwind_prepend_unwinder +@findex frame_unwind_append_unwinder +The architecture registers a list of frame unwinders (@code{struct +frame_unwind}), using the functions +@code{frame_unwind_prepend_unwinder} and +@code{frame_unwind_append_unwinder}. Each unwinder includes a +sniffer. Whenever @value{GDBN} needs to unwind a frame (to fetch the +previous frame's registers or the current frame's ID), it calls +registered sniffers in order to find one which recognizes the frame. +The first time a sniffer returns non-zero, the corresponding unwinder +is assigned to the frame. + +@section Unwinding the Frame ID +@cindex frame ID + +Every frame has an associated ID, of type @code{struct frame_id}. +The ID includes the stack base and function start address for +the frame. The ID persists through the entire life of the frame, +including while other called frames are running; it is used to +locate an appropriate @code{struct frame_info} from the cache. + +Every time the inferior stops, and at various other times, the frame +cache is flushed. Because of this, parts of @value{GDBN} which need +to keep track of individual frames cannot use pointers to @code{struct +frame_info}. A frame ID provides a stable reference to a frame, even +when the unwinder must be run again to generate a new @code{struct +frame_info} for the same frame. + +The frame's unwinder's @code{this_id} method is called to find the ID. +Note that this is different from register unwinding, where the next +frame's @code{prev_register} is called to unwind this frame's +registers. + +Both stack base and function address are required to identify the +frame, because a recursive function has the same function address for +two consecutive frames and a leaf function may have the same stack +address as its caller. On some platforms, a third address is part of +the ID to further disambiguate frames---for instance, on IA-64 +the separate register stack address is included in the ID. + +An invalid frame ID (@code{null_frame_id}) returned from the +@code{this_id} method means to stop unwinding after this frame. + +@section Unwinding Registers + +Each unwinder includes a @code{prev_register} method. This method +takes a frame, an associated cache pointer, and a register number. +It returns a @code{struct value *} describing the requested register, +as saved by this frame. This is the value of the register that is +current in this frame's caller. + +The returned value must have the same type as the register. It may +have any lvalue type. In most circumstances one of these routines +will generate the appropriate value: + +@table @code +@item frame_unwind_got_optimized +@findex frame_unwind_got_optimized +This register was not saved. + +@item frame_unwind_got_register +@findex frame_unwind_got_register +This register was copied into another register in this frame. This +is also used for unchanged registers; they are ``copied'' into the +same register. + +@item frame_unwind_got_memory +@findex frame_unwind_got_memory +This register was saved in memory. + +@item frame_unwind_got_constant +@findex frame_unwind_got_constant +This register was not saved, but the unwinder can compute the previous +value some other way. + +@item frame_unwind_got_address +@findex frame_unwind_got_address +Same as @code{frame_unwind_got_constant}, except that the value is a target +address. This is frequently used for the stack pointer, which is not +explicitly saved but has a known offset from this frame's stack +pointer. For architectures with a flat unified address space, this is +generally the same as @code{frame_unwind_got_constant}. +@end table + @node Symbol Handling @chapter Symbol Handling @@ -3943,14 +4032,6 @@ This method replaces @w{@code{gdbarch_call_dummy_location (@var{gdbarch})}} and Return the name of register @var{regnr} as a string. May return @code{NULL} to indicate that @var{regnr} is not a valid register. -@item SAVE_DUMMY_FRAME_TOS (@var{sp}) -@findex SAVE_DUMMY_FRAME_TOS -@anchor{SAVE_DUMMY_FRAME_TOS} Used in @samp{call_function_by_hand} to -notify the target dependent code of the top-of-stack value that will be -passed to the inferior code. This is the value of the @code{SP} -after both the dummy frame and space for parameters/results have been -allocated on the stack. @xref{gdbarch_unwind_dummy_id}. - @item int gdbarch_sdb_reg_to_regnum (@var{gdbarch}, @var{sdb_regnr}) @findex gdbarch_sdb_reg_to_regnum Use this function to convert sdb register @var{sdb_regnr} into @value{GDBN} @@ -4132,13 +4213,12 @@ the @code{opcodes} library (@pxref{Support Libraries, ,Opcodes}). @file{include/dis-asm.h} used to pass information to the instruction decoding routine. -@item frame_id gdbarch_unwind_dummy_id (@var{gdbarch}, @var{frame}) -@findex gdbarch_unwind_dummy_id -@anchor{gdbarch_unwind_dummy_id} Given @var{frame} return a @w{@code{struct +@item frame_id gdbarch_dummy_id (@var{gdbarch}, @var{frame}) +@findex gdbarch_dummy_id +@anchor{gdbarch_dummy_id} Given @var{frame} return a @w{@code{struct frame_id}} that uniquely identifies an inferior function call's dummy frame. The value returned must match the dummy frame stack value -previously saved using @code{SAVE_DUMMY_FRAME_TOS}. -@xref{SAVE_DUMMY_FRAME_TOS}. +previously saved by @code{call_function_by_hand}. @item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type}) @findex DEPRECATED_USE_STRUCT_CONVENTION diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index 3095f76bf8..4c044ef3df 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -39,7 +39,7 @@ struct dummy_frame { struct dummy_frame *next; /* This frame's ID. Must match the value returned by - gdbarch_unwind_dummy_id. */ + gdbarch_dummy_id. */ struct frame_id id; /* The caller's regcache. */ struct regcache *regcache; @@ -124,7 +124,7 @@ struct dummy_frame_cache int dummy_frame_sniffer (const struct frame_unwind *self, - struct frame_info *next_frame, + struct frame_info *this_frame, void **this_prologue_cache) { struct dummy_frame *dummyframe; @@ -141,12 +141,9 @@ dummy_frame_sniffer (const struct frame_unwind *self, /* Don't bother unles there is at least one dummy frame. */ if (dummy_frame_stack != NULL) { - /* Use an architecture specific method to extract the prev's - dummy ID from the next frame. Note that this method uses - frame_register_unwind to obtain the register values needed to - determine the dummy frame's ID. */ - this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame), - next_frame); + /* Use an architecture specific method to extract this frame's + dummy ID, assuming it is a dummy frame. */ + this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame); /* Use that ID to find the corresponding cache entry. */ for (dummyframe = dummy_frame_stack; @@ -170,43 +167,37 @@ dummy_frame_sniffer (const struct frame_unwind *self, /* Given a call-dummy dummy-frame, return the registers. Here the register value is taken from the local copy of the register buffer. */ -static void -dummy_frame_prev_register (struct frame_info *next_frame, +static struct value * +dummy_frame_prev_register (struct frame_info *this_frame, void **this_prologue_cache, - int regnum, int *optimized, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, gdb_byte *bufferp) + int regnum) { - /* The dummy-frame sniffer always fills in the cache. */ struct dummy_frame_cache *cache = (*this_prologue_cache); + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct value *reg_val; + + /* The dummy-frame sniffer always fills in the cache. */ gdb_assert (cache != NULL); /* Describe the register's location. Generic dummy frames always have the register value in an ``expression''. */ - *optimized = 0; - *lvalp = not_lval; - *addrp = 0; - *realnum = -1; - - /* 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->prev_regcache, regnum, bufferp); - } + reg_val = value_zero (register_type (gdbarch, regnum), not_lval); + + /* 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->prev_regcache, regnum, + value_contents_writeable (reg_val)); + return reg_val; } -/* Assuming that THIS frame is a dummy (remember, the NEXT and not - THIS frame is passed in), return the ID of THIS frame. That ID is +/* Assuming that THIS frame is a dummy, return the ID of THIS frame. That ID is determined by examining the NEXT frame's unwound registers using - the method unwind_dummy_id(). As a side effect, THIS dummy frame's + the method dummy_id(). As a side effect, THIS dummy frame's dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */ static void -dummy_frame_this_id (struct frame_info *next_frame, +dummy_frame_this_id (struct frame_info *this_frame, void **this_prologue_cache, struct frame_id *this_id) { diff --git a/gdb/frame-base.c b/gdb/frame-base.c index b85d2de385..e7b6cdd0c4 100644 --- a/gdb/frame-base.c +++ b/gdb/frame-base.c @@ -28,22 +28,21 @@ really need to override this. */ static CORE_ADDR -default_frame_base_address (struct frame_info *next_frame, void **this_cache) +default_frame_base_address (struct frame_info *this_frame, void **this_cache) { - struct frame_info *this_frame = get_prev_frame (next_frame); return get_frame_base (this_frame); /* sigh! */ } static CORE_ADDR -default_frame_locals_address (struct frame_info *next_frame, void **this_cache) +default_frame_locals_address (struct frame_info *this_frame, void **this_cache) { - return default_frame_base_address (next_frame, this_cache); + return default_frame_base_address (this_frame, this_cache); } static CORE_ADDR -default_frame_args_address (struct frame_info *next_frame, void **this_cache) +default_frame_args_address (struct frame_info *this_frame, void **this_cache) { - return default_frame_base_address (next_frame, this_cache); + return default_frame_base_address (this_frame, this_cache); } const struct frame_base default_frame_base = { @@ -97,16 +96,16 @@ frame_base_set_default (struct gdbarch *gdbarch, } const struct frame_base * -frame_base_find_by_frame (struct frame_info *next_frame) +frame_base_find_by_frame (struct frame_info *this_frame) { - struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data); struct frame_base_table_entry *entry; for (entry = table->head; entry != NULL; entry = entry->next) { const struct frame_base *desc = NULL; - desc = entry->sniffer (next_frame); + desc = entry->sniffer (this_frame); if (desc != NULL) return desc; } diff --git a/gdb/frame-base.h b/gdb/frame-base.h index 8fbcb28df0..7f10e1e165 100644 --- a/gdb/frame-base.h +++ b/gdb/frame-base.h @@ -28,9 +28,9 @@ struct gdbarch; struct regcache; /* Assuming the frame chain: (outer) prev <-> this <-> next (inner); - and that this is a `normal frame'; use the NEXT frame, and its - register unwind method, to determine the address of THIS frame's - `base'. + and that this is a `normal frame'; use THIS frame, and implicitly + the NEXT frame's register unwind method, to determine the address + of THIS frame's `base'. The exact meaning of `base' is highly dependant on the type of the debug info. It is assumed that dwarf2, stabs, ... will each @@ -42,17 +42,17 @@ struct regcache; /* A generic base address. */ -typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame, +typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *this_frame, void **this_base_cache); /* The base address of the frame's local variables. */ -typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame, +typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *this_frame, void **this_base_cache); /* The base address of the frame's arguments / parameters. */ -typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame, +typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *this_frame, void **this_base_cache); struct frame_base @@ -65,10 +65,10 @@ struct frame_base frame_this_args_ftype *this_args; }; -/* Given the NEXT frame, return the frame base methods for THIS frame, +/* Given THIS frame, return the frame base methods for THIS frame, or NULL if it can't handle THIS frame. */ -typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *next_frame); +typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *this_frame); /* Append a frame base sniffer to the list. The sniffers are polled in the order that they are appended. */ @@ -86,6 +86,6 @@ extern void frame_base_set_default (struct gdbarch *gdbarch, /* Iterate through the list of frame base handlers until one returns an implementation. */ -extern const struct frame_base *frame_base_find_by_frame (struct frame_info *next_frame); +extern const struct frame_base *frame_base_find_by_frame (struct frame_info *this_frame); #endif diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index 3a2cb7a1f7..7384259433 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -20,15 +20,17 @@ #include "defs.h" #include "frame.h" #include "frame-unwind.h" -#include "gdb_assert.h" #include "dummy-frame.h" +#include "value.h" +#include "regcache.h" + +#include "gdb_assert.h" #include "gdb_obstack.h" static struct gdbarch_data *frame_unwind_data; struct frame_unwind_table_entry { - frame_unwind_sniffer_ftype *sniffer; const struct frame_unwind *unwinder; struct frame_unwind_table_entry *next; }; @@ -54,19 +56,6 @@ frame_unwind_init (struct obstack *obstack) return table; } -void -frame_unwind_append_sniffer (struct gdbarch *gdbarch, - frame_unwind_sniffer_ftype *sniffer) -{ - struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); - struct frame_unwind_table_entry **ip; - - /* Find the end of the list and insert the new entry there. */ - for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next); - (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry); - (*ip)->sniffer = sniffer; -} - void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch, const struct frame_unwind *unwinder) @@ -81,32 +70,123 @@ frame_unwind_prepend_unwinder (struct gdbarch *gdbarch, (*table->osabi_head) = entry; } +void +frame_unwind_append_unwinder (struct gdbarch *gdbarch, + const struct frame_unwind *unwinder) +{ + struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); + struct frame_unwind_table_entry **ip; + + /* Find the end of the list and insert the new entry there. */ + for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next); + (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry); + (*ip)->unwinder = unwinder; +} + const struct frame_unwind * -frame_unwind_find_by_frame (struct frame_info *next_frame, void **this_cache) +frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache) { int i; - struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); struct frame_unwind_table_entry *entry; + struct cleanup *old_cleanup; for (entry = table->list; entry != NULL; entry = entry->next) { - if (entry->sniffer != NULL) - { - const struct frame_unwind *desc = NULL; - desc = entry->sniffer (next_frame); - if (desc != NULL) - return desc; - } - if (entry->unwinder != NULL) + struct cleanup *old_cleanup; + + old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder); + if (entry->unwinder->sniffer (entry->unwinder, this_frame, + this_cache)) { - if (entry->unwinder->sniffer (entry->unwinder, next_frame, - this_cache)) - return entry->unwinder; + discard_cleanups (old_cleanup); + return entry->unwinder; } + do_cleanups (old_cleanup); } internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed")); } +/* A default frame sniffer which always accepts the frame. Used by + fallback prologue unwinders. */ + +int +default_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + return 1; +} + +/* Helper functions for value-based register unwinding. These return + a (possibly lazy) value of the appropriate type. */ + +/* Return a value which indicates that FRAME did not save REGNUM. */ + +struct value * +frame_unwind_got_optimized (struct frame_info *frame, int regnum) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct value *reg_val; + + reg_val = value_zero (register_type (gdbarch, regnum), not_lval); + set_value_optimized_out (reg_val, 1); + return reg_val; +} + +/* Return a value which indicates that FRAME copied REGNUM into + register NEW_REGNUM. */ + +struct value * +frame_unwind_got_register (struct frame_info *frame, int regnum, int new_regnum) +{ + return value_of_register_lazy (frame, new_regnum); +} + +/* Return a value which indicates that FRAME saved REGNUM in memory at + ADDR. */ + +struct value * +frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + + return value_at_lazy (register_type (gdbarch, regnum), addr); +} + +/* Return a value which indicates that FRAME's saved version of + REGNUM has a known constant (computed) value of VAL. */ + +struct value * +frame_unwind_got_constant (struct frame_info *frame, int regnum, + ULONGEST val) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct value *reg_val; + + reg_val = value_zero (register_type (gdbarch, regnum), not_lval); + store_unsigned_integer (value_contents_writeable (reg_val), + register_size (gdbarch, regnum), val); + return reg_val; +} + +/* Return a value which indicates that FRAME's saved version of REGNUM + has a known constant (computed) value of ADDR. Convert the + CORE_ADDR to a target address if necessary. */ + +struct value * +frame_unwind_got_address (struct frame_info *frame, int regnum, + CORE_ADDR addr) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct value *reg_val; + + reg_val = value_zero (register_type (gdbarch, regnum), not_lval); + pack_long (value_contents_writeable (reg_val), + register_type (gdbarch, regnum), addr); + return reg_val; +} + extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */ void diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h index 8140a80130..9ffafffb26 100644 --- a/gdb/frame-unwind.h +++ b/gdb/frame-unwind.h @@ -26,6 +26,7 @@ struct frame_id; struct frame_unwind; struct gdbarch; struct regcache; +struct value; #include "frame.h" /* For enum frame_type. */ @@ -41,17 +42,24 @@ struct regcache; as where this frame's prologue stores the previous frame's registers. */ -/* Given the NEXT frame, take a wiff of THIS frame's registers (namely +/* Given THIS frame, take a whiff of its registers (namely the PC and attributes) and if SELF is the applicable unwinder, return non-zero. Possibly also initialize THIS_PROLOGUE_CACHE. */ typedef int (frame_sniffer_ftype) (const struct frame_unwind *self, - struct frame_info *next_frame, + struct frame_info *this_frame, void **this_prologue_cache); +/* A default frame sniffer which always accepts the frame. Used by + fallback prologue unwinders. */ + +int default_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache); + /* Assuming the frame chain: (outer) prev <-> this <-> next (inner); - use the NEXT frame, and its register unwind method, to determine - the frame ID of THIS frame. + use THIS frame, and through it the NEXT frame's register unwind + method, to determine the frame ID of THIS frame. A frame ID provides an invariant that can be used to re-identify an instance of a frame. It is a combination of the frame's `base' and @@ -72,14 +80,14 @@ typedef int (frame_sniffer_ftype) (const struct frame_unwind *self, with the other unwind methods. Memory for that cache should be allocated using FRAME_OBSTACK_ZALLOC(). */ -typedef void (frame_this_id_ftype) (struct frame_info *next_frame, +typedef void (frame_this_id_ftype) (struct frame_info *this_frame, void **this_prologue_cache, struct frame_id *this_id); /* Assuming the frame chain: (outer) prev <-> this <-> next (inner); - use the NEXT frame, and its register unwind method, to unwind THIS - frame's registers (returning the value of the specified register - REGNUM in the previous frame). + use THIS frame, and implicitly the NEXT frame's register unwind + method, to unwind THIS frame's registers (returning the value of + the specified register REGNUM in the previous frame). Traditionally, THIS frame's registers were unwound by examining THIS frame's function's prologue and identifying which registers @@ -91,37 +99,22 @@ typedef void (frame_this_id_ftype) (struct frame_info *next_frame, register in the previous frame is found in memory at SP+12, and THIS frame's SP can be obtained by unwinding the NEXT frame's SP. - Why not pass in THIS_FRAME? By passing in NEXT frame and THIS - cache, the supplied parameters are consistent with the sibling - function THIS_ID. + This function takes THIS_FRAME as an argument. It can find the + values of registers in THIS frame by calling get_frame_register + (THIS_FRAME), and reinvoke itself to find other registers in the + PREVIOUS frame by calling frame_unwind_register (THIS_FRAME). - Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''? - Won't the call frame_register (THIS_FRAME) be faster? Well, - ignoring the possability that the previous frame does not yet - exist, the ``frame_register (FRAME)'' function is expanded to - ``frame_register_unwind (get_next_frame (FRAME)'' and hence that - call will expand to ``frame_register_unwind (get_next_frame - (get_prev_frame (NEXT_FRAME)))''. Might as well call - ``frame_register_unwind (NEXT_FRAME)'' directly. + The result is a GDB value object describing the register value. It + may be a lazy reference to memory, a lazy reference to the value of + a register in THIS frame, or a non-lvalue. THIS_PROLOGUE_CACHE can be used to share any prolog analysis data with the other unwind methods. Memory for that cache should be allocated using FRAME_OBSTACK_ZALLOC(). */ -typedef void (frame_prev_register_ftype) (struct frame_info *next_frame, - void **this_prologue_cache, - int prev_regnum, - int *optimized, - enum lval_type * lvalp, - CORE_ADDR *addrp, - int *realnump, gdb_byte *valuep); - -/* Assuming the frame chain: (outer) prev <-> this <-> next (inner); - use the NEXT frame, and its register unwind method, to return the PREV - frame's program-counter. */ - -typedef CORE_ADDR (frame_prev_pc_ftype) (struct frame_info *next_frame, - void **this_prologue_cache); +typedef struct value * (frame_prev_register_ftype) + (struct frame_info *this_frame, void **this_prologue_cache, + int regnum); /* Deallocate extra memory associated with the frame cache if any. */ @@ -139,7 +132,6 @@ struct frame_unwind frame_prev_register_ftype *prev_register; const struct frame_data *unwind_data; frame_sniffer_ftype *sniffer; - frame_prev_pc_ftype *prev_pc; frame_dealloc_cache_ftype *dealloc_cache; }; @@ -152,23 +144,50 @@ struct frame_unwind extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch, const struct frame_unwind *unwinder); -/* Given the NEXT frame, take a wiff of THIS frame's registers (namely - the PC and attributes) and if it is the applicable unwinder return - the unwind methods, or NULL if it is not. */ - -typedef const struct frame_unwind *(frame_unwind_sniffer_ftype) (struct frame_info *next_frame); - /* Add a frame sniffer to the list. The predicates are polled in the order that they are appended. The initial list contains the dummy frame sniffer. */ -extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch, - frame_unwind_sniffer_ftype *sniffer); +extern void frame_unwind_append_unwinder (struct gdbarch *gdbarch, + const struct frame_unwind *unwinder); -/* Iterate through the next frame's sniffers until one returns with an +/* Iterate through sniffers for THIS frame until one returns with an unwinder implementation. Possibly initialize THIS_CACHE. */ -extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame, +extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache); +/* Helper functions for value-based register unwinding. These return + a (possibly lazy) value of the appropriate type. */ + +/* Return a value which indicates that FRAME did not save REGNUM. */ + +struct value *frame_unwind_got_optimized (struct frame_info *frame, + int regnum); + +/* Return a value which indicates that FRAME copied REGNUM into + register NEW_REGNUM. */ + +struct value *frame_unwind_got_register (struct frame_info *frame, int regnum, + int new_regnum); + +/* Return a value which indicates that FRAME saved REGNUM in memory at + ADDR. */ + +struct value *frame_unwind_got_memory (struct frame_info *frame, int regnum, + CORE_ADDR addr); + +/* Return a value which indicates that FRAME's saved version of + REGNUM has a known constant (computed) value of VAL. */ + +struct value *frame_unwind_got_constant (struct frame_info *frame, int regnum, + ULONGEST val); + +/* Return a value which indicates that FRAME's saved version of REGNUM + has a known constant (computed) value of ADDR. Convert the + CORE_ADDR to a target address if necessary. */ + +struct value *frame_unwind_got_address (struct frame_info *frame, int regnum, + CORE_ADDR addr); + #endif diff --git a/gdb/frame.c b/gdb/frame.c index 9434ce79d6..f59cbebac7 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -113,7 +113,7 @@ struct frame_info /* Flag to control debugging. */ -static int frame_debug; +int frame_debug; static void show_frame_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -255,10 +255,9 @@ get_frame_id (struct frame_info *fi) fi->level); /* Find the unwinder. */ if (fi->unwind == NULL) - fi->unwind = frame_unwind_find_by_frame (fi->next, - &fi->prologue_cache); + fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); /* Find THIS frame's ID. */ - fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value); + fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); fi->this_id.p = 1; if (frame_debug) { @@ -427,15 +426,7 @@ frame_pc_unwind (struct frame_info *this_frame) if (!this_frame->prev_pc.p) { CORE_ADDR pc; - if (this_frame->unwind == NULL) - this_frame->unwind - = frame_unwind_find_by_frame (this_frame->next, - &this_frame->prologue_cache); - if (this_frame->unwind->prev_pc != NULL) - /* A per-frame unwinder, prefer it. */ - pc = this_frame->unwind->prev_pc (this_frame->next, - &this_frame->prologue_cache); - else if (gdbarch_unwind_pc_p (get_frame_arch (this_frame))) + if (gdbarch_unwind_pc_p (get_frame_arch (this_frame))) { /* The right way. The `pure' way. The one true way. This method depends solely on the register-unwind code to @@ -495,8 +486,7 @@ get_frame_func (struct frame_info *fi) static int do_frame_register_read (void *src, int regnum, gdb_byte *buf) { - frame_register_read (src, regnum, buf); - return 1; + return frame_register_read (src, regnum, buf); } struct regcache * @@ -552,15 +542,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, int *optimizedp, enum lval_type *lvalp, CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) { - struct frame_unwind_cache *cache; - - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "\ -{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ", - frame->level, regnum, - frame_map_regnum_to_name (frame, regnum)); - } + struct value *value; /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates that the value proper does not need to be fetched. */ @@ -570,43 +552,23 @@ frame_register_unwind (struct frame_info *frame, int regnum, gdb_assert (realnump != NULL); /* gdb_assert (bufferp != NULL); */ - /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame - is broken. There is always a frame. If there, for some reason, - isn't a frame, there is some pretty busted code as it should have - detected the problem before calling here. */ - gdb_assert (frame != NULL); + value = frame_unwind_register_value (frame, regnum); - /* Find the unwinder. */ - if (frame->unwind == NULL) - frame->unwind = frame_unwind_find_by_frame (frame->next, - &frame->prologue_cache); + gdb_assert (value != NULL); - /* Ask this frame to unwind its register. See comment in - "frame-unwind.h" for why NEXT frame and this unwind cache are - passed in. */ - frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + *optimizedp = value_optimized_out (value); + *lvalp = VALUE_LVAL (value); + *addrp = VALUE_ADDRESS (value); + *realnump = VALUE_REGNUM (value); - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "->"); - fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp)); - fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp)); - fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp))); - fprintf_unfiltered (gdb_stdlog, " *bufferp="); - if (bufferp == NULL) - fprintf_unfiltered (gdb_stdlog, ""); - else - { - int i; - const unsigned char *buf = bufferp; - fprintf_unfiltered (gdb_stdlog, "["); - for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++) - fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); - fprintf_unfiltered (gdb_stdlog, "]"); - } - fprintf_unfiltered (gdb_stdlog, " }\n"); - } + if (bufferp) + memcpy (bufferp, value_contents_all (value), + TYPE_LENGTH (value_type (value))); + + /* Dispose of the new value. This prevents watchpoints from + trying to watch the saved frame pointer. */ + release_value (value); + value_free (value); } void @@ -647,6 +609,71 @@ get_frame_register (struct frame_info *frame, frame_unwind_register (frame->next, regnum, buf); } +struct value * +frame_unwind_register_value (struct frame_info *frame, int regnum) +{ + struct value *value; + + gdb_assert (frame != NULL); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "\ +{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ", + frame->level, regnum, + frame_map_regnum_to_name (frame, regnum)); + } + + /* Find the unwinder. */ + if (frame->unwind == NULL) + frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache); + + /* Ask this frame to unwind its register. */ + value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "->"); + if (value_optimized_out (value)) + fprintf_unfiltered (gdb_stdlog, " optimized out"); + else + { + if (VALUE_LVAL (value) == lval_register) + fprintf_unfiltered (gdb_stdlog, " register=%d", + VALUE_REGNUM (value)); + else if (VALUE_LVAL (value) == lval_memory) + fprintf_unfiltered (gdb_stdlog, " address=0x%s", + paddr_nz (VALUE_ADDRESS (value))); + else + fprintf_unfiltered (gdb_stdlog, " computed"); + + if (value_lazy (value)) + fprintf_unfiltered (gdb_stdlog, " lazy"); + else + { + int i; + const gdb_byte *buf = value_contents (value); + + fprintf_unfiltered (gdb_stdlog, " bytes="); + fprintf_unfiltered (gdb_stdlog, "["); + for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++) + fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); + fprintf_unfiltered (gdb_stdlog, "]"); + } + } + + fprintf_unfiltered (gdb_stdlog, " }\n"); + } + + return value; +} + +struct value * +get_frame_register_value (struct frame_info *frame, int regnum) +{ + return frame_unwind_register_value (frame->next, regnum); +} + LONGEST frame_unwind_register_signed (struct frame_info *frame, int regnum) { @@ -1022,7 +1049,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) /* Select/initialize both the unwind function and the frame's type based on the PC. */ - fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache); + fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); fi->this_id.p = 1; deprecated_update_frame_base_hack (fi, addr); @@ -1569,8 +1596,8 @@ get_frame_base_address (struct frame_info *fi) /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - return fi->base->this_base (fi->next, &fi->prologue_cache); - return fi->base->this_base (fi->next, &fi->base_cache); + return fi->base->this_base (fi, &fi->prologue_cache); + return fi->base->this_base (fi, &fi->base_cache); } CORE_ADDR @@ -1585,10 +1612,8 @@ get_frame_locals_address (struct frame_info *fi) /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - cache = &fi->prologue_cache; - else - cache = &fi->base_cache; - return fi->base->this_locals (fi->next, cache); + return fi->base->this_locals (fi, &fi->prologue_cache); + return fi->base->this_locals (fi, &fi->base_cache); } CORE_ADDR @@ -1603,10 +1628,8 @@ get_frame_args_address (struct frame_info *fi) /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - cache = &fi->prologue_cache; - else - cache = &fi->base_cache; - return fi->base->this_args (fi->next, cache); + return fi->base->this_args (fi, &fi->prologue_cache); + return fi->base->this_args (fi, &fi->base_cache); } /* Level of the selected frame: 0 for innermost, 1 for its caller, ... @@ -1627,8 +1650,7 @@ get_frame_type (struct frame_info *frame) if (frame->unwind == NULL) /* Initialize the frame's unwinder because that's what provides the frame's type. */ - frame->unwind = frame_unwind_find_by_frame (frame->next, - &frame->prologue_cache); + frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache); return frame->unwind->type; } @@ -1769,6 +1791,50 @@ frame_stop_reason_string (enum unwind_stop_reason reason) } } +/* Clean up after a failed (wrong unwinder) attempt to unwind past + FRAME. */ + +static void +frame_cleanup_after_sniffer (void *arg) +{ + struct frame_info *frame = arg; + + /* The sniffer should not allocate a prologue cache if it did not + match this frame. */ + gdb_assert (frame->prologue_cache == NULL); + + /* No sniffer should extend the frame chain; sniff based on what is + already certain. */ + gdb_assert (!frame->prev_p); + + /* The sniffer should not check the frame's ID; that's circular. */ + gdb_assert (!frame->this_id.p); + + /* Clear cached fields dependent on the unwinder. + + The previous PC is independent of the unwinder, but the previous + function is not (see frame_unwind_address_in_block). */ + frame->prev_func.p = 0; + frame->prev_func.addr = 0; + + /* Discard the unwinder last, so that we can easily find it if an assertion + in this function triggers. */ + frame->unwind = NULL; +} + +/* Set FRAME's unwinder temporarily, so that we can call a sniffer. + Return a cleanup which should be called if unwinding fails, and + discarded if it succeeds. */ + +struct cleanup * +frame_prepare_for_sniffer (struct frame_info *frame, + const struct frame_unwind *unwind) +{ + gdb_assert (frame->unwind == NULL); + frame->unwind = unwind; + return make_cleanup (frame_cleanup_after_sniffer, frame); +} + extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */ static struct cmd_list_element *set_backtrace_cmdlist; diff --git a/gdb/frame.h b/gdb/frame.h index 6d935965be..c1f9d7eea7 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -144,6 +144,10 @@ struct frame_id /* For convenience. All fields are zero. */ extern const struct frame_id null_frame_id; +/* Flag to control debugging. */ + +extern int frame_debug; + /* Construct a frame ID. The first parameter is the frame's constant stack address (typically the outer-bound), and the second the frame's constant code address (typically the entry point). @@ -460,13 +464,19 @@ extern void frame_register_unwind (struct frame_info *frame, int regnum, /* Fetch a register from this, or unwind a register from the next frame. Note that the get_frame methods are wrappers to frame->next->unwind. They all [potentially] throw an error if the - fetch fails. */ + fetch fails. The value methods never return NULL, but usually + do return a lazy value. */ extern void frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf); extern void get_frame_register (struct frame_info *frame, int regnum, gdb_byte *buf); +struct value *frame_unwind_register_value (struct frame_info *frame, + int regnum); +struct value *get_frame_register_value (struct frame_info *frame, + int regnum); + extern LONGEST frame_unwind_register_signed (struct frame_info *frame, int regnum); extern LONGEST get_frame_register_signed (struct frame_info *frame, @@ -666,6 +676,12 @@ extern void (*deprecated_selected_frame_level_changed_hook) (int); extern void return_command (char *, int); +/* Set FRAME's unwinder temporarily, so that we can call a sniffer. + Return a cleanup which should be called if unwinding fails, and + discarded if it succeeds. */ + +struct cleanup *frame_prepare_for_sniffer (struct frame_info *frame, + const struct frame_unwind *unwind); /* Notes (cagney/2002-11-27, drow/2003-09-06): diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index f63dcdc608..7984423286 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -162,7 +162,7 @@ struct gdbarch gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum; gdbarch_register_name_ftype *register_name; gdbarch_register_type_ftype *register_type; - gdbarch_unwind_dummy_id_ftype *unwind_dummy_id; + gdbarch_dummy_id_ftype *dummy_id; int deprecated_fp_regnum; gdbarch_push_dummy_call_ftype *push_dummy_call; int call_dummy_location; @@ -284,7 +284,7 @@ struct gdbarch startup_gdbarch = no_op_reg_to_regnum, /* dwarf2_reg_to_regnum */ 0, /* register_name */ 0, /* register_type */ - 0, /* unwind_dummy_id */ + 0, /* dummy_id */ -1, /* deprecated_fp_regnum */ 0, /* push_dummy_call */ 0, /* call_dummy_location */ @@ -522,7 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch) if (gdbarch->register_name == 0) fprintf_unfiltered (log, "\n\tregister_name"); /* Skip verify of register_type, has predicate */ - /* Skip verify of unwind_dummy_id, has predicate */ + /* Skip verify of dummy_id, has predicate */ /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */ /* Skip verify of push_dummy_call, has predicate */ /* Skip verify of call_dummy_location, invalid_p == 0 */ @@ -714,6 +714,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: double_format = %s\n", pformat (gdbarch->double_format)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_dummy_id_p() = %d\n", + gdbarch_dummy_id_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: dummy_id = <0x%lx>\n", + (long) gdbarch->dummy_id); fprintf_unfiltered (file, "gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n", (long) gdbarch->dwarf2_reg_to_regnum); @@ -978,12 +984,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: target_desc = %s\n", paddr_d ((long) gdbarch->target_desc)); - fprintf_unfiltered (file, - "gdbarch_dump: gdbarch_unwind_dummy_id_p() = %d\n", - gdbarch_unwind_dummy_id_p (gdbarch)); - fprintf_unfiltered (file, - "gdbarch_dump: unwind_dummy_id = <0x%lx>\n", - (long) gdbarch->unwind_dummy_id); fprintf_unfiltered (file, "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n", gdbarch_unwind_pc_p (gdbarch)); @@ -1646,27 +1646,27 @@ set_gdbarch_register_type (struct gdbarch *gdbarch, } int -gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch) +gdbarch_dummy_id_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); - return gdbarch->unwind_dummy_id != NULL; + return gdbarch->dummy_id != NULL; } struct frame_id -gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info) +gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) { gdb_assert (gdbarch != NULL); - gdb_assert (gdbarch->unwind_dummy_id != NULL); + gdb_assert (gdbarch->dummy_id != NULL); if (gdbarch_debug >= 2) - fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n"); - return gdbarch->unwind_dummy_id (gdbarch, info); + fprintf_unfiltered (gdb_stdlog, "gdbarch_dummy_id called\n"); + return gdbarch->dummy_id (gdbarch, this_frame); } void -set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, - gdbarch_unwind_dummy_id_ftype unwind_dummy_id) +set_gdbarch_dummy_id (struct gdbarch *gdbarch, + gdbarch_dummy_id_ftype dummy_id) { - gdbarch->unwind_dummy_id = unwind_dummy_id; + gdbarch->dummy_id = dummy_id; } int diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 220c2dda7c..e568993dc8 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register /* See gdbint.texinfo, and PUSH_DUMMY_CALL. */ -extern int gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch); +extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch); -typedef struct frame_id (gdbarch_unwind_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *info); -extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info); -extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id); +typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame); +extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame); +extern void set_gdbarch_dummy_id (struct gdbarch *gdbarch, gdbarch_dummy_id_ftype *dummy_id); -/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete +/* Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete deprecated_fp_regnum. */ extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 91d970e95c..e3efdc80b4 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:regnr::0 M:struct type *:register_type:int reg_nr:reg_nr # See gdbint.texinfo, and PUSH_DUMMY_CALL. -M:struct frame_id:unwind_dummy_id:struct frame_info *info:info -# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete +M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame +# Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete # deprecated_fp_regnum. v:int:deprecated_fp_regnum:::-1:-1::0 diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c index dd2064c9ba..ebde4dc372 100644 --- a/gdb/ia64-tdep.c +++ b/gdb/ia64-tdep.c @@ -2803,7 +2803,6 @@ static const struct frame_unwind ia64_libunwind_frame_unwind = ia64_libunwind_frame_prev_register, NULL, NULL, - NULL, libunwind_frame_dealloc_cache }; diff --git a/gdb/infcall.c b/gdb/infcall.c index ca4785e2e9..c065b59b42 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -462,7 +462,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) pushed) GDB won't be able to correctly perform back traces. If a target is having trouble with backtraces, first thing to do is add FRAME_ALIGN() to the architecture vector. If that - fails, try unwind_dummy_id(). + fails, try dummy_id(). If the ABI specifies a "Red Zone" (see the doco) the code below will quietly trash it. */ @@ -656,7 +656,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) ID so that the breakpoint code can correctly re-identify the dummy breakpoint. */ /* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL, - saved as the dummy-frame TOS, and used by unwind_dummy_id to form + saved as the dummy-frame TOS, and used by dummy_id to form the frame ID's stack address. */ dummy_id = frame_id_build (sp, bp_addr); @@ -671,7 +671,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) sal.section = find_pc_overlay (sal.pc); /* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by - unwind_dummy_id to form the frame ID's stack address. */ + dummy_id to form the frame ID's stack address. */ bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy); bpt->disposition = disp_del; } diff --git a/gdb/libunwind-frame.c b/gdb/libunwind-frame.c index c70c5516ac..223c3c052d 100644 --- a/gdb/libunwind-frame.c +++ b/gdb/libunwind-frame.c @@ -214,7 +214,6 @@ static const struct frame_unwind libunwind_frame_unwind = libunwind_frame_prev_register, NULL, NULL, - NULL, libunwind_frame_dealloc_cache }; diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c index ccf0359142..4ad3a4b07b 100644 --- a/gdb/sentinel-frame.c +++ b/gdb/sentinel-frame.c @@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *regcache) /* Here the register value is taken direct from the register cache. */ -static void -sentinel_frame_prev_register (struct frame_info *next_frame, +static struct value * +sentinel_frame_prev_register (struct frame_info *this_frame, void **this_prologue_cache, - int regnum, int *optimized, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, gdb_byte *bufferp) + int regnum) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct frame_unwind_cache *cache = *this_prologue_cache; - /* Describe the register's location. A reg-frame maps all registers - onto the corresponding hardware register. */ - *optimized = 0; - *lvalp = lval_register; - *addrp = 0; - *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); - } + struct value *value; + + /* Return the actual value. */ + value = allocate_value (register_type (gdbarch, regnum)); + VALUE_LVAL (value) = lval_register; + VALUE_REGNUM (value) = regnum; + VALUE_FRAME_ID (value) = get_frame_id (this_frame); + + /* 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, value_contents_raw (value)); + + return value; } static void -sentinel_frame_this_id (struct frame_info *next_frame, +sentinel_frame_this_id (struct frame_info *this_frame, void **this_prologue_cache, struct frame_id *this_id) { @@ -79,22 +76,11 @@ sentinel_frame_this_id (struct frame_info *next_frame, internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called")); } -static CORE_ADDR -sentinel_frame_prev_pc (struct frame_info *next_frame, - void **this_prologue_cache) -{ - struct gdbarch *gdbarch = get_frame_arch (next_frame); - return gdbarch_unwind_pc (gdbarch, next_frame); -} - const struct frame_unwind sentinel_frame_unwinder = { SENTINEL_FRAME, sentinel_frame_this_id, - sentinel_frame_prev_register, - NULL, /* unwind_data */ - NULL, /* sniffer */ - sentinel_frame_prev_pc, + sentinel_frame_prev_register }; const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder; diff --git a/gdb/valops.c b/gdb/valops.c index 7f9868cd39..d601974fba 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -622,24 +622,87 @@ value_fetch_lazy (struct value *val) } else if (VALUE_LVAL (val) == lval_register) { - struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (val)); - int regnum = VALUE_REGNUM (val); + struct frame_info *frame; + int regnum; struct type *type = check_typedef (value_type (val)); + struct value *new_val = val, *mark = value_mark (); - gdb_assert (frame != NULL); + /* Offsets are not supported here; lazy register values must + refer to the entire register. */ + gdb_assert (value_offset (val) == 0); - /* Convertible register routines are used for multi-register - values and for interpretation in different types (e.g. float - or int from a double register). Lazy register values should - have the register's natural type, so they do not apply. */ - gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), regnum, - type)); + while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) + { + frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); + regnum = VALUE_REGNUM (new_val); + + gdb_assert (frame != NULL); + + /* Convertible register routines are used for multi-register + values and for interpretation in different types + (e.g. float or int from a double register). Lazy + register values should have the register's natural type, + so they do not apply. */ + gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), + regnum, type)); + + new_val = get_frame_register_value (frame, regnum); + } - /* Get the data. */ - if (!get_frame_register_bytes (frame, regnum, value_offset (val), - TYPE_LENGTH (value_type (val)), - value_contents_raw (val))) + /* If it's still lazy (for instance, a saved register on the + stack), fetch it. */ + if (value_lazy (new_val)) + value_fetch_lazy (new_val); + + /* If the register was not saved, mark it unavailable. */ + if (value_optimized_out (new_val)) set_value_optimized_out (val, 1); + else + memcpy (value_contents_raw (val), value_contents (new_val), + TYPE_LENGTH (type)); + + if (frame_debug) + { + frame = frame_find_by_id (VALUE_FRAME_ID (val)); + regnum = VALUE_REGNUM (val); + + fprintf_unfiltered (gdb_stdlog, "\ +{ value_fetch_lazy (frame=%d,regnum=%d(%s),...) ", + frame_relative_level (frame), regnum, + frame_map_regnum_to_name (frame, regnum)); + + fprintf_unfiltered (gdb_stdlog, "->"); + if (value_optimized_out (new_val)) + fprintf_unfiltered (gdb_stdlog, " optimized out"); + else + { + int i; + const gdb_byte *buf = value_contents (new_val); + + if (VALUE_LVAL (new_val) == lval_register) + fprintf_unfiltered (gdb_stdlog, " register=%d", + VALUE_REGNUM (new_val)); + else if (VALUE_LVAL (new_val) == lval_memory) + fprintf_unfiltered (gdb_stdlog, " address=0x%s", + paddr_nz (VALUE_ADDRESS (new_val))); + else + fprintf_unfiltered (gdb_stdlog, " computed"); + + fprintf_unfiltered (gdb_stdlog, " bytes="); + fprintf_unfiltered (gdb_stdlog, "["); + for (i = 0; + i < register_size (get_frame_arch (frame), regnum); + i++) + fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); + fprintf_unfiltered (gdb_stdlog, "]"); + } + + fprintf_unfiltered (gdb_stdlog, " }\n"); + } + + /* Dispose of the intermediate values. This prevents + watchpoints from trying to watch the saved frame pointer. */ + value_free_to_mark (mark); } else internal_error (__FILE__, __LINE__, "Unexpected lazy value type."); -- 2.34.1