| Index: gdb/frame.c
|
| diff --git a/gdb/frame.c b/gdb/frame.c
|
| index b7698733c2aea38d1a2b0c1329325980c5008521..6a8b5ae58bcf829f8632ecd13907c22029c5833a 100644
|
| --- a/gdb/frame.c
|
| +++ b/gdb/frame.c
|
| @@ -1,7 +1,6 @@
|
| /* Cache and manage frames for GDB, the GNU debugger.
|
|
|
| - Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2004,
|
| - 2007-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 1986-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -25,7 +24,7 @@
|
| #include "inferior.h" /* for inferior_ptid */
|
| #include "regcache.h"
|
| #include "gdb_assert.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include "user-regs.h"
|
| #include "gdb_obstack.h"
|
| #include "dummy-frame.h"
|
| @@ -43,10 +42,30 @@
|
| #include "gdbthread.h"
|
| #include "block.h"
|
| #include "inline-frame.h"
|
| -#include "tracepoint.h"
|
| +#include "tracepoint.h"
|
| +#include "hashtab.h"
|
| +#include "valprint.h"
|
|
|
| static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
|
| static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
|
| +static const char *frame_stop_reason_symbol_string (enum unwind_stop_reason reason);
|
| +
|
| +/* Status of some values cached in the frame_info object. */
|
| +
|
| +enum cached_copy_status
|
| +{
|
| + /* Value is unknown. */
|
| + CC_UNKNOWN,
|
| +
|
| + /* We have a value. */
|
| + CC_VALUE,
|
| +
|
| + /* Value was not saved. */
|
| + CC_NOT_SAVED,
|
| +
|
| + /* Value is unavailable. */
|
| + CC_UNAVAILABLE
|
| +};
|
|
|
| /* We keep a cache of stack frames, each of which is a "struct
|
| frame_info". The innermost one gets allocated (in
|
| @@ -94,7 +113,7 @@ struct frame_info
|
|
|
| /* Cached copy of the previous frame's resume address. */
|
| struct {
|
| - int p;
|
| + enum cached_copy_status status;
|
| CORE_ADDR value;
|
| } prev_pc;
|
|
|
| @@ -129,43 +148,120 @@ struct frame_info
|
| enum unwind_stop_reason stop_reason;
|
| };
|
|
|
| -/* A frame stash used to speed up frame lookups. */
|
| +/* A frame stash used to speed up frame lookups. Create a hash table
|
| + to stash frames previously accessed from the frame cache for
|
| + quicker subsequent retrieval. The hash table is emptied whenever
|
| + the frame cache is invalidated. */
|
| +
|
| +static htab_t frame_stash;
|
| +
|
| +/* Internal function to calculate a hash from the frame_id addresses,
|
| + using as many valid addresses as possible. Frames below level 0
|
| + are not stored in the hash table. */
|
| +
|
| +static hashval_t
|
| +frame_addr_hash (const void *ap)
|
| +{
|
| + const struct frame_info *frame = ap;
|
| + const struct frame_id f_id = frame->this_id.value;
|
| + hashval_t hash = 0;
|
| +
|
| + gdb_assert (f_id.stack_addr_p || f_id.code_addr_p
|
| + || f_id.special_addr_p);
|
| +
|
| + if (f_id.stack_addr_p)
|
| + hash = iterative_hash (&f_id.stack_addr,
|
| + sizeof (f_id.stack_addr), hash);
|
| + if (f_id.code_addr_p)
|
| + hash = iterative_hash (&f_id.code_addr,
|
| + sizeof (f_id.code_addr), hash);
|
| + if (f_id.special_addr_p)
|
| + hash = iterative_hash (&f_id.special_addr,
|
| + sizeof (f_id.special_addr), hash);
|
| +
|
| + return hash;
|
| +}
|
| +
|
| +/* Internal equality function for the hash table. This function
|
| + defers equality operations to frame_id_eq. */
|
| +
|
| +static int
|
| +frame_addr_hash_eq (const void *a, const void *b)
|
| +{
|
| + const struct frame_info *f_entry = a;
|
| + const struct frame_info *f_element = b;
|
|
|
| -/* We currently only stash one frame at a time, as this seems to be
|
| - sufficient for now. */
|
| -static struct frame_info *frame_stash = NULL;
|
| + return frame_id_eq (f_entry->this_id.value,
|
| + f_element->this_id.value);
|
| +}
|
|
|
| -/* Add the following FRAME to the frame stash. */
|
| +/* Internal function to create the frame_stash hash table. 100 seems
|
| + to be a good compromise to start the hash table at. */
|
|
|
| static void
|
| +frame_stash_create (void)
|
| +{
|
| + frame_stash = htab_create (100,
|
| + frame_addr_hash,
|
| + frame_addr_hash_eq,
|
| + NULL);
|
| +}
|
| +
|
| +/* Internal function to add a frame to the frame_stash hash table.
|
| + Returns false if a frame with the same ID was already stashed, true
|
| + otherwise. */
|
| +
|
| +static int
|
| frame_stash_add (struct frame_info *frame)
|
| {
|
| - frame_stash = frame;
|
| + struct frame_info **slot;
|
| +
|
| + /* Do not try to stash the sentinel frame. */
|
| + gdb_assert (frame->level >= 0);
|
| +
|
| + slot = (struct frame_info **) htab_find_slot (frame_stash,
|
| + frame,
|
| + INSERT);
|
| +
|
| + /* If we already have a frame in the stack with the same id, we
|
| + either have a stack cycle (corrupted stack?), or some bug
|
| + elsewhere in GDB. In any case, ignore the duplicate and return
|
| + an indication to the caller. */
|
| + if (*slot != NULL)
|
| + return 0;
|
| +
|
| + *slot = frame;
|
| + return 1;
|
| }
|
|
|
| -/* Search the frame stash for an entry with the given frame ID.
|
| - If found, return that frame. Otherwise return NULL. */
|
| +/* Internal function to search the frame stash for an entry with the
|
| + given frame ID. If found, return that frame. Otherwise return
|
| + NULL. */
|
|
|
| static struct frame_info *
|
| frame_stash_find (struct frame_id id)
|
| {
|
| - if (frame_stash && frame_id_eq (frame_stash->this_id.value, id))
|
| - return frame_stash;
|
| + struct frame_info dummy;
|
| + struct frame_info *frame;
|
|
|
| - return NULL;
|
| + dummy.this_id.value = id;
|
| + frame = htab_find (frame_stash, &dummy);
|
| + return frame;
|
| }
|
|
|
| -/* Invalidate the frame stash by removing all entries in it. */
|
| +/* Internal function to invalidate the frame stash by removing all
|
| + entries in it. This only occurs when the frame cache is
|
| + invalidated. */
|
|
|
| static void
|
| frame_stash_invalidate (void)
|
| {
|
| - frame_stash = NULL;
|
| + htab_empty (frame_stash);
|
| }
|
|
|
| /* Flag to control debugging. */
|
|
|
| -int frame_debug;
|
| +unsigned int frame_debug;
|
| static void
|
| show_frame_debug (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| @@ -196,7 +292,7 @@ show_backtrace_past_entry (struct ui_file *file, int from_tty,
|
| value);
|
| }
|
|
|
| -static int backtrace_limit = INT_MAX;
|
| +static unsigned int backtrace_limit = UINT_MAX;
|
| static void
|
| show_backtrace_limit (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| @@ -226,8 +322,8 @@ fprint_frame_id (struct ui_file *file, struct frame_id id)
|
| fprint_field (file, "code", id.code_addr_p, id.code_addr);
|
| fprintf_unfiltered (file, ",");
|
| fprint_field (file, "special", id.special_addr_p, id.special_addr);
|
| - if (id.inline_depth)
|
| - fprintf_unfiltered (file, ",inlined=%d", id.inline_depth);
|
| + if (id.artificial_depth)
|
| + fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
|
| fprintf_unfiltered (file, "}");
|
| }
|
|
|
| @@ -245,8 +341,8 @@ fprint_frame_type (struct ui_file *file, enum frame_type type)
|
| case INLINE_FRAME:
|
| fprintf_unfiltered (file, "INLINE_FRAME");
|
| return;
|
| - case SENTINEL_FRAME:
|
| - fprintf_unfiltered (file, "SENTINEL_FRAME");
|
| + case TAILCALL_FRAME:
|
| + fprintf_unfiltered (file, "TAILCALL_FRAME");
|
| return;
|
| case SIGTRAMP_FRAME:
|
| fprintf_unfiltered (file, "SIGTRAMP_FRAME");
|
| @@ -254,6 +350,9 @@ fprint_frame_type (struct ui_file *file, enum frame_type type)
|
| case ARCH_FRAME:
|
| fprintf_unfiltered (file, "ARCH_FRAME");
|
| return;
|
| + case SENTINEL_FRAME:
|
| + fprintf_unfiltered (file, "SENTINEL_FRAME");
|
| + return;
|
| default:
|
| fprintf_unfiltered (file, "<unknown type>");
|
| return;
|
| @@ -284,10 +383,15 @@ fprint_frame (struct ui_file *file, struct frame_info *fi)
|
| fprintf_unfiltered (file, "<unknown>");
|
| fprintf_unfiltered (file, ",");
|
| fprintf_unfiltered (file, "pc=");
|
| - if (fi->next != NULL && fi->next->prev_pc.p)
|
| - fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value));
|
| - else
|
| + if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN)
|
| fprintf_unfiltered (file, "<unknown>");
|
| + else if (fi->next->prev_pc.status == CC_VALUE)
|
| + fprintf_unfiltered (file, "%s",
|
| + hex_string (fi->next->prev_pc.value));
|
| + else if (fi->next->prev_pc.status == CC_NOT_SAVED)
|
| + val_print_not_saved (file);
|
| + else if (fi->next->prev_pc.status == CC_UNAVAILABLE)
|
| + val_print_unavailable (file);
|
| fprintf_unfiltered (file, ",");
|
| fprintf_unfiltered (file, "id=");
|
| if (fi->this_id.p)
|
| @@ -303,11 +407,12 @@ fprint_frame (struct ui_file *file, struct frame_info *fi)
|
| fprintf_unfiltered (file, "}");
|
| }
|
|
|
| -/* Given FRAME, return the enclosing normal frame for inlined
|
| - function frames. Otherwise return the original frame. */
|
| +/* Given FRAME, return the enclosing frame as found in real frames read-in from
|
| + inferior memory. Skip any previous frames which were made up by GDB.
|
| + Return the original frame if no immediate previous frames exist. */
|
|
|
| static struct frame_info *
|
| -skip_inlined_frames (struct frame_info *frame)
|
| +skip_artificial_frames (struct frame_info *frame)
|
| {
|
| while (get_frame_type (frame) == INLINE_FRAME
|
| || get_frame_type (frame) == TAILCALL_FRAME)
|
| @@ -316,6 +421,34 @@ skip_inlined_frames (struct frame_info *frame)
|
| return frame;
|
| }
|
|
|
| +/* Compute the frame's uniq ID that can be used to, later, re-find the
|
| + frame. */
|
| +
|
| +static void
|
| +compute_frame_id (struct frame_info *fi)
|
| +{
|
| + gdb_assert (!fi->this_id.p);
|
| +
|
| + if (frame_debug)
|
| + fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
|
| + fi->level);
|
| + /* Find the unwinder. */
|
| + if (fi->unwind == NULL)
|
| + frame_unwind_find_by_frame (fi, &fi->prologue_cache);
|
| + /* Find THIS frame's ID. */
|
| + /* Default to outermost if no ID is found. */
|
| + fi->this_id.value = outer_frame_id;
|
| + fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
|
| + gdb_assert (frame_id_p (fi->this_id.value));
|
| + fi->this_id.p = 1;
|
| + if (frame_debug)
|
| + {
|
| + fprintf_unfiltered (gdb_stdlog, "-> ");
|
| + fprint_frame_id (gdb_stdlog, fi->this_id.value);
|
| + fprintf_unfiltered (gdb_stdlog, " }\n");
|
| + }
|
| +}
|
| +
|
| /* Return a frame uniq ID that can be used to, later, re-find the
|
| frame. */
|
|
|
| @@ -325,37 +458,14 @@ get_frame_id (struct frame_info *fi)
|
| if (fi == NULL)
|
| return null_frame_id;
|
|
|
| - if (!fi->this_id.p)
|
| - {
|
| - if (frame_debug)
|
| - fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
|
| - fi->level);
|
| - /* Find the unwinder. */
|
| - if (fi->unwind == NULL)
|
| - frame_unwind_find_by_frame (fi, &fi->prologue_cache);
|
| - /* Find THIS frame's ID. */
|
| - /* Default to outermost if no ID is found. */
|
| - fi->this_id.value = outer_frame_id;
|
| - fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
|
| - gdb_assert (frame_id_p (fi->this_id.value));
|
| - fi->this_id.p = 1;
|
| - if (frame_debug)
|
| - {
|
| - fprintf_unfiltered (gdb_stdlog, "-> ");
|
| - fprint_frame_id (gdb_stdlog, fi->this_id.value);
|
| - fprintf_unfiltered (gdb_stdlog, " }\n");
|
| - }
|
| - }
|
| -
|
| - frame_stash_add (fi);
|
| -
|
| + gdb_assert (fi->this_id.p);
|
| return fi->this_id.value;
|
| }
|
|
|
| struct frame_id
|
| get_stack_frame_id (struct frame_info *next_frame)
|
| {
|
| - return get_frame_id (skip_inlined_frames (next_frame));
|
| + return get_frame_id (skip_artificial_frames (next_frame));
|
| }
|
|
|
| struct frame_id
|
| @@ -368,10 +478,10 @@ frame_unwind_caller_id (struct frame_info *next_frame)
|
| returning a null_frame_id (e.g., when a caller requests the frame
|
| ID of "main()"s caller. */
|
|
|
| - next_frame = skip_inlined_frames (next_frame);
|
| + next_frame = skip_artificial_frames (next_frame);
|
| this_frame = get_prev_frame_1 (next_frame);
|
| if (this_frame)
|
| - return get_frame_id (skip_inlined_frames (this_frame));
|
| + return get_frame_id (skip_artificial_frames (this_frame));
|
| else
|
| return null_frame_id;
|
| }
|
| @@ -436,12 +546,12 @@ frame_id_p (struct frame_id l)
|
| }
|
|
|
| int
|
| -frame_id_inlined_p (struct frame_id l)
|
| +frame_id_artificial_p (struct frame_id l)
|
| {
|
| if (!frame_id_p (l))
|
| return 0;
|
|
|
| - return (l.inline_depth != 0);
|
| + return (l.artificial_depth != 0);
|
| }
|
|
|
| int
|
| @@ -473,8 +583,8 @@ frame_id_eq (struct frame_id l, struct frame_id r)
|
| /* An invalid special addr is a wild card (or unused). Otherwise
|
| if special addresses are different, the frames are different. */
|
| eq = 0;
|
| - else if (l.inline_depth != r.inline_depth)
|
| - /* If inline depths are different, the frames must be different. */
|
| + else if (l.artificial_depth != r.artificial_depth)
|
| + /* If artifical depths are different, the frames must be different. */
|
| eq = 0;
|
| else
|
| /* Frames are equal. */
|
| @@ -531,7 +641,7 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
|
| if (!l.stack_addr_p || !r.stack_addr_p)
|
| /* Like NaN, any operation involving an invalid ID always fails. */
|
| inner = 0;
|
| - else if (l.inline_depth > r.inline_depth
|
| + else if (l.artificial_depth > r.artificial_depth
|
| && l.stack_addr == r.stack_addr
|
| && l.code_addr_p == r.code_addr_p
|
| && l.special_addr_p == r.special_addr_p
|
| @@ -619,10 +729,10 @@ frame_find_by_id (struct frame_id id)
|
| return NULL;
|
| }
|
|
|
| -static int
|
| -frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc)
|
| +static CORE_ADDR
|
| +frame_unwind_pc (struct frame_info *this_frame)
|
| {
|
| - if (!this_frame->prev_pc.p)
|
| + if (this_frame->prev_pc.status == CC_UNKNOWN)
|
| {
|
| if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
|
| {
|
| @@ -652,24 +762,35 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc)
|
| {
|
| pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
|
| }
|
| - if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR)
|
| - {
|
| - this_frame->prev_pc.p = -1;
|
| -
|
| - if (frame_debug)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "{ frame_unwind_pc (this_frame=%d)"
|
| - " -> <unavailable> }\n",
|
| - this_frame->level);
|
| - }
|
| - else if (ex.reason < 0)
|
| + if (ex.reason < 0)
|
| {
|
| - throw_exception (ex);
|
| + if (ex.error == NOT_AVAILABLE_ERROR)
|
| + {
|
| + this_frame->prev_pc.status = CC_UNAVAILABLE;
|
| +
|
| + if (frame_debug)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "{ frame_unwind_pc (this_frame=%d)"
|
| + " -> <unavailable> }\n",
|
| + this_frame->level);
|
| + }
|
| + else if (ex.error == OPTIMIZED_OUT_ERROR)
|
| + {
|
| + this_frame->prev_pc.status = CC_NOT_SAVED;
|
| +
|
| + if (frame_debug)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "{ frame_unwind_pc (this_frame=%d)"
|
| + " -> <not saved> }\n",
|
| + this_frame->level);
|
| + }
|
| + else
|
| + throw_exception (ex);
|
| }
|
| else
|
| {
|
| this_frame->prev_pc.value = pc;
|
| - this_frame->prev_pc.p = 1;
|
| + this_frame->prev_pc.status = CC_VALUE;
|
| if (frame_debug)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "{ frame_unwind_pc (this_frame=%d) "
|
| @@ -681,40 +802,23 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc)
|
| else
|
| internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
|
| }
|
| - if (this_frame->prev_pc.p < 0)
|
| - {
|
| - *pc = -1;
|
| - return 0;
|
| - }
|
| - else
|
| - {
|
| - *pc = this_frame->prev_pc.value;
|
| - return 1;
|
| - }
|
| -}
|
|
|
| -static CORE_ADDR
|
| -frame_unwind_pc (struct frame_info *this_frame)
|
| -{
|
| - CORE_ADDR pc;
|
| -
|
| - if (!frame_unwind_pc_if_available (this_frame, &pc))
|
| + if (this_frame->prev_pc.status == CC_VALUE)
|
| + return this_frame->prev_pc.value;
|
| + else if (this_frame->prev_pc.status == CC_UNAVAILABLE)
|
| throw_error (NOT_AVAILABLE_ERROR, _("PC not available"));
|
| + else if (this_frame->prev_pc.status == CC_NOT_SAVED)
|
| + throw_error (OPTIMIZED_OUT_ERROR, _("PC not saved"));
|
| else
|
| - return pc;
|
| + internal_error (__FILE__, __LINE__,
|
| + "unexpected prev_pc status: %d",
|
| + (int) this_frame->prev_pc.status);
|
| }
|
|
|
| CORE_ADDR
|
| frame_unwind_caller_pc (struct frame_info *this_frame)
|
| {
|
| - return frame_unwind_pc (skip_inlined_frames (this_frame));
|
| -}
|
| -
|
| -int
|
| -frame_unwind_caller_pc_if_available (struct frame_info *this_frame,
|
| - CORE_ADDR *pc)
|
| -{
|
| - return frame_unwind_pc_if_available (skip_inlined_frames (this_frame), pc);
|
| + return frame_unwind_pc (skip_artificial_frames (this_frame));
|
| }
|
|
|
| int
|
| @@ -775,7 +879,7 @@ get_frame_func (struct frame_info *this_frame)
|
| static enum register_status
|
| do_frame_register_read (void *src, int regnum, gdb_byte *buf)
|
| {
|
| - if (!frame_register_read (src, regnum, buf))
|
| + if (!deprecated_frame_register_read (src, regnum, buf))
|
| return REG_UNAVAILABLE;
|
| else
|
| return REG_VALID;
|
| @@ -919,7 +1023,8 @@ frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
|
| &lval, &addr, &realnum, buf);
|
|
|
| if (optimized)
|
| - error (_("Register %d was optimized out"), regnum);
|
| + throw_error (OPTIMIZED_OUT_ERROR,
|
| + _("Register %d was not saved"), regnum);
|
| if (unavailable)
|
| throw_error (NOT_AVAILABLE_ERROR,
|
| _("Register %d is not available"), regnum);
|
| @@ -961,7 +1066,10 @@ frame_unwind_register_value (struct frame_info *frame, int regnum)
|
| {
|
| fprintf_unfiltered (gdb_stdlog, "->");
|
| if (value_optimized_out (value))
|
| - fprintf_unfiltered (gdb_stdlog, " optimized out");
|
| + {
|
| + fprintf_unfiltered (gdb_stdlog, " ");
|
| + val_print_optimized_out (value, gdb_stdlog);
|
| + }
|
| else
|
| {
|
| if (VALUE_LVAL (value) == lval_register)
|
| @@ -1071,17 +1179,12 @@ put_frame_register (struct frame_info *frame, int regnum,
|
| frame_register (frame, regnum, &optim, &unavail,
|
| &lval, &addr, &realnum, NULL);
|
| if (optim)
|
| - error (_("Attempt to assign to a value that was optimized out."));
|
| + error (_("Attempt to assign to a register that was not saved."));
|
| switch (lval)
|
| {
|
| case lval_memory:
|
| {
|
| - /* FIXME: write_memory doesn't yet take constant buffers.
|
| - Arrrg! */
|
| - gdb_byte tmp[MAX_REGISTER_SIZE];
|
| -
|
| - memcpy (tmp, buf, register_size (gdbarch, regnum));
|
| - write_memory (addr, tmp, register_size (gdbarch, regnum));
|
| + write_memory (addr, buf, register_size (gdbarch, regnum));
|
| break;
|
| }
|
| case lval_register:
|
| @@ -1092,7 +1195,8 @@ put_frame_register (struct frame_info *frame, int regnum,
|
| }
|
| }
|
|
|
| -/* frame_register_read ()
|
| +/* This function is deprecated. Use get_frame_register_value instead,
|
| + which provides more accurate information.
|
|
|
| Find and return the value of REGNUM for the specified stack frame.
|
| The number of bytes copied is REGISTER_SIZE (REGNUM).
|
| @@ -1100,7 +1204,7 @@ put_frame_register (struct frame_info *frame, int regnum,
|
| Returns 0 if the register value could not be found. */
|
|
|
| int
|
| -frame_register_read (struct frame_info *frame, int regnum,
|
| +deprecated_frame_register_read (struct frame_info *frame, int regnum,
|
| gdb_byte *myaddr)
|
| {
|
| int optimized;
|
| @@ -1221,7 +1325,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
|
| {
|
| gdb_byte buf[MAX_REGISTER_SIZE];
|
|
|
| - frame_register_read (frame, regnum, buf);
|
| + deprecated_frame_register_read (frame, regnum, buf);
|
| memcpy (buf + offset, myaddr, curr_len);
|
| put_frame_register (frame, regnum, buf);
|
| }
|
| @@ -1484,7 +1588,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
|
| very likely to read this, and the corresponding unwinder is
|
| entitled to rely that the PC doesn't magically change. */
|
| fi->next->prev_pc.value = pc;
|
| - fi->next->prev_pc.p = 1;
|
| + fi->next->prev_pc.status = CC_VALUE;
|
|
|
| /* We currently assume that frame chain's can't cross spaces. */
|
| fi->pspace = fi->next->pspace;
|
| @@ -1587,6 +1691,42 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
|
| }
|
| }
|
|
|
| +/* Get the previous raw frame, and check that it is not identical to
|
| + same other frame frame already in the chain. If it is, there is
|
| + most likely a stack cycle, so we discard it, and mark THIS_FRAME as
|
| + outermost, with UNWIND_SAME_ID stop reason. Unlike the other
|
| + validity tests, that compare THIS_FRAME and the next frame, we do
|
| + this right after creating the previous frame, to avoid ever ending
|
| + up with two frames with the same id in the frame chain. */
|
| +
|
| +static struct frame_info *
|
| +get_prev_frame_if_no_cycle (struct frame_info *this_frame)
|
| +{
|
| + struct frame_info *prev_frame;
|
| +
|
| + prev_frame = get_prev_frame_raw (this_frame);
|
| + if (prev_frame == NULL)
|
| + return NULL;
|
| +
|
| + compute_frame_id (prev_frame);
|
| + if (frame_stash_add (prev_frame))
|
| + return prev_frame;
|
| +
|
| + /* Another frame with the same id was already in the stash. We just
|
| + detected a cycle. */
|
| + if (frame_debug)
|
| + {
|
| + fprintf_unfiltered (gdb_stdlog, "-> ");
|
| + fprint_frame (gdb_stdlog, NULL);
|
| + fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
|
| + }
|
| + this_frame->stop_reason = UNWIND_SAME_ID;
|
| + /* Unlink. */
|
| + prev_frame->next = NULL;
|
| + this_frame->prev = NULL;
|
| + return NULL;
|
| +}
|
| +
|
| /* Return a "struct frame_info" corresponding to the frame that called
|
| THIS_FRAME. Returns NULL if there is no such frame.
|
|
|
| @@ -1596,7 +1736,6 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
|
| static struct frame_info *
|
| get_prev_frame_1 (struct frame_info *this_frame)
|
| {
|
| - struct frame_id this_id;
|
| struct gdbarch *gdbarch;
|
|
|
| gdb_assert (this_frame != NULL);
|
| @@ -1640,7 +1779,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
| until we have unwound all the way down to the previous non-inline
|
| frame. */
|
| if (get_frame_type (this_frame) == INLINE_FRAME)
|
| - return get_prev_frame_raw (this_frame);
|
| + return get_prev_frame_if_no_cycle (this_frame);
|
|
|
| /* Check that this frame is unwindable. If it isn't, don't try to
|
| unwind to the prev frame. */
|
| @@ -1649,21 +1788,16 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
| &this_frame->prologue_cache);
|
|
|
| if (this_frame->stop_reason != UNWIND_NO_REASON)
|
| - return NULL;
|
| -
|
| - /* Check that this frame's ID was valid. If it wasn't, don't try to
|
| - unwind to the prev frame. Be careful to not apply this test to
|
| - the sentinel frame. */
|
| - this_id = get_frame_id (this_frame);
|
| - if (this_frame->level >= 0 && frame_id_eq (this_id, outer_frame_id))
|
| {
|
| if (frame_debug)
|
| {
|
| + enum unwind_stop_reason reason = this_frame->stop_reason;
|
| +
|
| fprintf_unfiltered (gdb_stdlog, "-> ");
|
| fprint_frame (gdb_stdlog, NULL);
|
| - fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
|
| + fprintf_unfiltered (gdb_stdlog, " // %s }\n",
|
| + frame_stop_reason_symbol_string (reason));
|
| }
|
| - this_frame->stop_reason = UNWIND_NULL_ID;
|
| return NULL;
|
| }
|
|
|
| @@ -1673,7 +1807,8 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
| See the comment at frame_id_inner for details. */
|
| if (get_frame_type (this_frame) == NORMAL_FRAME
|
| && this_frame->next->unwind->type == NORMAL_FRAME
|
| - && frame_id_inner (get_frame_arch (this_frame->next), this_id,
|
| + && frame_id_inner (get_frame_arch (this_frame->next),
|
| + get_frame_id (this_frame),
|
| get_frame_id (this_frame->next)))
|
| {
|
| CORE_ADDR this_pc_in_block;
|
| @@ -1682,7 +1817,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
|
|
| /* gcc -fsplit-stack __morestack can continue the stack anywhere. */
|
| this_pc_in_block = get_frame_address_in_block (this_frame);
|
| - morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block);
|
| + morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym;
|
| if (morestack_msym)
|
| morestack_name = SYMBOL_LINKAGE_NAME (morestack_msym);
|
| if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
|
| @@ -1699,22 +1834,6 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
| }
|
| }
|
|
|
| - /* Check that this and the next frame are not identical. If they
|
| - are, there is most likely a stack cycle. As with the inner-than
|
| - test above, avoid comparing the inner-most and sentinel frames. */
|
| - if (this_frame->level > 0
|
| - && frame_id_eq (this_id, get_frame_id (this_frame->next)))
|
| - {
|
| - if (frame_debug)
|
| - {
|
| - fprintf_unfiltered (gdb_stdlog, "-> ");
|
| - fprint_frame (gdb_stdlog, NULL);
|
| - fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
|
| - }
|
| - this_frame->stop_reason = UNWIND_SAME_ID;
|
| - return NULL;
|
| - }
|
| -
|
| /* Check that this and the next frame do not unwind the PC register
|
| to the same memory location. If they do, then even though they
|
| have different frame IDs, the new frame will be bogus; two
|
| @@ -1762,7 +1881,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
| }
|
| }
|
|
|
| - return get_prev_frame_raw (this_frame);
|
| + return get_prev_frame_if_no_cycle (this_frame);
|
| }
|
|
|
| /* Construct a new "struct frame_info" and link it previous to
|
| @@ -2332,7 +2451,7 @@ frame_unwind_arch (struct frame_info *next_frame)
|
| struct gdbarch *
|
| frame_unwind_caller_arch (struct frame_info *next_frame)
|
| {
|
| - return frame_unwind_arch (skip_inlined_frames (next_frame));
|
| + return frame_unwind_arch (skip_artificial_frames (next_frame));
|
| }
|
|
|
| /* Stack pointer methods. */
|
| @@ -2389,6 +2508,25 @@ frame_stop_reason_string (enum unwind_stop_reason reason)
|
| }
|
| }
|
|
|
| +/* Return the enum symbol name of REASON as a string, to use in debug
|
| + output. */
|
| +
|
| +static const char *
|
| +frame_stop_reason_symbol_string (enum unwind_stop_reason reason)
|
| +{
|
| + switch (reason)
|
| + {
|
| +#define SET(name, description) \
|
| + case name: return #name;
|
| +#include "unwind_stop_reasons.def"
|
| +#undef SET
|
| +
|
| + default:
|
| + internal_error (__FILE__, __LINE__,
|
| + "Invalid frame stop reason");
|
| + }
|
| +}
|
| +
|
| /* Clean up after a failed (wrong unwinder) attempt to unwind past
|
| FRAME. */
|
|
|
| @@ -2455,6 +2593,8 @@ _initialize_frame (void)
|
| {
|
| obstack_init (&frame_cache_obstack);
|
|
|
| + frame_stash_create ();
|
| +
|
| observer_attach_target_changed (frame_observer_target_changed);
|
|
|
| add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
|
| @@ -2494,23 +2634,23 @@ the rest of the stack trace."),
|
| &set_backtrace_cmdlist,
|
| &show_backtrace_cmdlist);
|
|
|
| - add_setshow_integer_cmd ("limit", class_obscure,
|
| - &backtrace_limit, _("\
|
| + add_setshow_uinteger_cmd ("limit", class_obscure,
|
| + &backtrace_limit, _("\
|
| Set an upper bound on the number of backtrace levels."), _("\
|
| Show the upper bound on the number of backtrace levels."), _("\
|
| No more than the specified number of frames can be displayed or examined.\n\
|
| -Zero is unlimited."),
|
| - NULL,
|
| - show_backtrace_limit,
|
| - &set_backtrace_cmdlist,
|
| - &show_backtrace_cmdlist);
|
| +Literal \"unlimited\" or zero means no limit."),
|
| + NULL,
|
| + show_backtrace_limit,
|
| + &set_backtrace_cmdlist,
|
| + &show_backtrace_cmdlist);
|
|
|
| /* Debug this files internals. */
|
| - add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
|
| + add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
|
| Set frame debugging."), _("\
|
| Show frame debugging."), _("\
|
| When non-zero, frame specific internal debugging is enabled."),
|
| - NULL,
|
| - show_frame_debug,
|
| - &setdebuglist, &showdebuglist);
|
| + NULL,
|
| + show_frame_debug,
|
| + &setdebuglist, &showdebuglist);
|
| }
|
|
|