diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-03-06 19:21:30 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-03-06 19:21:30 +0000 |
commit | b51cddb805f0e4cf2d59678ebdfb88fc029eb1e7 (patch) | |
tree | e81656231d74f3c9705e59e6b91135a91f309634 | |
parent | ada25ff8b02cd70298e538164b415b2c14958a3b (diff) | |
download | gdb-b51cddb805f0e4cf2d59678ebdfb88fc029eb1e7.tar.gz |
2003-03-06 Andrew Cagney <cagney@redhat.com>
* gdbarch.sh (gdbarch_unwind_pc): New method.
* gdbarch.h, gdbarch.c: Regenerate.
* frame.c (frame_pc_unwind): Rewrite. Prefer gdbarch_unwind_pc,
but use read_pc and FRAME_SAVED_PC as fall backs.
(frame_saved_regs_pc_unwind): Delete function.
(trad_frame_unwinder): Update.
* frame-unwind.h (frame_unwind_pc_ftype): Delete declaration.
(struct frame_unwind): Update.
* dummy-frame.c (dummy_frame_pc_unwind): Delete function.
(dummy_frame_unwind): Update.
* sentinel-frame.c (sentinel_frame_pc_unwind): Delete function.
(sentinel_frame_unwinder): Update.
* d10v-tdep.c (d10v_frame_pc_unwind): Delete function.
(d10v_frame_unwind): Update.
(d10v_unwind_pc): New function.
(d10v_gdbarch_init): Set unwind_pc.
2003-03-05 Andrew Cagney <cagney@redhat.com>
* dummy-frame.c (dummy_frame_id_unwind): Abort if called.
(cached_find_dummy_frame): Add hack to obtain this thread's id
without calling id unwind.
* frame.h: Merge with mainline.
* d10v-tdep.c: Merge with mainline.
* frame.c: Merge with mainline.
-rw-r--r-- | gdb/ChangeLog | 28 | ||||
-rw-r--r-- | gdb/d10v-tdep.c | 137 | ||||
-rw-r--r-- | gdb/dummy-frame.c | 36 | ||||
-rw-r--r-- | gdb/frame-unwind.h | 21 | ||||
-rw-r--r-- | gdb/frame.c | 235 | ||||
-rw-r--r-- | gdb/frame.h | 10 | ||||
-rw-r--r-- | gdb/gdbarch.c | 37 | ||||
-rw-r--r-- | gdb/gdbarch.h | 8 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 2 | ||||
-rw-r--r-- | gdb/sentinel-frame.c | 12 |
10 files changed, 291 insertions, 235 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8ac3ae9487c..b2510c3a36d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2003-03-06 Andrew Cagney <cagney@redhat.com> + + * gdbarch.sh (gdbarch_unwind_pc): New method. + * gdbarch.h, gdbarch.c: Regenerate. + * frame.c (frame_pc_unwind): Rewrite. Prefer gdbarch_unwind_pc, + but use read_pc and FRAME_SAVED_PC as fall backs. + (frame_saved_regs_pc_unwind): Delete function. + (trad_frame_unwinder): Update. + * frame-unwind.h (frame_unwind_pc_ftype): Delete declaration. + (struct frame_unwind): Update. + * dummy-frame.c (dummy_frame_pc_unwind): Delete function. + (dummy_frame_unwind): Update. + * sentinel-frame.c (sentinel_frame_pc_unwind): Delete function. + (sentinel_frame_unwinder): Update. + * d10v-tdep.c (d10v_frame_pc_unwind): Delete function. + (d10v_frame_unwind): Update. + (d10v_unwind_pc): New function. + (d10v_gdbarch_init): Set unwind_pc. + +2003-03-05 Andrew Cagney <cagney@redhat.com> + + * dummy-frame.c (dummy_frame_id_unwind): Abort if called. + (cached_find_dummy_frame): Add hack to obtain this thread's id + without calling id unwind. + * frame.h: Merge with mainline. + * d10v-tdep.c: Merge with mainline. + * frame.c: Merge with mainline. + 2003-03-04 Andrew Cagney <cagney@redhat.com> * d10v-tdep.c (struct d10v_unwind_cache): Add field "r11_addr", diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c index 5cbdddcdce5..0fe222ec2fe 100644 --- a/gdb/d10v-tdep.c +++ b/gdb/d10v-tdep.c @@ -616,8 +616,11 @@ struct d10v_unwind_cache CORE_ADDR base; int size; CORE_ADDR *saved_regs; - LONGEST next_addr; - LONGEST r11_addr; + /* How far the SP and r11 (FP) have been offset from the start of + the stack frame (as defined by the previous frame's stack + pointer). */ + LONGEST sp_offset; + LONGEST r11_offset; int uses_frame; void **regs; }; @@ -632,8 +635,8 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, if ((op & 0x7E1F) == 0x6C1F) { n = (op & 0x1E0) >> 5; - info->next_addr -= 2; - info->saved_regs[n] = info->next_addr; + info->sp_offset -= 2; + info->saved_regs[n] = info->sp_offset; return 1; } @@ -641,9 +644,9 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, 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; + info->sp_offset -= 4; + info->saved_regs[n] = info->sp_offset; + info->saved_regs[n + 1] = info->sp_offset + 2; return 1; } @@ -653,7 +656,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, n = (op & 0x1E) >> 1; if (n == 0) n = 16; - info->next_addr -= n; + info->sp_offset -= n; return 1; } @@ -661,7 +664,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, if (op == 0x417E) { info->uses_frame = 1; - info->r11_addr = info->next_addr; + info->r11_offset = info->sp_offset; return 1; } @@ -669,7 +672,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, if ((op & 0x7E1F) == 0x6816) { n = (op & 0x1E0) >> 5; - info->saved_regs[n] = info->r11_addr; + info->saved_regs[n] = info->r11_offset; return 1; } @@ -681,7 +684,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, if ((op & 0x7E1F) == 0x681E) { n = (op & 0x1E0) >> 5; - info->saved_regs[n] = info->next_addr; + info->saved_regs[n] = info->sp_offset; return 1; } @@ -689,8 +692,8 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op, if ((op & 0x7E3F) == 0x3A1E) { n = (op & 0x1E0) >> 5; - info->saved_regs[n] = info->next_addr; - info->saved_regs[n + 1] = info->next_addr + 2; + info->saved_regs[n] = info->sp_offset; + info->saved_regs[n + 1] = info->sp_offset + 2; return 1; } @@ -708,8 +711,8 @@ d10v_frame_unwind_cache (struct frame_info *next_frame, void **this_cache) { CORE_ADDR pc; - ULONGEST sp; - ULONGEST base; + ULONGEST prev_sp; + ULONGEST this_base; unsigned long op; unsigned short op1, op2; int i; @@ -724,7 +727,7 @@ d10v_frame_unwind_cache (struct frame_info *next_frame, info->size = 0; - info->next_addr = 0; + info->sp_offset = 0; pc = get_pc_function_start (frame_pc_unwind (next_frame)); @@ -739,22 +742,22 @@ d10v_frame_unwind_cache (struct frame_info *next_frame, { /* add3 sp,sp,n */ short n = op & 0xFFFF; - info->next_addr += n; + info->sp_offset += 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; + info->saved_regs[n] = info->sp_offset + 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; + info->saved_regs[n] = info->sp_offset + offset; + info->saved_regs[n + 1] = info->sp_offset + offset + 2; } else break; @@ -779,52 +782,50 @@ d10v_frame_unwind_cache (struct frame_info *next_frame, pc += 4; } - info->size = -info->next_addr; + info->size = -info->sp_offset; - /* Compute the frame's base. */ + /* Compute the frame's base, and the previous frame's SP. */ if (info->uses_frame) { - /* The SP was moved into the FP. This indicates that a new - frame was created. Get THIS frame's FP value by unwinding it - from the next frame. */ - frame_unwind_unsigned_register (next_frame, FP_REGNUM, &base); + /* The SP was moved to the FP. This indicates that a new frame + was created. Get THIS frame's FP value by unwinding it from + the next frame. */ + frame_unwind_unsigned_register (next_frame, FP_REGNUM, &this_base); /* The FP points at the last saved register. Adjust the FP back to before the first saved register giving the SP. */ - sp = base + info->size; + prev_sp = this_base + info->size; } else if (info->saved_regs[SP_REGNUM]) { /* The SP was saved (which is very unusual), the frame base is just the PREV's frame's TOP-OF-STACK. */ - base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM], - register_size (current_gdbarch, - SP_REGNUM)); - sp = base; + this_base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM], + register_size (current_gdbarch, + SP_REGNUM)); + prev_sp = this_base; } else { /* Assume that the FP is this frame's SP but with that pushed stack space added back. */ - frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base); - sp = base + info->size; + frame_unwind_unsigned_register (next_frame, SP_REGNUM, &this_base); + prev_sp = this_base + info->size; } - info->base = d10v_make_daddr (base); - sp = d10v_make_daddr (sp); + info->base = d10v_make_daddr (this_base); + prev_sp = d10v_make_daddr (prev_sp); /* Adjust all the saved registers so that they contain addresses and not offsets. */ for (i = 0; i < NUM_REGS - 1; i++) - { - if (info->saved_regs[i]) - { - info->saved_regs[i] = (sp + info->saved_regs[i]); - } - } + if (info->saved_regs[i]) + { + info->saved_regs[i] = (prev_sp + info->saved_regs[i]); + } /* The SP_REGNUM is special. Instead of the address of the SP, the previous frame's SP value is saved. */ - info->saved_regs[SP_REGNUM] = sp; + info->saved_regs[SP_REGNUM] = prev_sp; return info; } @@ -1432,22 +1433,12 @@ display_trace (int low, int high) } } - static CORE_ADDR -d10v_frame_pc_unwind (struct frame_info *next_frame, - void **this_cache) +d10v_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - /* FIXME: This shouldn't be needed. Instead single per-architecture - method should be called for all frames. */ - CORE_ADDR lr; - struct d10v_unwind_cache *info - = d10v_frame_unwind_cache (next_frame, this_cache); - void *buffer = alloca (max_register_size (current_gdbarch)); - saved_regs_unwind (next_frame, info->saved_regs, LR_REGNUM, buffer); - lr = extract_unsigned_integer (buffer, register_size (current_gdbarch, - LR_REGNUM)); - return d10v_make_iaddr (lr); - + ULONGEST pc; + frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc); + return d10v_make_iaddr (pc); } /* Given the next frame, determine the address of this function's @@ -1587,18 +1578,6 @@ d10v_frame_register_unwind (struct frame_info *next_frame, lvalp, addrp, realnump, bufferp); } - -static struct frame_id -d10v_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - ULONGEST base; - struct frame_id id; - id.pc = frame_pc_unwind (next_frame); - frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base); - id.base = d10v_make_daddr (base); - return id; -} - static void d10v_frame_pop (struct frame_info *next_frame, void **this_cache, struct regcache *regcache) @@ -1635,7 +1614,6 @@ d10v_frame_pop (struct frame_info *next_frame, void **this_cache, static struct frame_unwind d10v_frame_unwind = { d10v_frame_pop, - d10v_frame_pc_unwind, d10v_frame_id_unwind, d10v_frame_register_unwind }; @@ -1646,6 +1624,22 @@ d10v_frame_p (CORE_ADDR pc) return &d10v_frame_unwind; } +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +d10v_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + ULONGEST base; + struct frame_id id; + id.pc = frame_pc_unwind (next_frame); + frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base); + id.base = d10v_make_daddr (base); + return id; +} + static gdbarch_init_ftype d10v_gdbarch_init; static struct gdbarch * @@ -1782,9 +1776,14 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_print_registers_info (gdbarch, d10v_print_registers_info); frame_unwind_append_predicate (gdbarch, d10v_frame_p); + + /* Methods for saving / extracting a dummy frame's ID. */ set_gdbarch_unwind_dummy_id (gdbarch, d10v_unwind_dummy_id); set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos); + /* Return the unwound PC value. */ + set_gdbarch_unwind_pc (gdbarch, d10v_unwind_pc); + return gdbarch; } diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index 6812ed92d1e..a44f4510dbc 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -108,8 +108,13 @@ struct dummy_frame * cached_find_dummy_frame (struct frame_info *next_frame, void **this_cache) { if ((*this_cache) == NULL) - (*this_cache) = find_dummy_frame (frame_pc_unwind (next_frame), - frame_id_unwind (next_frame).base); + { + /* FIXME: hack to find the frame ID of this frame. Need to do + this better. */ + gdb_assert (next_frame->prev != NULL); + (*this_cache) = find_dummy_frame (frame_pc_unwind (next_frame), + next_frame->prev->frame); + } return (*this_cache); } @@ -371,23 +376,6 @@ dummy_frame_register_unwind (struct frame_info *next_frame, void **this_cache, } } -/* Assuming that FRAME is a dummy, return the resume address for the - previous frame. */ - -static CORE_ADDR -dummy_frame_pc_unwind (struct frame_info *next_frame, - void **this_cache) -{ - struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache); - /* Oops! In a dummy-frame but can't find the stack dummy. Pretend - that the frame doesn't unwind. Should this function instead - return a has-no-caller indication? */ - if (dummy == NULL) - return 0; - return dummy->pc; -} - - /* Assuming that FRAME is a dummy, return the ID of the calling frame (the frame that the dummy has the saved state of). */ @@ -396,6 +384,7 @@ dummy_frame_id_unwind (struct frame_info *next_frame, void **this_cache, struct frame_id *this_id) { +#if 0 struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache); /* Oops! In a dummy-frame but can't find the stack dummy. Pretend that the frame doesn't unwind. Should this function instead @@ -404,12 +393,19 @@ dummy_frame_id_unwind (struct frame_info *next_frame, (*this_id) = null_frame_id; else (*this_id) = dummy->id; +#else + /* FIXME - with all the frames shuffled by one, it becomes possible + to move the dummy frame unwind code to here. This is because, + unlike the mainline, this function is called when determining the + ID of the dummy, and not the ID of the dummy's caller. For the + moment, this function is never called. */ + internal_error (__FILE__, __LINE__, "dummy_frame_pc_unwind called"); +#endif } static struct frame_unwind dummy_frame_unwind = { dummy_frame_pop, - dummy_frame_pc_unwind, dummy_frame_id_unwind, dummy_frame_register_unwind }; diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h index 0ee0bc366d6..4d00b2f5e19 100644 --- a/gdb/frame-unwind.h +++ b/gdb/frame-unwind.h @@ -104,26 +104,6 @@ typedef void (frame_unwind_reg_ftype) (struct frame_info *next_frame, /* Assuming the frame chain: (outer) prev <-> this <-> next (inner); use the NEXT frame, and its register unwind method, to unwind THIS - frame's PC, returning the value of PC (the return address) in PREV - frame. - - Traditionally, THIS frame's PC was unwound by examining THIS - frame's function prolog and identifying where (in a register or on - the stack) that return address was saved. - - Please note that this per-frame method may be superseeded by an - architecture specific method that determines the unwound PC (aka - return address) using just the register unwind methods. - - THIS_CACHE can be used to share any prologue analysis data with the - other unwind methods. Memory for that cache should be allocated - using frame_obstack_zalloc(). */ - -typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info *next_frame, - void **this_cache); - -/* Assuming the frame chain: (outer) prev <-> this <-> next (inner); - use the NEXT frame, and its register unwind method, to unwind THIS frame's entire stack, writing PREV's frames register values into REGCACHE. @@ -151,7 +131,6 @@ struct frame_unwind /* Should an attribute indicating the frame's address-in-block go here? */ frame_unwind_pop_ftype *pop; - frame_unwind_pc_ftype *pc; frame_unwind_id_ftype *id; frame_unwind_reg_ftype *reg; }; diff --git a/gdb/frame.c b/gdb/frame.c index dd3cd68aad7..d61ec08ee8c 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -135,27 +135,54 @@ frame_find_by_id (struct frame_id id) } CORE_ADDR -frame_pc_unwind (struct frame_info *this_frame) +frame_pc_unwind (struct frame_info *next_frame) { - if (!this_frame->pc_unwind_cache_p) + if (!next_frame->pc_unwind_cache_p) { - this_frame->pc_unwind_cache - = this_frame->unwind->pc (this_frame->next, &this_frame->unwind_cache); - this_frame->pc_unwind_cache_p = 1; - } - return this_frame->pc_unwind_cache; -} - -struct frame_id -frame_id_unwind (struct frame_info *this_frame) -{ - if (!this_frame->id_unwind_cache_p) - { - this_frame->unwind->id (this_frame->next, &this_frame->unwind_cache, - &this_frame->id_unwind_cache); - this_frame->id_unwind_cache_p = 1; + CORE_ADDR pc; + if (gdbarch_unwind_pc_p (current_gdbarch)) + { + /* The right way. The `pure' way. The one true way. This + method depends solely on the register-unwind code to + determine the value of registers in THIS frame, and hence + the value of this frame's PC (resume address). A typical + implementation is no more than: + + frame_unwind_register (next_frame, ISA_PC_REGNUM, buf); + return extract_address (buf, size of ISA_PC_REGNUM); + + Note: this method is very heavily dependent on a correct + register-unwind implementation, it pays to fix that + method first; this method is frame type agnostic, since + it only deals with register values, it works with any + frame. This is all in stark contrast to the old + FRAME_SAVED_PC which would try to directly handle all the + different ways that a PC could be unwound. */ + pc = gdbarch_unwind_pc (current_gdbarch, next_frame); + } + else if (next_frame->level < 0) + { + /* FIXME: cagney/2003-03-06: Old code and and a sentinel + frame. Do like was always done. Fetch the PC's value + direct from the global registers array (via read_pc). + This assumes that this frame belongs to the current + global register cache. The assumption is dangerous. */ + pc = read_pc (); + } + else if (FRAME_SAVED_PC_P ()) + { + /* FIXME: cagney/2003-03-06: Old code, but not a sentinel + frame. Do like was always done. Note that this method, + unlike unwind_pc(), tries to handle all the different + frame cases directly. It fails. */ + pc = FRAME_SAVED_PC (next_frame); + } + else + internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method"); + next_frame->pc_unwind_cache = pc; + next_frame->pc_unwind_cache_p = 1; } - return this_frame->id_unwind_cache; + return next_frame->pc_unwind_cache; } void @@ -682,13 +709,6 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, bufferp); } -static CORE_ADDR -frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache) -{ - gdb_assert (FRAME_SAVED_PC_P ()); - return FRAME_SAVED_PC (frame); -} - static void frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, struct frame_id *id) @@ -760,7 +780,6 @@ frame_saved_regs_pop (struct frame_info *fi, void **cache, const struct frame_unwind trad_frame_unwinder = { frame_saved_regs_pop, - frame_saved_regs_pc_unwind, frame_saved_regs_id_unwind, frame_saved_regs_register_unwind }; @@ -1346,83 +1365,87 @@ get_prev_frame (struct frame_info *next_frame) prev_frame->pc); /* Find the prev's frame's ID. */ - { - switch (prev_frame->type) - { - case DUMMY_FRAME: - /* A dummy doesn't have anything resembling either a sane - frame or PC. The PC is sitting in the entry code and the - stack, which has nothing to do with that entry address, is - a down right mess. Trying to use the standard frame ID - unwind code to get the previous frame ID is just asking for - trouble. */ - if (gdbarch_unwind_dummy_id_p (current_gdbarch)) - { - /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS, - previously saved the dummy ID that is being obtained - here. Things only work if the two match. */ - gdb_assert (SAVE_DUMMY_FRAME_TOS_P ()); - /* Use an architecture specific method to extract the - prev's dummy ID from the next frame. Note that this - method typically uses frame_register_unwind to obtain - register values needed to determine the dummy ID. */ - next_frame->id_unwind_cache = - gdbarch_unwind_dummy_id (current_gdbarch, next_frame); - } - else if (next_frame->level == 0) - { - /* We're `unwinding' the sentinel frame. Just fake up the - ID the same way that the traditional hacks did it. */ - next_frame->id_unwind_cache.pc = read_pc (); - next_frame->id_unwind_cache.pc = read_fp (); - } - else - { - /* Outch! We're not on the innermost frame yet we're - trying to unwind to a dummy. The architecture must - provide the unwind_dummy_id() method. */ - internal_error (__FILE__, __LINE__, + switch (prev_frame->type) + { + case DUMMY_FRAME: + /* When unwinding a normal frame, the stack structure is + determined by analyzing the frame's function's code (be it + using brute force prologue analysis, or the dwarf2 CFI). In + the case of a dummy frame, that simply isn't possible. The + The PC is either the program entry point, or some random + address on the stack. Trying to use that PC to apply + standard frame ID unwind techniques is just asking for + trouble. */ + if (gdbarch_unwind_dummy_id_p (current_gdbarch)) + { + /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS, + previously saved the dummy frame's ID. Things only work + if the two return the same value. */ + gdb_assert (SAVE_DUMMY_FRAME_TOS_P ()); + /* 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. */ + prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, + next_frame); + } + else if (next_frame->level < 0) + { + /* We're unwinding a sentinel frame, the PC of which is + pointing at a stack dummy. Fake up the dummy frame's ID + using the same sequence as is found a traditional + unwinder. Once all architectures supply the + unwind_dummy_id method, this code can go away. */ + prev_frame->id.base = read_fp (); + prev_frame->id.pc = read_pc (); + } + else + { + /* Outch! We're not on the innermost frame yet we're trying + to unwind to a dummy. The architecture must provide the + unwind_dummy_id() method. Abandon the unwind process but + only after first warning the user. */ + internal_warning (__FILE__, __LINE__, "Missing unwind_dummy_id architecture method"); - } - break; - case NORMAL_FRAME: - case SIGTRAMP_FRAME: - prev_frame->unwind->id (next_frame, &prev_frame->unwind_cache, - &next_frame->id_unwind_cache); - /* Check that the unwound ID is valid. */ - if (!frame_id_p (next_frame->id_unwind_cache)) - { - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - unwound frame ID invalid\n"); - return NULL; - } - /* Check that the new frame isn't inner to (younger, below, - next) the old frame. If that happens the frame unwind is - going backwards. */ - /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since - that doesn't have a valid frame ID. Should instead set the - sentinel frame's frame ID to a `sentinel'. Leave it until - after the switch to storing the frame ID, instead of the - frame base, in the frame object. */ - if (next_frame->level >= 0 - && frame_id_inner (next_frame->id_unwind_cache, - get_frame_id (next_frame))) - error ("Unwound frame inner-to selected frame (corrupt stack?)"); - /* Note that, due to frameless functions, the stronger test of - the new frame being outer to the old frame can't be used - - frameless functions differ by only their PC value. */ - break; - default: - internal_error (__FILE__, __LINE__, "bad switch"); - } - /* FIXME: cagney/2002-12-18: Instead of this hack, the frame ID - should be directly stored in the `struct frame_info'. - Unfortunatly, GDB isn't quite ready for this, need to get HP/UX - multi-arch and make 'struct frame_info' opaque. */ - next_frame->id_unwind_cache_p = 1; - prev_frame->frame = next_frame->id_unwind_cache.base; - } + return NULL; + } + break; + case NORMAL_FRAME: + case SIGTRAMP_FRAME: + prev_frame->unwind->id (next_frame, &prev_frame->unwind_cache, + &prev_frame->id); + /* Check that the unwound ID is valid. */ + if (!frame_id_p (prev_frame->id)) + { + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "Outermost frame - unwound frame ID invalid\n"); + return NULL; + } + /* Check that the new frame isn't inner to (younger, below, + next) the old frame. If that happens the frame unwind is + going backwards. */ + /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since + that doesn't have a valid frame ID. Should instead set the + sentinel frame's frame ID to a `sentinel'. Leave it until + after the switch to storing the frame ID, instead of the + frame base, in the frame object. */ + if (next_frame->level >= 0 + && frame_id_inner (prev_frame->id, get_frame_id (next_frame))) + error ("Unwound frame inner-to selected frame (corrupt stack?)"); + /* Note that, due to frameless functions, the stronger test of + the new frame being outer to the old frame can't be used - + frameless functions differ by only their PC value. */ + break; + default: + internal_error (__FILE__, __LINE__, "bad switch"); + } + + /* FIXME: cagney/2002-12-18: Instead of this hack, should only store + the frame ID in PREV_FRAME. Unfortunatly, some architectures + (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at + the "struct frame_info" object directly. */ + prev_frame->frame = prev_frame->id.base; /* Link it in. */ next_frame->prev = prev_frame; @@ -1557,11 +1580,11 @@ void deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc) { /* See comment in "frame.h". */ - gdb_assert (frame->next != NULL); - /* Fix up this PC's value. */ frame->pc = pc; - /* While we're at it, also update the cache, in NEXT, that also - contains that value. */ + /* While we're at it, update this frame's cached PC value, found in + the next frame. Oh, for the day when "struct frame_info" is + opaque and this hack on hack can go. */ + gdb_assert (frame->next != NULL); frame->next->pc_unwind_cache = pc; frame->next->pc_unwind_cache_p = 1; } diff --git a/gdb/frame.h b/gdb/frame.h index bd20ba7aec1..18c4df4397f 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -310,10 +310,6 @@ extern const char *frame_map_regnum_to_name (int regnum); extern CORE_ADDR frame_pc_unwind (struct frame_info *frame); -/* Unwind the frame ID. Return an ID that uniquely identifies the - caller's frame. */ -extern struct frame_id frame_id_unwind (struct frame_info *frame); - /* Discard the specified frame. Restoring the registers to the state of the caller. */ extern void frame_pop (struct frame_info *frame); @@ -412,9 +408,9 @@ struct frame_info int pc_unwind_cache_p; CORE_ADDR pc_unwind_cache; - /* Cached copy of the previous frame's ID. */ - int id_unwind_cache_p; - struct frame_id id_unwind_cache; + /* This frame's ID. Note that the frame's ID, base and PC contain + redundant information. */ + struct frame_id id; /* Pointers to the next (down, inner, younger) and previous (up, outer, older) frame_info's in the frame cache. */ diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 636349c7be2..8b5a475375c 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -242,6 +242,7 @@ struct gdbarch gdbarch_frame_chain_ftype *frame_chain; gdbarch_frame_chain_valid_ftype *frame_chain_valid; gdbarch_frame_saved_pc_ftype *frame_saved_pc; + gdbarch_unwind_pc_ftype *unwind_pc; gdbarch_frame_args_address_ftype *frame_args_address; gdbarch_frame_locals_address_ftype *frame_locals_address; gdbarch_saved_pc_after_call_ftype *saved_pc_after_call; @@ -433,6 +434,7 @@ struct gdbarch startup_gdbarch = 0, 0, 0, + 0, generic_in_function_epilogue_p, construct_inferior_arguments, 0, @@ -759,6 +761,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of frame_chain, has predicate */ /* Skip verify of frame_chain_valid, has predicate */ /* Skip verify of frame_saved_pc, has predicate */ + /* Skip verify of unwind_pc, has predicate */ /* Skip verify of frame_args_address, invalid_p == 0 */ /* Skip verify of frame_locals_address, invalid_p == 0 */ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) @@ -2578,6 +2581,14 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: unwind_dummy_id = 0x%08lx\n", (long) current_gdbarch->unwind_dummy_id); + if (GDB_MULTI_ARCH) + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n", + gdbarch_unwind_pc_p (current_gdbarch)); + if (GDB_MULTI_ARCH) + fprintf_unfiltered (file, + "gdbarch_dump: unwind_pc = 0x%08lx\n", + (long) current_gdbarch->unwind_pc); #ifdef USE_STRUCT_CONVENTION fprintf_unfiltered (file, "gdbarch_dump: %s # %s\n", @@ -4845,6 +4856,32 @@ set_gdbarch_frame_saved_pc (struct gdbarch *gdbarch, gdbarch->frame_saved_pc = frame_saved_pc; } +int +gdbarch_unwind_pc_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->unwind_pc != 0; +} + +CORE_ADDR +gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + gdb_assert (gdbarch != NULL); + if (gdbarch->unwind_pc == 0) + internal_error (__FILE__, __LINE__, + "gdbarch: gdbarch_unwind_pc invalid"); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_pc called\n"); + return gdbarch->unwind_pc (gdbarch, next_frame); +} + +void +set_gdbarch_unwind_pc (struct gdbarch *gdbarch, + gdbarch_unwind_pc_ftype unwind_pc) +{ + gdbarch->unwind_pc = unwind_pc; +} + CORE_ADDR gdbarch_frame_args_address (struct gdbarch *gdbarch, struct frame_info *fi) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index b1cb72bd185..ee77461cf13 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -2230,6 +2230,8 @@ extern void set_gdbarch_frame_chain_valid (struct gdbarch *gdbarch, gdbarch_fram #endif #endif +/* NOTE: FRAME_SAVED_PC is replaced by UNWIND_PC */ + #if defined (FRAME_SAVED_PC) /* Legacy for systems yet to multi-arch FRAME_SAVED_PC */ #if !defined (FRAME_SAVED_PC_P) @@ -2267,6 +2269,12 @@ extern void set_gdbarch_frame_saved_pc (struct gdbarch *gdbarch, gdbarch_frame_s #endif #endif +extern int gdbarch_unwind_pc_p (struct gdbarch *gdbarch); + +typedef CORE_ADDR (gdbarch_unwind_pc_ftype) (struct gdbarch *gdbarch, struct frame_info *next_frame); +extern CORE_ADDR gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame); +extern void set_gdbarch_unwind_pc (struct gdbarch *gdbarch, gdbarch_unwind_pc_ftype *unwind_pc); + /* Default (function) for non- multi-arch platforms. */ #if (!GDB_MULTI_ARCH) && !defined (FRAME_ARGS_ADDRESS) #define FRAME_ARGS_ADDRESS(fi) (get_frame_base (fi)) diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index b367fda7b7f..8380a601820 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -591,7 +591,9 @@ v:2:FRAME_ARGS_SKIP:CORE_ADDR:frame_args_skip::::0:-1 f:2:FRAMELESS_FUNCTION_INVOCATION:int:frameless_function_invocation:struct frame_info *fi:fi:::generic_frameless_function_invocation_not::0 F:2:FRAME_CHAIN:CORE_ADDR:frame_chain:struct frame_info *frame:frame::0:0 F:2:FRAME_CHAIN_VALID:int:frame_chain_valid:CORE_ADDR chain, struct frame_info *thisframe:chain, thisframe::0:0 +# NOTE: FRAME_SAVED_PC is replaced by UNWIND_PC F:2:FRAME_SAVED_PC:CORE_ADDR:frame_saved_pc:struct frame_info *fi:fi::0:0 +M::UNWIND_PC:CORE_ADDR:unwind_pc:struct frame_info *next_frame:next_frame: f:2:FRAME_ARGS_ADDRESS:CORE_ADDR:frame_args_address:struct frame_info *fi:fi::0:get_frame_base::0 f:2:FRAME_LOCALS_ADDRESS:CORE_ADDR:frame_locals_address:struct frame_info *fi:fi::0:get_frame_base::0 f:2:SAVED_PC_AFTER_CALL:CORE_ADDR:saved_pc_after_call:struct frame_info *frame:frame::0:0 diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c index ef8113da4e4..046655f0687 100644 --- a/gdb/sentinel-frame.c +++ b/gdb/sentinel-frame.c @@ -76,17 +76,6 @@ sentinel_frame_register_unwind (struct frame_info *next_frame, } } -CORE_ADDR -sentinel_frame_pc_unwind (struct frame_info *next_frame, - void **this_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 *next_frame, void **this_cache, @@ -106,7 +95,6 @@ sentinel_frame_pop (struct frame_info *next_frame, const struct frame_unwind sentinel_frame_unwinder = { sentinel_frame_pop, - sentinel_frame_pc_unwind, sentinel_frame_id_unwind, sentinel_frame_register_unwind }; |