/* Cache and manage frames for GDB, the GNU debugger.
- Copyright (C) 1986-2017 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "frame-base.h"
#include "command.h"
#include "gdbcmd.h"
-#include "observer.h"
+#include "observable.h"
#include "objfiles.h"
#include "gdbthread.h"
#include "block.h"
struct program_space *pspace;
/* The frame's address space. */
- struct address_space *aspace;
+ const address_space *aspace;
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
htab_empty (frame_stash);
}
+/* See frame.h */
+scoped_restore_selected_frame::scoped_restore_selected_frame ()
+{
+ m_fid = get_frame_id (get_selected_frame (NULL));
+}
+
+/* See frame.h */
+scoped_restore_selected_frame::~scoped_restore_selected_frame ()
+{
+ frame_info *frame = frame_find_by_id (m_fid);
+ if (frame == NULL)
+ warning (_("Unable to restore previously selected frame."));
+ else
+ select_frame (frame);
+}
+
/* Flag to control debugging. */
unsigned int frame_debug;
{
if (this_frame->prev_pc.status == CC_UNKNOWN)
{
- if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
+ struct gdbarch *prev_gdbarch;
+ CORE_ADDR pc = 0;
+ int pc_p = 0;
+
+ /* 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 (this_frame, ISA_PC_REGNUM, buf);
+ return extract_unsigned_integer (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. */
+ prev_gdbarch = frame_unwind_arch (this_frame);
+
+ try
+ {
+ pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
+ pc_p = 1;
+ }
+ catch (const gdb_exception_error &ex)
{
- struct gdbarch *prev_gdbarch;
- CORE_ADDR pc = 0;
- int pc_p = 0;
-
- /* 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 (this_frame, ISA_PC_REGNUM, buf);
- return extract_unsigned_integer (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. */
- prev_gdbarch = frame_unwind_arch (this_frame);
-
- TRY
+ if (ex.error == NOT_AVAILABLE_ERROR)
{
- pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
- pc_p = 1;
+ 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);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ else if (ex.error == OPTIMIZED_OUT_ERROR)
{
- 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);
- }
- END_CATCH
+ this_frame->prev_pc.status = CC_NOT_SAVED;
- if (pc_p)
- {
- this_frame->prev_pc.value = pc;
- this_frame->prev_pc.status = CC_VALUE;
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
- "{ frame_unwind_pc (this_frame=%d) "
- "-> %s }\n",
- this_frame->level,
- hex_string (this_frame->prev_pc.value));
+ "{ frame_unwind_pc (this_frame=%d)"
+ " -> <not saved> }\n",
+ this_frame->level);
}
+ else
+ throw;
+ }
+
+ if (pc_p)
+ {
+ this_frame->prev_pc.value = pc;
+ this_frame->prev_pc.status = CC_VALUE;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_pc (this_frame=%d) "
+ "-> %s }\n",
+ this_frame->level,
+ hex_string (this_frame->prev_pc.value));
}
- else
- internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
}
if (this_frame->prev_pc.status == CC_VALUE)
return pc;
}
-static enum register_status
-do_frame_register_read (void *src, int regnum, gdb_byte *buf)
-{
- if (!deprecated_frame_register_read ((struct frame_info *) src, regnum, buf))
- return REG_UNAVAILABLE;
- else
- return REG_VALID;
-}
-
-std::unique_ptr<struct regcache>
+std::unique_ptr<readonly_detached_regcache>
frame_save_as_regcache (struct frame_info *this_frame)
{
- struct address_space *aspace = get_frame_address_space (this_frame);
- std::unique_ptr<struct regcache> regcache
- (new struct regcache (get_frame_arch (this_frame), aspace));
+ auto cooked_read = [this_frame] (int regnum, gdb_byte *buf)
+ {
+ if (!deprecated_frame_register_read (this_frame, regnum, buf))
+ return REG_UNAVAILABLE;
+ else
+ return REG_VALID;
+ };
+
+ std::unique_ptr<readonly_detached_regcache> regcache
+ (new readonly_detached_regcache (get_frame_arch (this_frame), cooked_read));
- regcache_save (regcache.get (), do_frame_register_read, this_frame);
return regcache;
}
{
/* Popping a dummy frame involves restoring more than just registers.
dummy_frame_pop does all the work. */
- dummy_frame_pop (get_frame_id (this_frame), inferior_ptid);
+ dummy_frame_pop (get_frame_id (this_frame), inferior_thread ());
return;
}
Save them in a scratch buffer so that there isn't a race between
trying to extract the old values from the current regcache while
at the same time writing new values into that same cache. */
- std::unique_ptr<struct regcache> scratch
+ std::unique_ptr<readonly_detached_regcache> scratch
= frame_save_as_regcache (prev_frame);
/* FIXME: cagney/2003-03-16: It should be possible to tell the
Unfortunately, they don't implement it. Their lack of a formal
definition can lead to targets writing back bogus values
(arguably a bug in the target code mind). */
- /* Now copy those saved registers into the current regcache.
- Here, regcache_cpy() calls regcache_restore(). */
- regcache_cpy (get_current_regcache (), scratch.get ());
+ /* Now copy those saved registers into the current regcache. */
+ get_current_regcache ()->restore (scratch.get ());
/* We've made right mess of GDB's local state, just discard
everything. */
}
void
-frame_register_unwind (struct frame_info *frame, int regnum,
+frame_register_unwind (frame_info *next_frame, int regnum,
int *optimizedp, int *unavailablep,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *bufferp)
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- value = frame_unwind_register_value (frame, regnum);
+ value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
/* Dispose of the new value. This prevents watchpoints from
trying to watch the saved frame pointer. */
release_value (value);
- value_free (value);
}
void
}
void
-frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
+frame_unwind_register (frame_info *next_frame, int regnum, gdb_byte *buf)
{
int optimized;
int unavailable;
int realnum;
enum lval_type lval;
- frame_register_unwind (frame, regnum, &optimized, &unavailable,
+ frame_register_unwind (next_frame, regnum, &optimized, &unavailable,
&lval, &addr, &realnum, buf);
if (optimized)
}
struct value *
-frame_unwind_register_value (struct frame_info *frame, int regnum)
+frame_unwind_register_value (frame_info *next_frame, int regnum)
{
struct gdbarch *gdbarch;
struct value *value;
- gdb_assert (frame != NULL);
- gdbarch = frame_unwind_arch (frame);
+ gdb_assert (next_frame != NULL);
+ gdbarch = frame_unwind_arch (next_frame);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog,
"{ frame_unwind_register_value "
"(frame=%d,regnum=%d(%s),...) ",
- frame->level, regnum,
+ next_frame->level, regnum,
user_reg_map_regnum_to_name (gdbarch, regnum));
}
/* Find the unwinder. */
- if (frame->unwind == NULL)
- frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+ if (next_frame->unwind == NULL)
+ frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
/* Ask this frame to unwind its register. */
- value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+ value = next_frame->unwind->prev_register (next_frame,
+ &next_frame->prologue_cache,
+ regnum);
if (frame_debug)
{
}
LONGEST
-frame_unwind_register_signed (struct frame_info *frame, int regnum)
+frame_unwind_register_signed (frame_info *next_frame, int regnum)
{
- struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, regnum);
- struct value *value = frame_unwind_register_value (frame, regnum);
+ struct value *value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
byte_order);
release_value (value);
- value_free (value);
return r;
}
}
ULONGEST
-frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+frame_unwind_register_unsigned (frame_info *next_frame, int regnum)
{
- struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, regnum);
- struct value *value = frame_unwind_register_value (frame, regnum);
+ struct value *value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
byte_order);
release_value (value);
- value_free (value);
return r;
}
break;
}
case lval_register:
- regcache_cooked_write (get_current_regcache (), realnum, buf);
+ get_current_regcache ()->cooked_write (realnum, buf);
break;
default:
error (_("Attempt to assign to an unmodifiable value."));
/* Ensure that we will not read beyond the end of the register file.
This can only ever happen if the debug information is bad. */
maxsize = -offset;
- numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+ numregs = gdbarch_num_cooked_regs (gdbarch);
for (i = regnum; i < numregs; i++)
{
int thissize = register_size (gdbarch, i);
if (*optimizedp || *unavailablep)
{
release_value (value);
- value_free (value);
return 0;
}
memcpy (myaddr, value_contents_all (value) + offset, curr_len);
release_value (value);
- value_free (value);
}
myaddr += curr_len;
curr_len);
put_frame_register (frame, regnum, value_contents_raw (value));
release_value (value);
- value_free (value);
}
myaddr += curr_len;
frame->level = -1;
frame->pspace = pspace;
- frame->aspace = get_regcache_aspace (regcache);
+ frame->aspace = regcache->aspace ();
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
if (get_traceframe_number () < 0)
{
/* No current inferior, no frame. */
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
return 0;
+ thread_info *tp = inferior_thread ();
/* Don't try to read from a dead thread. */
- if (is_exited (inferior_ptid))
+ if (tp->state == THREAD_EXITED)
return 0;
/* ... or from a spinning thread. */
- if (is_executing (inferior_ptid))
+ if (tp->executing)
return 0;
}
}
}
-#if GDB_SELF_TEST
-struct frame_info *
-create_test_frame (struct regcache *regcache)
-{
- struct frame_info *this_frame = XCNEW (struct frame_info);
-
- sentinel_frame = create_sentinel_frame (NULL, regcache);
- sentinel_frame->prev = this_frame;
- sentinel_frame->prev_p = 1;;
- this_frame->prev_arch.p = 1;
- this_frame->prev_arch.arch = get_regcache_arch (regcache);
- this_frame->next = sentinel_frame;
-
- return this_frame;
-}
-#endif
-
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
}
}
-/* Called during frame unwinding to remove a previous frame pointer from a
- frame passed in ARG. */
-
-static void
-remove_prev_frame (void *arg)
-{
- struct frame_info *this_frame, *prev_frame;
-
- this_frame = (struct frame_info *) arg;
- prev_frame = this_frame->prev;
- gdb_assert (prev_frame != NULL);
-
- prev_frame->next = NULL;
- this_frame->prev = NULL;
-}
-
/* 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
get_prev_frame_if_no_cycle (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
- struct cleanup *prev_frame_cleanup;
prev_frame = get_prev_frame_raw (this_frame);
if (prev_frame->level == 0)
return prev_frame;
- /* The cleanup will remove the previous frame that get_prev_frame_raw
- linked onto THIS_FRAME. */
- prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
-
- compute_frame_id (prev_frame);
- if (!frame_stash_add (prev_frame))
+ try
{
- /* Another frame with the same id was already in the stash. We just
- detected a cycle. */
- if (frame_debug)
+ compute_frame_id (prev_frame);
+ if (!frame_stash_add (prev_frame))
{
- fprintf_unfiltered (gdb_stdlog, "-> ");
- fprint_frame (gdb_stdlog, NULL);
- fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+ /* 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;
+ prev_frame = NULL;
}
- this_frame->stop_reason = UNWIND_SAME_ID;
- /* Unlink. */
+ }
+ catch (const gdb_exception &ex)
+ {
prev_frame->next = NULL;
this_frame->prev = NULL;
- prev_frame = NULL;
+
+ throw;
}
- discard_cleanups (prev_frame_cleanup);
return prev_frame;
}
{
struct frame_info *prev_frame = NULL;
- TRY
+ try
{
prev_frame = get_prev_frame_always_1 (this_frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == MEMORY_ERROR)
{
Allocate using stack local STOP_STRING then assign the
pointer to the frame, this allows the STOP_STRING on the
frame to be of type 'const char *'. */
- size = strlen (ex.message) + 1;
+ size = ex.message->size () + 1;
stop_string = (char *) frame_obstack_zalloc (size);
- memcpy (stop_string, ex.message, size);
+ memcpy (stop_string, ex.what (), size);
this_frame->stop_string = stop_string;
}
prev_frame = NULL;
}
else
- throw_exception (ex);
+ throw;
}
- END_CATCH
return prev_frame;
}
returned. */
maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
BMSYMBOL_VALUE_ADDRESS (msymbol),
- ¤t_target);
+ current_top_target ());
return maddr == get_frame_func (this_frame);
}
gdb_assert (frame->next != NULL);
- TRY
+ try
{
*pc = frame_unwind_pc (frame->next);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
return 0;
else
- throw_exception (ex);
+ throw;
}
- END_CATCH
return 1;
}
CORE_ADDR *pc)
{
- TRY
+ try
{
*pc = get_frame_address_in_block (this_frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
return 0;
- throw_exception (ex);
+ throw;
}
- END_CATCH
return 1;
}
if (next_frame)
sym = get_frame_function (next_frame);
else
- sym = inline_skipped_symbol (inferior_ptid);
+ sym = inline_skipped_symbol (inferior_thread ());
/* If frame is inline, it certainly has symbols. */
gdb_assert (sym);
return this_frame->pspace;
}
-struct address_space *
+const address_space *
get_frame_address_space (struct frame_info *frame)
{
return frame->aspace;
a PC that is guaranteed to be inside the frame's code
block. */
- TRY
+ try
{
pc = get_frame_address_in_block (frame);
pc_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
if (pc_p)
{
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
- /* Normality - an architecture that provides a way of obtaining any
- frame inner-most address. */
- if (gdbarch_unwind_sp_p (gdbarch))
- /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
- operate on THIS_FRAME now. */
- return gdbarch_unwind_sp (gdbarch, this_frame->next);
- /* Now things are really are grim. Hope that the value returned by
- the gdbarch_sp_regnum register is meaningful. */
- if (gdbarch_sp_regnum (gdbarch) >= 0)
- return get_frame_register_unsigned (this_frame,
- gdbarch_sp_regnum (gdbarch));
- internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
+ /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
+ operate on THIS_FRAME now. */
+ return gdbarch_unwind_sp (gdbarch, this_frame->next);
}
/* Return the reason why we can't unwind past FRAME. */
/* Clean up after a failed (wrong unwinder) attempt to unwind past
FRAME. */
-static void
-frame_cleanup_after_sniffer (void *arg)
+void
+frame_cleanup_after_sniffer (struct frame_info *frame)
{
- struct frame_info *frame = (struct frame_info *) arg;
-
/* The sniffer should not allocate a prologue cache if it did not
match this frame. */
gdb_assert (frame->prologue_cache == 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. */
+ If sniffing fails, the caller should be sure to call
+ frame_cleanup_after_sniffer. */
-struct cleanup *
+void
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);
}
static struct cmd_list_element *set_backtrace_cmdlist;
static struct cmd_list_element *show_backtrace_cmdlist;
static void
-set_backtrace_cmd (char *args, int from_tty)
+set_backtrace_cmd (const char *args, int from_tty)
{
help_list (set_backtrace_cmdlist, "set backtrace ", all_commands,
gdb_stdout);
}
static void
-show_backtrace_cmd (char *args, int from_tty)
+show_backtrace_cmd (const char *args, int from_tty)
{
cmd_show_list (show_backtrace_cmdlist, from_tty, "");
}
frame_stash_create ();
- observer_attach_target_changed (frame_observer_target_changed);
+ gdb::observers::target_changed.attach (frame_observer_target_changed);
add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\