aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/frame.c')
-rw-r--r--gdb/frame.c259
1 files changed, 151 insertions, 108 deletions
diff --git a/gdb/frame.c b/gdb/frame.c
index 2fb06a0..2442f5d 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1,6 +1,6 @@
/* Cache and manage frames for GDB, the GNU debugger.
- Copyright (C) 1986-2024 Free Software Foundation, Inc.
+ Copyright (C) 1986-2025 Free Software Foundation, Inc.
This file is part of GDB.
@@ -213,82 +213,129 @@ get_frame_pc_masked (const frame_info_ptr &frame)
return frame->next->prev_pc.masked;
}
-/* 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. */
+/* Deletion function for the frame cache hash table. */
-static htab_t frame_stash;
+static void
+frame_info_del (frame_info *frame)
+{
+ if (frame->prologue_cache != nullptr)
+ frame->unwind->dealloc_cache (frame, frame->prologue_cache);
-/* 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. */
+ if (frame->base_cache != nullptr)
+ frame->base->unwind->dealloc_cache (frame, frame->base_cache);
+}
-static hashval_t
-frame_addr_hash (const void *ap)
+/* A wrapper for frame_info that calls the 'frame_info_del' when
+ destroyed. */
+
+struct frame_info_stash_entry
{
- const frame_info *frame = (const frame_info *) ap;
- const struct frame_id f_id = frame->this_id.value;
- hashval_t hash = 0;
+ explicit frame_info_stash_entry (frame_info *info)
+ : frame (info)
+ {
+ }
- gdb_assert (f_id.stack_status != FID_STACK_INVALID
- || f_id.code_addr_p
- || f_id.special_addr_p);
+ ~frame_info_stash_entry ()
+ {
+ destroy ();
+ }
- if (f_id.stack_status == FID_STACK_VALID)
- 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);
+ DISABLE_COPY_AND_ASSIGN (frame_info_stash_entry);
- char user_created_p = f_id.user_created_p;
- hash = iterative_hash (&user_created_p, sizeof (user_created_p), hash);
+ frame_info_stash_entry (frame_info_stash_entry &&other)
+ : frame (other.frame)
+ {
+ other.frame = nullptr;
+ }
- return hash;
-}
+ frame_info_stash_entry &operator= (frame_info_stash_entry &&other)
+ {
+ destroy ();
+ frame = other.frame;
+ other.frame = nullptr;
+ return *this;
+ }
-/* Internal equality function for the hash table. This function
- defers equality operations to frame_id::operator==. */
+ void destroy ()
+ {
+ if (frame != nullptr)
+ frame_info_del (frame);
+ }
-static int
-frame_addr_hash_eq (const void *a, const void *b)
+ frame_info *frame;
+};
+
+struct frame_info_stash_hash
{
- const frame_info *f_entry = (const frame_info *) a;
- const frame_info *f_element = (const frame_info *) b;
+ using is_transparent = void;
+ using is_avalanching = void;
- return f_entry->this_id.value == f_element->this_id.value;
-}
+ uint64_t operator() (const frame_id &f_id) const noexcept
+ {
+ hashval_t hash = 0;
-/* Deletion function for the frame cache hash table. */
+ gdb_assert (f_id.stack_status != FID_STACK_INVALID
+ || f_id.code_addr_p
+ || f_id.special_addr_p);
-static void
-frame_info_del (frame_info *frame)
-{
- if (frame->prologue_cache != nullptr)
- frame->unwind->dealloc_cache (frame, frame->prologue_cache);
+ if (f_id.stack_status == FID_STACK_VALID)
+ 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);
- if (frame->base_cache != nullptr)
- frame->base->unwind->dealloc_cache (frame, frame->base_cache);
-}
+ char user_created_p = f_id.user_created_p;
+ hash = iterative_hash (&user_created_p, sizeof (user_created_p), hash);
-/* Internal function to create the frame_stash hash table. 100 seems
- to be a good compromise to start the hash table at. */
+ return hash;
+ }
-static void
-frame_stash_create (void)
+ uint64_t operator() (const frame_info_stash_entry &info) const noexcept
+ {
+ return (*this) (info.frame->this_id.value);
+ }
+
+ uint64_t operator() (const frame_info *frame) const noexcept
+ {
+ return (*this) (frame->this_id.value);
+ }
+};
+
+struct frame_info_stash_eq
{
- frame_stash = htab_create
- (100, frame_addr_hash, frame_addr_hash_eq,
- [] (void *p)
- {
- auto frame = static_cast<frame_info *> (p);
- frame_info_del (frame);
- });
-}
+ using is_transparent = void;
+
+ bool operator() (const frame_id &lhs, const frame_info_stash_entry &rhs)
+ const noexcept
+ {
+ return lhs == rhs.frame->this_id.value;
+ }
+
+ bool operator() (const frame_info *lhs, const frame_info_stash_entry &rhs)
+ const noexcept
+ {
+ return (*this) (lhs->this_id.value, rhs);
+ }
+
+ bool operator() (const frame_info_stash_entry &lhs,
+ const frame_info_stash_entry &rhs)
+ const noexcept
+ {
+ return (*this) (lhs.frame->this_id.value, rhs);
+ }
+};
+
+/* 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 gdb::unordered_set<frame_info_stash_entry, frame_info_stash_hash,
+ frame_info_stash_eq> frame_stash;
/* 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
@@ -300,18 +347,7 @@ frame_stash_add (frame_info *frame)
/* Valid frame levels are -1 (sentinel frames) and above. */
gdb_assert (frame->level >= -1);
- frame_info **slot = (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 != nullptr)
- return false;
-
- *slot = frame;
- return true;
+ return frame_stash.emplace (frame).second;
}
/* Internal function to search the frame stash for an entry with the
@@ -321,12 +357,10 @@ frame_stash_add (frame_info *frame)
static frame_info_ptr
frame_stash_find (struct frame_id id)
{
- struct frame_info dummy;
- frame_info *frame;
-
- dummy.this_id.value = id;
- frame = (frame_info *) htab_find (frame_stash, &dummy);
- return frame_info_ptr (frame);
+ auto iter = frame_stash.find (id);
+ if (iter == frame_stash.end ())
+ return nullptr;
+ return frame_info_ptr (iter->frame);
}
/* Internal function to invalidate the frame stash by removing all
@@ -336,7 +370,7 @@ frame_stash_find (struct frame_id id)
static void
frame_stash_invalidate (void)
{
- htab_empty (frame_stash);
+ frame_stash.clear ();
}
/* See frame.h */
@@ -1623,7 +1657,7 @@ create_sentinel_frame (program_space *pspace, address_space *aspace,
regcache *regcache, CORE_ADDR stack_addr,
CORE_ADDR code_addr)
{
- frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ frame_info *frame = frame_obstack_zalloc<frame_info> ();
frame->level = -1;
frame->pspace = pspace;
@@ -1991,7 +2025,7 @@ select_frame (const frame_info_ptr &fi)
block. */
if (get_frame_address_in_block_if_available (fi, &pc))
{
- struct compunit_symtab *cust = find_pc_compunit_symtab (pc);
+ struct compunit_symtab *cust = find_compunit_symtab_for_pc (pc);
if (cust != NULL
&& cust->language () != current_language->la_language
@@ -2021,7 +2055,7 @@ create_new_frame (frame_id id)
if (frame != nullptr)
return frame;
- frame_info *fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ frame_info *fi = frame_obstack_zalloc<frame_info> ();
fi->next = create_sentinel_frame (current_program_space,
current_inferior ()->aspace.get (),
@@ -2111,7 +2145,7 @@ reinit_frame_cache (void)
{
++frame_cache_generation;
- if (htab_elements (frame_stash) > 0)
+ if (!frame_stash.empty ())
annotate_frames_invalid ();
invalidate_selected_frame ();
@@ -2325,7 +2359,22 @@ get_prev_frame_always_1 (const frame_info_ptr &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_maybe_check_cycle (this_frame);
+ {
+ frame_info_ptr fi = get_prev_frame_maybe_check_cycle (this_frame);
+
+ /* If this_frame is the current frame, then compute and stash its frame
+ id so that the cycle check in get_prev_frame_maybe_check_cycle works
+ correctly in the case where inline frame 0 has been duplicated.
+
+ The this_id.p check is required to avoid recursion as computing the
+ frame id results in a call to inline_frame_this_id which calls back
+ into get_prev_frame_always. */
+ if (this_frame->level == 0
+ && this_frame->this_id.p != frame_id_status::COMPUTING)
+ get_frame_id (this_frame);
+
+ return fi;
+ }
/* If this_frame is the current frame, then compute and stash its
frame id prior to fetching and computing the frame id of the
@@ -2522,7 +2571,7 @@ get_prev_frame_raw (const frame_info_ptr &this_frame)
quickly reclaimed when the frame cache is flushed, and the `we've
been here before' check above will stop repeated memory
allocation calls. */
- prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ prev_frame = frame_obstack_zalloc<frame_info> ();
prev_frame->level = this_frame->level + 1;
/* For now, assume we don't have frame chains crossing address
@@ -2602,7 +2651,7 @@ inside_main_func (const frame_info_ptr &this_frame)
SEARCH_FUNCTION_DOMAIN, nullptr);
/* This lookup should always yield a block-valued symbol. */
- if (bs.symbol != nullptr && bs.symbol->aclass () == LOC_BLOCK)
+ if (bs.symbol != nullptr && bs.symbol->loc_class () == LOC_BLOCK)
{
const struct block *block = bs.symbol->value_block ();
gdb_assert (block != nullptr);
@@ -2648,15 +2697,14 @@ get_prev_frame (const frame_info_ptr &this_frame)
{
FRAME_SCOPED_DEBUG_ENTER_EXIT;
- CORE_ADDR frame_pc;
- int frame_pc_p;
+ std::optional<CORE_ADDR> frame_pc;
/* There is always a frame. If this assertion fails, suspect that
something should be calling get_selected_frame() or
get_current_frame(). */
gdb_assert (this_frame != NULL);
- frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
+ frame_pc = get_frame_pc_if_available (this_frame);
/* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
sense to stop unwinding at a dummy frame. One place where a dummy
@@ -2671,7 +2719,7 @@ get_prev_frame (const frame_info_ptr &this_frame)
if (this_frame->level >= 0
&& get_frame_type (this_frame) == NORMAL_FRAME
&& !user_set_backtrace_options.backtrace_past_main
- && frame_pc_p
+ && frame_pc.has_value ()
&& inside_main_func (this_frame))
/* Don't unwind past main(). Note, this is done _before_ the
frame has been marked as previously unwound. That way if the
@@ -2718,7 +2766,7 @@ get_prev_frame (const frame_info_ptr &this_frame)
if (this_frame->level >= 0
&& get_frame_type (this_frame) == NORMAL_FRAME
&& !user_set_backtrace_options.backtrace_past_entry
- && frame_pc_p
+ && frame_pc.has_value ()
&& inside_entry_func (this_frame))
{
frame_debug_got_null_frame (this_frame, "inside entry func");
@@ -2732,7 +2780,7 @@ get_prev_frame (const frame_info_ptr &this_frame)
&& (get_frame_type (this_frame) == NORMAL_FRAME
|| get_frame_type (this_frame) == INLINE_FRAME)
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
- && frame_pc_p && frame_pc == 0)
+ && frame_pc.has_value () && *frame_pc == 0)
{
frame_debug_got_null_frame (this_frame, "zero PC");
return NULL;
@@ -2748,25 +2796,24 @@ get_frame_pc (const frame_info_ptr &frame)
return frame_unwind_pc (frame_info_ptr (frame->next));
}
-bool
-get_frame_pc_if_available (const frame_info_ptr &frame, CORE_ADDR *pc)
+std::optional<CORE_ADDR>
+get_frame_pc_if_available (const frame_info_ptr &frame)
{
+ std::optional<CORE_ADDR> pc;
gdb_assert (frame->next != NULL);
try
{
- *pc = frame_unwind_pc (frame_info_ptr (frame->next));
+ pc = frame_unwind_pc (frame_info_ptr (frame->next));
}
catch (const gdb_exception_error &ex)
{
- if (ex.error == NOT_AVAILABLE_ERROR)
- return false;
- else
+ if (ex.error != NOT_AVAILABLE_ERROR)
throw;
}
- return true;
+ return pc;
}
/* Return an address that falls within THIS_FRAME's code block. */
@@ -2855,7 +2902,7 @@ find_frame_sal (const frame_info_ptr &frame)
{
frame_info_ptr next_frame;
int notcurrent;
- CORE_ADDR pc;
+ std::optional<CORE_ADDR> pc;
if (frame_inlined_callees (frame) > 0)
{
@@ -2899,11 +2946,11 @@ find_frame_sal (const frame_info_ptr &frame)
PC and such a PC indicates the current (rather than next)
instruction/line, consequently, for such cases, want to get the
line containing fi->pc. */
- if (!get_frame_pc_if_available (frame, &pc))
+ if (!(pc = get_frame_pc_if_available (frame)))
return {};
- notcurrent = (pc != get_frame_address_in_block (frame));
- return find_pc_line (pc, notcurrent);
+ notcurrent = (*pc != get_frame_address_in_block (frame));
+ return find_sal_for_pc (*pc, notcurrent);
}
/* Per "frame.h", return the ``address'' of the frame. Code should
@@ -3130,7 +3177,7 @@ get_frame_language (const frame_info_ptr &frame)
if (pc_p)
{
- struct compunit_symtab *cust = find_pc_compunit_symtab (pc);
+ struct compunit_symtab *cust = find_compunit_symtab_for_pc (pc);
if (cust != NULL)
return cust->language ();
@@ -3409,14 +3456,10 @@ frame_info_ptr::reinflate () const
return m_ptr;
}
-void _initialize_frame ();
-void
-_initialize_frame ()
+INIT_GDB_FILE (frame)
{
obstack_init (&frame_cache_obstack);
- frame_stash_create ();
-
gdb::observers::target_changed.attach (frame_observer_target_changed,
"frame");