diff options
Diffstat (limited to 'gdb/frame.c')
| -rw-r--r-- | gdb/frame.c | 259 |
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"); |
