Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions coregrind/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ COREGRIND_SOURCES_COMMON = \
m_debuginfo/d3basics.c \
m_debuginfo/debuginfo.c \
m_debuginfo/image.c \
m_debuginfo/inltab_lookup.c \
m_debuginfo/minilzo-inl.c \
m_debuginfo/readdwarf.c \
m_debuginfo/readdwarf3.c \
Expand Down
15 changes: 8 additions & 7 deletions coregrind/m_debuginfo/debuginfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "priv_d3basics.h" /* ML_(pp_GX) */
#include "priv_tytypes.h"
#include "priv_storage.h"
#include "priv_inltab_lookup.h"
#include "priv_readdwarf.h"
#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
# include "priv_readelf.h"
Expand Down Expand Up @@ -345,6 +346,7 @@ static void free_DebugInfo ( DebugInfo* di )
if (di->loctab) ML_(dinfo_free)(di->loctab);
if (di->loctab_fndn_ix) ML_(dinfo_free)(di->loctab_fndn_ix);
if (di->inltab) ML_(dinfo_free)(di->inltab);
if (di->inltab_lookup) VG_(inltab_lookup_cleanup)(di->inltab_lookup);
if (di->cfsi_base) ML_(dinfo_free)(di->cfsi_base);
if (di->cfsi_m_ix) ML_(dinfo_free)(di->cfsi_m_ix);
if (di->cfsi_rd) ML_(dinfo_free)(di->cfsi_rd);
Expand Down Expand Up @@ -2388,13 +2390,12 @@ Bool VG_(get_inline_fnname) ( DiEpoch ep, Addr a, const HChar** inl_fnname )
return False;

/* Search the inline table for an entry containing this address */
/* We search from the end backwards to find the innermost inline function first */
for (Word i = si->inltab_used - 1; i >= 0; i--) {
if (si->inltab[i].addr_lo <= a && a < si->inltab[i].addr_hi) {
/* Found it! Return the inline function name */
*inl_fnname = si->inltab[i].inlinedfn;
return True;
}
/* Lookup with hash table cache and binary search fallback */
Word inl_idx;
if (VG_(inltab_lookup_get)(si->inltab_lookup, a, &inl_idx, si)) {
/* Found it! Return the inline function name */
*inl_fnname = si->inltab[inl_idx].inlinedfn;
return True;
}

return False;
Expand Down
124 changes: 124 additions & 0 deletions coregrind/m_debuginfo/inltab_lookup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* VgHashTable-based implementation for inline lookup table.
Maps addresses to inline function info indices. */

#include "pub_core_basics.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
#include "pub_core_mallocfree.h"
#include "pub_core_hashtable.h"
#include "priv_storage.h"

/* Node structure for VgHashTable
Extends VgHashNode with our key (Addr) and value (Word) */
typedef struct {
VgHashNode node; /* Must be first for VgHashTable API */
Word value; /* The inline table index */
} InlLookupNode;

/* Binary search for an inline function entry containing address 'a'.
Uses the sorted inltab array to efficiently find candidates.
Returns the index of the matching entry, or -1 if not found.

The inltab is sorted by addr_lo, so we:
1. Binary search to find entries where addr_lo <= a
2. Scan backwards to find an entry that contains address a
(this finds the innermost inline function if multiple are nested)
*/
static Word binary_search_inltab(const DebugInfo* di, Addr a) {
if (di == NULL || di->inltab == NULL || di->inltab_used == 0)
return -1;

Word lo = 0, hi = di->inltab_used;

/* Binary search: find the first entry where addr_lo > a */
while (lo < hi) {
Word mid = lo + (hi - lo) / 2;
if (a < di->inltab[mid].addr_lo) {
hi = mid;
} else {
lo = mid + 1;
}
}

/* lo now points to the first entry where addr_lo > a.
Search backwards from lo-1 to find an entry that contains address a */
for (Word i = lo - 1; i >= 0; i--) {
if (di->inltab[i].addr_lo <= a && a < di->inltab[i].addr_hi) {
/* Found it! Return the index */
return i;
}
/* Since we're scanning backwards through sorted addr_lo entries,
if we encounter an addr_hi <= a, we can stop as we've passed
the potential range */
if (di->inltab[i].addr_hi <= a) {
break;
}
}

return -1;
}

/* Public API for inline lookup table */

VgHashTable *VG_(inltab_lookup_new)(void) {
return VG_(HT_construct)("inltab_lookup");
}

void VG_(inltab_lookup_insert)(VgHashTable *ht, Addr addr, Word inl_idx) {
if (ht == NULL)
ht = VG_(inltab_lookup_new)();

/* Check if entry already exists */
InlLookupNode *existing = VG_(HT_lookup)(ht, (UWord)addr);
if (existing) {
/* Update existing value */
existing->value = inl_idx;
return;
}

/* Allocate new node */
InlLookupNode *node = VG_(malloc)("di.inltab_vghash.node", sizeof(InlLookupNode));
if (!node)
return;
node->node.key = (UWord)addr;
node->value = inl_idx;

VG_(HT_add_node)(ht, node);
}

/* Enhanced lookup that combines hash table lookup with binary search fallback.
First tries the hash table for exact addr_lo matches.
If not found, uses binary search on the sorted inltab array.
If found via binary search, caches the result in the hash table.
*/
Bool VG_(inltab_lookup_get)(VgHashTable *ht, Addr addr, Word *inl_idx,
const DebugInfo* di) {
if (ht == NULL)
return False;

/* Try hash table lookup first */
InlLookupNode *node = VG_(HT_lookup)(ht, (UWord)addr);
if (node) {
*inl_idx = node->value;
return True;
}

/* Hash table miss, try binary search on the inltab array */
Word idx = binary_search_inltab(di, addr);
if (idx >= 0) {
/* Found via binary search, cache it for future lookups */
*inl_idx = idx;
VG_(inltab_lookup_insert)(ht, addr, idx);
return True;
}

return False;
}

void VG_(inltab_lookup_cleanup)(VgHashTable *ht) {
if (ht == NULL)
return;

/* Free all nodes */
VG_(HT_destruct)(ht, VG_(free));
}
13 changes: 13 additions & 0 deletions coregrind/m_debuginfo/priv_inltab_lookup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef __PRIV_INLTAB_LOOKUP_H
#define __PRIV_INLTAB_LOOKUP_H

#include "pub_core_basics.h"
#include "pub_tool_hashtable.h"

extern VgHashTable *VG_(inltab_lookup_new)(void);
extern void VG_(inltab_lookup_insert)(VgHashTable *ht, Addr addr, Word inl_idx);
extern Bool VG_(inltab_lookup_get)(VgHashTable *ht, Addr addr, Word *inl_idx,
const DebugInfo *di);
extern void VG_(inltab_lookup_cleanup)(VgHashTable *ht);

#endif
5 changes: 5 additions & 0 deletions coregrind/m_debuginfo/priv_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "pub_core_basics.h" // Addr
#include "pub_core_xarray.h" // XArray
#include "pub_core_deduppoolalloc.h" // DedupPoolAlloc
#include "pub_tool_hashtable.h" // VgHashTable
#include "priv_d3basics.h" // GExpr et al.
#include "priv_image.h" // DiCursor

Expand Down Expand Up @@ -953,6 +954,10 @@ struct _DebugInfo {
UWord inltab_size;
SizeT maxinl_codesz;

/* Hash table for O(1) inline lookups by address.
Maps arbitrary addresses to indices in inltab; populated on-demand during lookups for cache efficiency. */
VgHashTable* inltab_lookup;

/* A set of expandable arrays to store CFI summary info records.
The machine specific information (i.e. the DiCfSI_m struct)
are stored in cfsi_m_pool, as these are highly duplicated.
Expand Down
5 changes: 5 additions & 0 deletions coregrind/m_debuginfo/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "priv_d3basics.h" /* ML_(pp_GX) */
#include "priv_tytypes.h"
#include "priv_storage.h" /* self */
#include "priv_inltab_lookup.h"


/*------------------------------------------------------------*/
Expand Down Expand Up @@ -2164,6 +2165,10 @@ static void canonicaliseInltab ( struct _DebugInfo* di )

/* Free up unused space at the end of the table. */
shrinkInlTab(di);

if (di->inltab_lookup == NULL) {
di->inltab_lookup = VG_(inltab_lookup_new)();
}
}


Expand Down
Loading