gdb/dwarf2-frame-tailcall.c - gdb
Global variables defined
Data types defined
Functions defined
Source code
- #include "defs.h"
- #include "frame.h"
- #include "dwarf2-frame-tailcall.h"
- #include "dwarf2loc.h"
- #include "frame-unwind.h"
- #include "block.h"
- #include "hashtab.h"
- #include "gdbtypes.h"
- #include "regcache.h"
- #include "value.h"
- #include "dwarf2-frame.h"
- static htab_t cache_htab;
- struct tailcall_cache
- {
-
- struct frame_info *next_bottom_frame;
-
- int refc;
-
- struct call_site_chain *chain;
-
- int chain_levels;
-
- CORE_ADDR prev_pc;
-
- unsigned prev_sp_p : 1;
- CORE_ADDR prev_sp;
- LONGEST entry_cfa_sp_offset;
- };
- static hashval_t
- cache_hash (const void *arg)
- {
- const struct tailcall_cache *cache = arg;
- return htab_hash_pointer (cache->next_bottom_frame);
- }
- static int
- cache_eq (const void *arg1, const void *arg2)
- {
- const struct tailcall_cache *cache1 = arg1;
- const struct tailcall_cache *cache2 = arg2;
- return cache1->next_bottom_frame == cache2->next_bottom_frame;
- }
- static struct tailcall_cache *
- cache_new_ref1 (struct frame_info *next_bottom_frame)
- {
- struct tailcall_cache *cache;
- void **slot;
- cache = xzalloc (sizeof (*cache));
- cache->next_bottom_frame = next_bottom_frame;
- cache->refc = 1;
- slot = htab_find_slot (cache_htab, cache, INSERT);
- gdb_assert (*slot == NULL);
- *slot = cache;
- return cache;
- }
- static void
- cache_ref (struct tailcall_cache *cache)
- {
- gdb_assert (cache->refc > 0);
- cache->refc++;
- }
- static void
- cache_unref (struct tailcall_cache *cache)
- {
- gdb_assert (cache->refc > 0);
- if (!--cache->refc)
- {
- gdb_assert (htab_find_slot (cache_htab, cache, NO_INSERT) != NULL);
- htab_remove_elt (cache_htab, cache);
- xfree (cache->chain);
- xfree (cache);
- }
- }
- static int
- frame_is_tailcall (struct frame_info *fi)
- {
- return frame_unwinder_is (fi, &dwarf2_tailcall_frame_unwind);
- }
- static struct tailcall_cache *
- cache_find (struct frame_info *fi)
- {
- struct tailcall_cache *cache;
- void **slot;
- while (frame_is_tailcall (fi))
- {
- fi = get_next_frame (fi);
- gdb_assert (fi != NULL);
- }
- slot = htab_find_slot (cache_htab, &fi, NO_INSERT);
- if (slot == NULL)
- return NULL;
- cache = *slot;
- gdb_assert (cache != NULL);
- return cache;
- }
- static int
- existing_next_levels (struct frame_info *this_frame,
- struct tailcall_cache *cache)
- {
- int retval = (frame_relative_level (this_frame)
- - frame_relative_level (cache->next_bottom_frame) - 1);
- gdb_assert (retval >= -1);
- return retval;
- }
- static int
- pretended_chain_levels (struct call_site_chain *chain)
- {
- int chain_levels;
- gdb_assert (chain != NULL);
- if (chain->callers == chain->length && chain->callees == chain->length)
- return chain->length;
- chain_levels = chain->callers + chain->callees;
- gdb_assert (chain_levels < chain->length);
- return chain_levels;
- }
- static void
- tailcall_frame_this_id (struct frame_info *this_frame, void **this_cache,
- struct frame_id *this_id)
- {
- struct tailcall_cache *cache = *this_cache;
- struct frame_info *next_frame;
-
- next_frame = get_next_frame (this_frame);
- gdb_assert (next_frame != NULL);
- *this_id = get_frame_id (next_frame);
- (*this_id).code_addr = get_frame_pc (this_frame);
- (*this_id).code_addr_p = 1;
- (*this_id).artificial_depth = (cache->chain_levels
- - existing_next_levels (this_frame, cache));
- gdb_assert ((*this_id).artificial_depth > 0);
- }
- static CORE_ADDR
- pretend_pc (struct frame_info *this_frame, struct tailcall_cache *cache)
- {
- int next_levels = existing_next_levels (this_frame, cache);
- struct call_site_chain *chain = cache->chain;
- gdb_assert (chain != NULL);
- next_levels++;
- gdb_assert (next_levels >= 0);
- if (next_levels < chain->callees)
- return chain->call_site[chain->length - next_levels - 1]->pc;
- next_levels -= chain->callees;
-
- if (chain->callees != chain->length)
- {
- if (next_levels < chain->callers)
- return chain->call_site[chain->callers - next_levels - 1]->pc;
- next_levels -= chain->callers;
- }
- gdb_assert (next_levels == 0);
- return cache->prev_pc;
- }
- struct value *
- dwarf2_tailcall_prev_register_first (struct frame_info *this_frame,
- void **tailcall_cachep, int regnum)
- {
- struct gdbarch *this_gdbarch = get_frame_arch (this_frame);
- struct tailcall_cache *cache = *tailcall_cachep;
- CORE_ADDR addr;
- if (regnum == gdbarch_pc_regnum (this_gdbarch))
- addr = pretend_pc (this_frame, cache);
- else if (cache->prev_sp_p && regnum == gdbarch_sp_regnum (this_gdbarch))
- {
- int next_levels = existing_next_levels (this_frame, cache);
- if (next_levels == cache->chain_levels - 1)
- addr = cache->prev_sp;
- else
- addr = dwarf2_frame_cfa (this_frame) - cache->entry_cfa_sp_offset;
- }
- else
- return NULL;
- return frame_unwind_got_address (this_frame, regnum, addr);
- }
- static struct value *
- tailcall_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- struct tailcall_cache *cache = *this_cache;
- struct value *val;
- gdb_assert (this_frame != cache->next_bottom_frame);
- val = dwarf2_tailcall_prev_register_first (this_frame, this_cache, regnum);
- if (val)
- return val;
- return frame_unwind_got_register (this_frame, regnum, regnum);
- }
- static int
- tailcall_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame, void **this_cache)
- {
- struct frame_info *next_frame;
- int next_levels;
- struct tailcall_cache *cache;
-
- next_frame = get_next_frame (this_frame);
- if (next_frame == NULL)
- return 0;
- cache = cache_find (next_frame);
- if (cache == NULL)
- return 0;
- cache_ref (cache);
- next_levels = existing_next_levels (this_frame, cache);
-
- gdb_assert (next_levels >= 0);
- gdb_assert (next_levels <= cache->chain_levels);
- if (next_levels == cache->chain_levels)
- {
- cache_unref (cache);
- return 0;
- }
- *this_cache = cache;
- return 1;
- }
- void
- dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
- void **tailcall_cachep,
- const LONGEST *entry_cfa_sp_offsetp)
- {
- CORE_ADDR prev_pc = 0, prev_sp = 0;
- int prev_sp_p = 0;
- CORE_ADDR this_pc;
- struct gdbarch *prev_gdbarch;
- struct call_site_chain *chain = NULL;
- struct tailcall_cache *cache;
- volatile struct gdb_exception except;
- gdb_assert (*tailcall_cachep == NULL);
-
- this_pc = get_frame_address_in_block (this_frame);
-
- TRY_CATCH (except, RETURN_MASK_ERROR)
- {
- int sp_regnum;
- prev_gdbarch = frame_unwind_arch (this_frame);
-
- prev_pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
-
- chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);
- if (entry_cfa_sp_offsetp == NULL)
- break;
- sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
- if (sp_regnum == -1)
- break;
- prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
- prev_sp_p = 1;
- }
- if (except.reason < 0)
- {
- if (entry_values_debug)
- exception_print (gdb_stdout, except);
- return;
- }
-
- if (chain == NULL || chain->length == 0)
- {
- xfree (chain);
- return;
- }
- cache = cache_new_ref1 (this_frame);
- *tailcall_cachep = cache;
- cache->chain = chain;
- cache->prev_pc = prev_pc;
- cache->chain_levels = pretended_chain_levels (chain);
- cache->prev_sp_p = prev_sp_p;
- if (cache->prev_sp_p)
- {
- cache->prev_sp = prev_sp;
- cache->entry_cfa_sp_offset = *entry_cfa_sp_offsetp;
- }
- gdb_assert (cache->chain_levels > 0);
- }
- static void
- tailcall_frame_dealloc_cache (struct frame_info *self, void *this_cache)
- {
- struct tailcall_cache *cache = this_cache;
- cache_unref (cache);
- }
- static struct gdbarch *
- tailcall_frame_prev_arch (struct frame_info *this_frame,
- void **this_prologue_cache)
- {
- struct tailcall_cache *cache = *this_prologue_cache;
- return get_frame_arch (cache->next_bottom_frame);
- }
- const struct frame_unwind dwarf2_tailcall_frame_unwind =
- {
- TAILCALL_FRAME,
- default_frame_unwind_stop_reason,
- tailcall_frame_this_id,
- tailcall_frame_prev_register,
- NULL,
- tailcall_frame_sniffer,
- tailcall_frame_dealloc_cache,
- tailcall_frame_prev_arch
- };
- extern initialize_file_ftype _initialize_tailcall_frame;
- void
- _initialize_tailcall_frame (void)
- {
- cache_htab = htab_create_alloc (50, cache_hash, cache_eq, NULL, xcalloc,
- xfree);
- }