diff options
Diffstat (limited to 'gdb/frame-unwind.c')
-rw-r--r-- | gdb/frame-unwind.c | 136 |
1 files changed, 108 insertions, 28 deletions
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index 3a2cb7a..7384259 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; }; @@ -55,19 +57,6 @@ frame_unwind_init (struct obstack *obstack) } 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 |