Skip to content

Commit

Permalink
gdb: call frame unwinders' dealloc_cache methods through destroying t…
Browse files Browse the repository at this point in the history
…he frame cache

Currently, some frame resources are deallocated by iterating on the
frame chain (starting from the sentinel), calling dealloc_cache.  The
problem is that user-created frames are not part of that chain, so we
never call dealloc_cache for them.

I propose to make it so the dealloc_cache callbacks are called when the
frames are removed from the frame_stash hash table, by registering a
deletion function to the hash table.  This happens when
frame_stash_invalidate is called by reinit_frame_cache.  This way, all
frames registered in the cache will get their unwinder's dealloc_cache
callbacks called.

Note that at the moment, the sentinel frames are not registered in the
cache, so we won't call dealloc_cache for them.  However, it's just a
theoritical problem, because the sentinel frame unwinder does not
provide this callback.  Also, a subsequent patch will change things so
that sentinel frames are registered to the cache.

I moved the obstack_free / obstack_init pair below the
frame_stash_invalidate call in reinit_frame_cache, because I assumed
that some dealloc_cache would need to access some data on that obstack,
so it would be better to free it after clearing the hash table.

Change-Id: If4f9b38266b458c4e2f7eb43e933090177c22190
  • Loading branch information
simark committed Feb 8, 2023
1 parent dcee6fb commit 6d3717d
Showing 1 changed file with 24 additions and 15 deletions.
39 changes: 24 additions & 15 deletions gdb/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,22 @@ frame_addr_hash_eq (const void *a, const void *b)
return f_entry->this_id.value == f_element->this_id.value;
}

/* Deletion function for the frame cache hash table. */

static void
frame_info_del (void *frame_v)
{
frame_info *frame = (frame_info *) frame_v;

if (frame->prologue_cache != nullptr
&& frame->unwind->dealloc_cache != nullptr)
frame->unwind->dealloc_cache (frame, frame->prologue_cache);

if (frame->base_cache != nullptr
&& frame->base->unwind->dealloc_cache != nullptr)
frame->base->unwind->dealloc_cache (frame, frame->base_cache);
}

/* Internal function to create the frame_stash hash table. 100 seems
to be a good compromise to start the hash table at. */

Expand All @@ -268,7 +284,7 @@ frame_stash_create (void)
frame_stash = htab_create (100,
frame_addr_hash,
frame_addr_hash_eq,
NULL);
frame_info_del);
}

/* Internal function to add a frame to the frame_stash hash table.
Expand Down Expand Up @@ -2048,26 +2064,19 @@ reinit_frame_cache (void)
{
++frame_cache_generation;

/* Tear down all frame caches. */
for (frame_info *fi = sentinel_frame; fi != NULL; fi = fi->prev)
{
if (fi->prologue_cache && fi->unwind->dealloc_cache)
fi->unwind->dealloc_cache (fi, fi->prologue_cache);
if (fi->base_cache && fi->base->unwind->dealloc_cache)
fi->base->unwind->dealloc_cache (fi, fi->base_cache);
}

/* Since we can't really be sure what the first object allocated was. */
obstack_free (&frame_cache_obstack, 0);
obstack_init (&frame_cache_obstack);

if (sentinel_frame != NULL)
annotate_frames_invalid ();

sentinel_frame = NULL; /* Invalidate cache */
invalidate_selected_frame ();

/* Invalidate cache. */
sentinel_frame = NULL;
frame_stash_invalidate ();

/* Since we can't really be sure what the first object allocated was. */
obstack_free (&frame_cache_obstack, 0);
obstack_init (&frame_cache_obstack);

for (frame_info_ptr &iter : frame_info_ptr::frame_list)
iter.invalidate ();

Expand Down

0 comments on commit 6d3717d

Please sign in to comment.