* Error messages about fishy arguments (formerly known as silly arguments)
now include a back-trace to aid debugging.
+* Reduction of memory used by Valgrind to read and store the debug information.
+
* ==================== FIXED BUGS ====================
The following bugs have been fixed or resolved. Note that "n-i-bz"
if (di->fsm.filename) ML_(dinfo_free)(di->fsm.filename);
if (di->soname) ML_(dinfo_free)(di->soname);
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->cfsi_base) ML_(dinfo_free)(di->cfsi_base);
if (di->cfsi_m_ix) ML_(dinfo_free)(di->cfsi_m_ix);
if (di->strpool)
VG_(deleteDedupPA) (di->strpool);
+ if (di->fndnpool)
+ VG_(deleteDedupPA) (di->fndnpool);
/* Delete the two admin arrays. These lists exist primarily so
that we can visit each object exactly once when we need to
{
DebugInfo* si;
Word locno;
+ UInt fndn_ix;
+ FnDn* fndn;
+
search_all_loctabs ( a, &si, &locno );
if (si == NULL)
return False;
- VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
+ fndn_ix = ML_(fndn_ix) (si, locno);
+ if (fndn_ix == 0)
+ VG_(strncpy_safely)(filename, "???", n_filename);
+ else {
+ fndn = VG_(indexEltNumber) (si->fndnpool, fndn_ix);
+ VG_(strncpy_safely)(filename, fndn->filename, n_filename);
+ }
return True;
}
{
DebugInfo* si;
Word locno;
+ UInt fndn_ix;
+ FnDn* fndn = NULL;
vg_assert( (dirname == NULL && dirname_available == NULL)
||
return False;
}
- VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
+ fndn_ix = ML_(fndn_ix)(si, locno);
+ if (fndn_ix == 0)
+ VG_(strncpy_safely)(filename, "???", n_filename);
+ else {
+ fndn = VG_(indexEltNumber) (si->fndnpool, fndn_ix);
+ VG_(strncpy_safely)(filename, fndn->filename, n_filename);
+ }
*lineno = si->loctab[locno].lineno;
if (dirname) {
/* caller wants directory info too .. */
vg_assert(n_dirname > 0);
- if (si->loctab[locno].dirname) {
+ if (fndn_ix != 0 && fndn->dirname) {
/* .. and we have some */
*dirname_available = True;
- VG_(strncpy_safely)(dirname, si->loctab[locno].dirname,
- n_dirname);
+ VG_(strncpy_safely)(dirname, fndn->dirname, n_dirname);
} else {
/* .. but we don't have any */
*dirname_available = False;
VG_(snprintf) (buf_srcloc, BUF_LEN, "%s", cur_inl->filename);
lineno = cur_inl->lineno;
- know_dirinfo = False; //INLINED TBD
-
+ know_dirinfo = False;
know_srcloc = True;
}
*/
#define OVERFLOW_DIFFERENCE (LINENO_OVERFLOW - 5000)
+/* Filename and Dirname pair. FnDn are stored in di->fndnpool
+ and are allocated using VG_(allocFixedEltDedupPA).
+ The filename/dirname strings are themselves stored in di->strpool. */
+typedef
+ struct {
+ const HChar* filename; /* source filename */
+ const HChar* dirname; /* source directory name */
+ } FnDn;
+
/* A structure to hold addr-to-source info for a single line. There
can be a lot of these, hence the dense packing. */
typedef
/* Word 2 */
UShort size:LOC_SIZE_BITS; /* # bytes; we catch overflows of this */
UInt lineno:LINENO_BITS; /* source line number, or zero */
- /* Word 3 */
- const HChar* filename; /* source filename */
- /* Word 4 */
- const HChar* dirname; /* source directory name */
}
DiLoc;
#define MAX_LEVEL ((1 << LEVEL_BITS) - 1)
/* A structure to hold addr-to-inlined fn info. There
- can be a lot of these, hence the dense packing. */
+ can be a lot of these, hence the dense packing.
+ Only caller source filename and lineno are stored.
+ Handling dirname should be done using fndn_ix technique
+ similar to ML_(addLineInfo). */
typedef
struct {
/* Word 1 */
/* Word 4 */
const HChar* filename; /* caller source filename */
/* Word 5 */
- const HChar* dirname; /* caller source directory name */
- /* Word 6 */
UInt lineno:LINENO_BITS; /* caller line number */
UShort level:LEVEL_BITS; /* level of inlining */
}
DiSym* symtab;
UWord symtab_used;
UWord symtab_size;
- /* An expandable array of locations. */
+ /* Two expandable arrays, storing locations and their filename/dirname. */
DiLoc* loctab;
+ UInt sizeof_fndn_ix; /* Similar use as sizeof_cfsi_m_ix below. */
+ void* loctab_fndn_ix; /* loctab[i] filename/dirname is identified by
+ loctab_fnindex_ix[i] (an index in di->fndnpool)
+ 0 means filename/dirname unknown.
+ The void* is an UChar* or UShort* or UInt*
+ depending on sizeof_fndn_ix. */
UWord loctab_used;
UWord loctab_size;
/* An expandable array of inlined fn info.
For each base in cfsi_base, an index into cfsi_m_pool is stored
in cfsi_m_ix array. The size of cfsi_m_ix is equal to
- cfsi_size*sizeof_ix. The used portion of cfsi_m_ix is
- cfsi_m_ix[0] till cfsi_m_ix[(cfsi_used-1)*sizeof_ix].
+ cfsi_size*sizeof_cfsi_m_ix. The used portion of cfsi_m_ix is
+ cfsi_m_ix[0] till cfsi_m_ix[(cfsi_used-1)*sizeof_cfsi_m_ix].
cfsi_base[i] gives the base address of a code range covered by
some CF Info. The corresponding CF Info is identified by an index
in cfsi_m_pool. The DiCfSI_m index in cfsi_m_pool corresponding to
cfsi_base[i] is given
- by ((UChar*) cfsi_m_ix)[i] if sizeof_ix == 1
- by ((UShort*)cfsi_m_ix)[i] if sizeof_ix == 2
- by ((UInt*) cfsi_m_ix)[i] if sizeof_ix == 4.
+ by ((UChar*) cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 1
+ by ((UShort*)cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 2
+ by ((UInt*) cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 4.
The end of the code range starting at cfsi_base[i] is given by
cfsi_base[i+1]-1 (or cfsi_maxavma for cfsi_base[cfsi_used-1]).
records require any expression nodes, they are stored in
cfsi_exprs. */
Addr* cfsi_base;
- UInt sizeof_ix; /* size in byte of the indexes stored in cfsi_m_ix. */
- void* cfsi_m_ix; /* Each index occupies sizeof_ix bytes. */
+ UInt sizeof_cfsi_m_ix; /* size in byte of indexes stored in cfsi_m_ix. */
+ UInt* cfsi_m_ix; /* Each index occupies sizeof_cfsi_m_ix bytes. */
DiCfSI* cfsi_rd; /* Only used during reading, NULL once info is read. */
into this are stable (the memory is not reallocated). */
DedupPoolAlloc *strpool;
+ /* Pool of FnDn -- filename and dirname.
+ Elements in the pool are allocated using VG_(allocFixedEltDedupPA). */
+ DedupPoolAlloc *fndnpool;
+
/* Variable scope information, as harvested from Dwarf3 files.
In short it's an
to ensure that's OK. */
extern void ML_(addSym) ( struct _DebugInfo* di, DiSym* sym );
-/* Add a line-number record to a DebugInfo. */
+/* Add a filename/dirname pair to a DebugInfo and returns the index
+ in the fndnpool fixed pool. */
+extern UInt ML_(addFnDn) (struct _DebugInfo* di,
+ const HChar* filename,
+ const HChar* dirname); /* NULL is allowable */
+
+/* Returns the fndn_ix for the LineInfo locno in di->loctab.
+ 0 if filename/dirname are unknown. */
+extern UInt ML_(fndn_ix) (struct _DebugInfo* di, Word locno);
+
+/* Add a line-number record to a DebugInfo.
+ fndn_ix is an index in di->fndnpool, allocated using ML_(addFnDn).
+ Give a 0 index for a unknown filename/dirname pair. */
extern
void ML_(addLineInfo) ( struct _DebugInfo* di,
- const HChar* filename,
- const HChar* dirname, /* NULL is allowable */
+ UInt fndn_ix,
Addr this, Addr next, Int lineno, Int entry);
/* Add a call inlined record to a DebugInfo.
A call to the below means that inlinedfn code has been
inlined, resulting in code from [addr_lo, addr_hi[.
Note that addr_hi is excluded, i.e. is not part of the inlined code.
- The call that caused this inlining is in filename/dirname/lineno
+ The call that caused this inlining is in filename/lineno (dirname
+ is not recorded).
In case of nested inlining, a small level indicates the call
is closer to main that a call with a higher level. */
extern
Addr addr_lo, Addr addr_hi,
const HChar* inlinedfn,
const HChar* filename,
- const HChar* dirname, /* NULL is allowable */
Int lineno, UShort level);
/* Add a CFI summary record. The supplied DiCfSI_m is copied. */
/*--- ---*/
/*------------------------------------------------------------*/
-/*------------------------------------------------------------*/
-/*--- Expanding arrays of words, for holding file name and ---*/
-/*--- directory name arrays. ---*/
-/*------------------------------------------------------------*/
-
-typedef
- struct {
- Word* tab;
- UInt tab_size;
- UInt tab_used;
- }
- WordArray;
-
-static void init_WordArray ( WordArray* wa )
-{
- wa->tab = NULL;
- wa->tab_size = 0;
- wa->tab_used = 0;
-}
-
-static void free_WordArray ( WordArray* wa )
-{
- if (wa->tab) {
- vg_assert(wa->tab_size > 0);
- ML_(dinfo_free)(wa->tab);
- }
- init_WordArray(wa);
-}
-
-static void addto_WordArray ( WordArray* wa, Word w )
+/* The below "safe_*ix" functions allow to resist to malformed dwarf info:
+ if dwarf info contains wrong file or dirname indexes, these are (silently!)
+ ignored. */
+
+/* if xa_ix is a valid index in fndn_ix_xa,
+ return the element (i.e. the UInt indexing in fndnpool).
+ If xa_ix is invalid, return 0 (i.e. the "null" element in fndnpool). */
+static UInt safe_fndn_ix (XArray* fndn_ix_xa, Int xa_ix)
{
- UInt new_size, i;
- Word* new_tab;
-
- if (0) VG_(printf)("<<ADD %p (new sz = %d) >>\n",
- (HChar*)w, wa->tab_used+1);
-
- if (wa->tab_used < wa->tab_size) {
- /* fine */
- } else {
- /* expand array */
- if (0) VG_(printf)("EXPAND ARRAY from %d\n", wa->tab_size);
- vg_assert(wa->tab_used == wa->tab_size);
- vg_assert( (wa->tab_size == 0 && wa->tab == NULL)
- || (wa->tab_size != 0 && wa->tab != NULL) );
- new_size = wa->tab_size == 0 ? 8 : 2 * wa->tab_size;
- new_tab = ML_(dinfo_zalloc)("di.aWA.1", new_size * sizeof(Word));
- vg_assert(new_tab != NULL);
- for (i = 0; i < wa->tab_used; i++)
- new_tab[i] = wa->tab[i];
- wa->tab_size = new_size;
- if (wa->tab)
- ML_(dinfo_free)(wa->tab);
- wa->tab = new_tab;
- }
-
- vg_assert(wa->tab_used < wa->tab_size);
- vg_assert(wa->tab_size > 0);
- wa->tab[wa->tab_used] = w;
- wa->tab_used++;
+ if (xa_ix < 0) return 0;
+ if (xa_ix >= VG_(sizeXA) (fndn_ix_xa)) return 0;
+ return *(UInt*)VG_(indexXA) ( fndn_ix_xa, xa_ix );
}
-static Word index_WordArray ( /*OUT*/Bool* inRange, WordArray* wa, Int i )
+/* if xa_ix is a valid index in dirname_xa,
+ return the element (i.e. the HChar*).
+ If xa_ix is invalid, return NULL. */
+static HChar* safe_dirname_ix (XArray* dirname_xa, Int xa_ix)
{
- vg_assert(inRange);
- if (i >= 0 && i < wa->tab_used) {
- *inRange = True;
- return wa->tab[i];
- } else {
- *inRange = False;
- return 0;
- }
+ if (xa_ix < 0) return NULL;
+ if (xa_ix >= VG_(sizeXA) (dirname_xa)) return NULL;
+ return *(HChar**)VG_(indexXA) ( dirname_xa, xa_ix );
}
-
/*------------------------------------------------------------*/
/*--- Read DWARF2 format line number info. ---*/
/*------------------------------------------------------------*/
state_machine_regs.end_sequence = 0;
}
-/* Look up a directory name, or return NULL if unknown. */
-static
-HChar* lookupDir ( Int filename_index,
- WordArray* fnidx2dir,
- WordArray* dirnames )
-{
- Bool inRange;
- Word diridx, dirname;
-
- diridx = index_WordArray( &inRange, fnidx2dir, filename_index );
- if (!inRange) goto bad;
-
- dirname = index_WordArray( &inRange, dirnames, (Int)diridx );
- if (!inRange) goto bad;
-
- return (HChar*)dirname;
- bad:
- return NULL;
-}
-
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
accordingly. */
static
void process_extended_line_op( struct _DebugInfo* di,
- WordArray* filenames,
- WordArray* dirnames,
- WordArray* fnidx2dir,
+ XArray* fndn_ix_xa,
DiCursor* data, Int is_stmt)
{
UInt len = step_leb128U(data);
if (state_machine_regs.is_stmt) {
if (state_machine_regs.last_address) {
- Bool inRange = False;
- const HChar* filename
- = (HChar*)index_WordArray( &inRange, filenames,
- state_machine_regs.last_file);
- if (!inRange || !filename)
- filename = "???";
ML_(addLineInfo) (
- di,
- filename,
- lookupDir( state_machine_regs.last_file,
- fnidx2dir, dirnames ),
+ di,
+ safe_fndn_ix (fndn_ix_xa,
+ state_machine_regs.last_file),
di->text_debug_bias + state_machine_regs.last_address,
di->text_debug_bias + state_machine_regs.address,
state_machine_regs.last_line, 0
case DW_LNE_define_file: {
HChar* name = ML_(cur_step_strdup)(data, "di.pelo.1");
- addto_WordArray( filenames, (Word)ML_(addStr)(di,name,-1) );
+ UInt fndn_ix = ML_(addFnDn) (di, name, NULL);
+ VG_(addToXA) (fndn_ix_xa, &fndn_ix);
ML_(dinfo_free)(name);
(void)step_leb128U(data); // ignored: dir index
(void)step_leb128U(data); // ignored: mod time
Int i;
DebugLineInfo info;
Bool is64;
- WordArray filenames;
- WordArray dirnames;
- WordArray fnidx2dir;
+ XArray* fndn_ix_xa; /* xarray of UInt fndn_ix */
+ UInt fndn_ix;
+ XArray* dirname_xa; /* xarray of HChar* dirname */
+ HChar* dirname;
DiCursor external = theBlock;
DiCursor data = theBlock;
- /* filenames is an array of file names harvested from the DWARF2
- info. Entry [0] is NULL and is never referred to by the state
- machine.
+ /* fndn_ix_xa is an xarray of fndn_ix (indexes in di->fndnpool) which
+ are build from file names harvested from the DWARF2
+ info. Entry [0] is the "null" pool index and is never referred to
+ by the state machine.
- Similarly, dirnames is an array of directory names. Entry [0]
+ Similarly, dirname_xa is an xarray of directory names. Entry [0]
is also NULL and denotes "we don't know what the path is", since
that is different from "the path is the empty string". Unlike
- the file name table, the state machine does refer to entry [0],
+ the fndn_ix_xa table, the state machine does refer to entry [0],
which basically means "." ("the current directory of the
compilation", whatever that means, according to the DWARF3
spec.)
-
- fnidx2dir is an array of indexes into the dirnames table.
- (confused yet?) filenames[] and fnidx2dir[] are indexed
- together. That is, for some index i in the filename table, then
-
- the filename is filenames[i]
- the directory is dirnames[ fnidx2dir[i] ] */
+ */
/* Fails due to gcc padding ...
vg_assert(sizeof(DWARF2_External_LineInfo)
== sizeof(DWARF2_Internal_LineInfo));
*/
- init_WordArray(&filenames);
- init_WordArray(&dirnames);
- init_WordArray(&fnidx2dir);
+ dirname_xa = VG_(newXA) (ML_(dinfo_zalloc), "di.rd2l.1", ML_(dinfo_free),
+ sizeof(HChar*) );
+ fndn_ix_xa = VG_(newXA) (ML_(dinfo_zalloc), "di.rd2l.2", ML_(dinfo_free),
+ sizeof(UInt) );
/* DWARF2 starts numbering filename entries at 1, so we need to
- add a dummy zeroth entry to the table. The zeroth dirnames
- entry denotes 'current directory of compilation' so we might
- as well make the fnidx2dir zeroth entry denote that.
- */
- addto_WordArray( &filenames, (Word)NULL );
+ add a dummy zeroth entry to the table. */
+ fndn_ix = 0; // 0 is the "null" index in a fixed pool.
+ VG_(addToXA) (fndn_ix_xa, &fndn_ix);
if (ML_(cur_is_valid)(ui->compdir))
- addto_WordArray( &dirnames,
- (Word)ML_(addStrFromCursor)(di, ui->compdir) );
+ dirname = ML_(addStrFromCursor)(di, ui->compdir);
else
- addto_WordArray( &dirnames, (Word)ML_(addStr)(di, ".", -1) );
-
- addto_WordArray( &fnidx2dir, (Word)0 ); /* compilation dir */
+ dirname = ML_(addStr)(di, ".", -1);
+ VG_(addToXA) (dirname_xa, &dirname);
info.li_length = step_initial_length_field( &external, &is64 );
if (di->ddump_line)
VG_(strcat)(buf, "/");
VG_(strcat)(buf, data_str);
vg_assert(VG_(strlen)(buf) < NBUF);
- addto_WordArray( &dirnames, (Word)ML_(addStr)(di,buf,-1) );
+ dirname = ML_(addStr)(di,buf,-1);
+ VG_(addToXA) (dirname_xa, &dirname);
if (0) VG_(printf)("rel path %s\n", buf);
ML_(dinfo_free)(compdir_str);
} else {
/* just use 'data'. */
- addto_WordArray( &dirnames, (Word)ML_(addStr)(di,data_str,-1) );
+ dirname = ML_(addStr)(di,data_str,-1);
+ VG_(addToXA) (dirname_xa, &dirname);
if (0) VG_(printf)("abs path %s\n", data_str);
}
data = ML_(cur_plus)(data, 1);
/* Read the contents of the File Name table. This produces a bunch
- of file names, and for each, an index to the corresponding
- directory name entry. */
+ of fndn_ix in fndn_ix_xa. */
if (di->ddump_line) {
VG_(printf)(" The File Name Table:\n");
VG_(printf)(" Entry Dir Time Size Name\n");
Int diridx = step_leb128U(&data);
Int uu_time = step_leb128U(&data); /* unused */
Int uu_size = step_leb128U(&data); /* unused */
- addto_WordArray( &filenames, (Word)ML_(addStr)(di,name,-1) );
- addto_WordArray( &fnidx2dir, (Word)diridx );
+
+ dirname = safe_dirname_ix( dirname_xa, diridx );
+ fndn_ix = ML_(addFnDn) (di, name, dirname);
+ VG_(addToXA) (fndn_ix_xa, &fndn_ix);
if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
if (di->ddump_line)
VG_(printf)(" %d\t%d\t%d\t%d\t%s\n",
if (state_machine_regs.is_stmt) {
/* only add a statement if there was a previous boundary */
if (state_machine_regs.last_address) {
- Bool inRange = False;
- const HChar* filename
- = (HChar*)index_WordArray( &inRange, &filenames,
- state_machine_regs.last_file);
- if (!inRange || !filename)
- filename = "???";
ML_(addLineInfo)(
- di,
- filename,
- lookupDir( state_machine_regs.last_file,
- &fnidx2dir, &dirnames ),
+ di,
+ safe_fndn_ix (fndn_ix_xa,
+ state_machine_regs.last_file),
di->text_debug_bias + state_machine_regs.last_address,
di->text_debug_bias + state_machine_regs.address,
state_machine_regs.last_line,
switch (op_code) {
case DW_LNS_extended_op:
process_extended_line_op (
- di, &filenames, &dirnames, &fnidx2dir,
+ di, fndn_ix_xa,
&data, info.li_default_is_stmt);
break;
if (state_machine_regs.is_stmt) {
/* only add a statement if there was a previous boundary */
if (state_machine_regs.last_address) {
- Bool inRange = False;
- const HChar* filename
- = (HChar*)index_WordArray( &inRange, &filenames,
- state_machine_regs.last_file );
- if (!inRange || !filename)
- filename = "???";
ML_(addLineInfo)(
- di,
- filename,
- lookupDir( state_machine_regs.last_file,
- &fnidx2dir, &dirnames ),
+ di,
+ safe_fndn_ix (fndn_ix_xa,
+ state_machine_regs.last_file),
di->text_debug_bias + state_machine_regs.last_address,
di->text_debug_bias + state_machine_regs.address,
state_machine_regs.last_line,
VG_(printf)("\n");
out:
- free_WordArray(&filenames);
- free_WordArray(&dirnames);
- free_WordArray(&fnidx2dir);
+ VG_(deleteXA)(dirname_xa);
+ VG_(deleteXA)(fndn_ix_xa);
}
////////////////////////////////////////////////////////////////////
ip_lo, ip_hi1,
get_inlFnName (inlinedfn_abstract_origin, cc, td3),
caller_filename,
- NULL, // INLINED TBD dirname ?????
caller_lineno, level);
}
} else if (have_range) {
// included.
inlfnname,
caller_filename,
- NULL, // INLINED TBD dirname ?????
caller_lineno, level);
}
VG_(deleteXA)( ranges );
vg_assert(!di->cfsi_rd);
vg_assert(!di->cfsi_exprs);
vg_assert(!di->strpool);
+ vg_assert(!di->fndnpool);
vg_assert(!di->soname);
{
((const unsigned short *)(pnt2.ui + linecount))[j],
startaddr, endaddr );
ML_(addLineInfo)(
- di, fnmstr, dirstr, startaddr, endaddr,
+ di,
+ ML_(addFnDn) (di, // fndnTBD
+ fnmstr,
+ dirstr),
+ startaddr, endaddr,
((const unsigned short *)(pnt2.ui + linecount))[j], j );
n_lines_read++;
}
if (debug)
VG_(printf)("%s line %d: %08lx to %08lx\n",
pfx, lbh->l[i].lineno ^ 0x80000000, svma_s, svma_e);
- ML_(addLineInfo)( di, filename, dirname,
+ ML_(addLineInfo)( di,
+ ML_(addFnDn) (di, // fndnTBD
+ filename,
+ dirname),
bias + svma_s,
bias + svma_e + 1,
lbh->l[i].lineno ^ 0x80000000, 0 );
VG_(printf)("%s line %d: %08lx to %08lx\n",
pfx, lbh->l[ lbh->nlines-1 ].lineno ^ 0x80000000,
svma_s, svma_e);
- ML_(addLineInfo)( di, filename, dirname,
+ ML_(addLineInfo)( di,
+ ML_(addFnDn) (di, // fndnTBD
+ filename,
+ dirname),
bias + svma_s,
bias + svma_e + 1,
lbh->l[lbh->nlines-1].lineno ^ 0x80000000, 0 );
Bool first; /* first line in function */
} line = { 0, 0, 0, 0, False };
+ vg_assert (0);
+ /* Stab reader broken since debuginfo server (revision 13440)
+ See #if 0 for call to ML_(read_debuginfo_stabs) in readelf.c.
+ If ever it is repaired, file.name above should be replaced by a fndn_ix
+ for performance reasons. */
+
/* Ok. It all looks plausible. Go on and read debug data.
stab kinds: 100 N_SO a source file name
68 N_SLINE a source line number
if (line.addr != 0) {
/* finish off previous line */
- ML_(addLineInfo)(di, file.name, NULL, line.addr,
+ ML_(addLineInfo)(di,
+ ML_(addFnDn) (di,
+ file.name,
+ NULL),
+ line.addr,
addr, line.no + line.ovf * LINENO_OVERFLOW, i);
}
if (line.addr != 0) {
/* there was a previous */
- ML_(addLineInfo)(di, file.name, NULL, line.addr,
+ ML_(addLineInfo)(di,
+ ML_(addFnDn)(di,
+ file.name,
+ NULL),
+ line.addr,
addr, line.no + line.ovf * LINENO_OVERFLOW, i);
}
}
if (line.addr) {
- ML_(addLineInfo)(di, file.name, NULL, line.addr,
+ ML_(addLineInfo)(di,
+ ML_(addFnDn) (di,
+ file.name,
+ NULL),
+ line.addr,
addr, line.no + line.ovf * LINENO_OVERFLOW, i);
line.addr = 0;
}
return p;
}
+UInt ML_(addFnDn) (struct _DebugInfo* di,
+ const HChar* filename,
+ const HChar* dirname)
+{
+ FnDn fndn;
+ UInt fndn_ix;
+
+ if (UNLIKELY(di->fndnpool == NULL))
+ di->fndnpool = VG_(newDedupPA)(500,
+ vg_alignof(FnDn),
+ ML_(dinfo_zalloc),
+ "di.storage.addFnDn.1",
+ ML_(dinfo_free));
+ fndn.filename = ML_(addStr)(di, filename, -1);
+ fndn.dirname = dirname ? ML_(addStr)(di, dirname, -1) : NULL;
+ fndn_ix = VG_(allocFixedEltDedupPA) (di->fndnpool, sizeof(FnDn), &fndn);
+ return fndn_ix;
+}
/* Add a string to the string table of a DebugInfo, by copying the
string from the given DiCursor. Measures the length of the string
vg_assert(di->symtab_used <= di->symtab_size);
}
+UInt ML_(fndn_ix) (struct _DebugInfo* di, Word locno)
+{
+ UInt fndn_ix;
+
+ switch(di->sizeof_fndn_ix) {
+ case 1: fndn_ix = ((UChar*) di->loctab_fndn_ix)[locno]; break;
+ case 2: fndn_ix = ((UShort*) di->loctab_fndn_ix)[locno]; break;
+ case 4: fndn_ix = ((UInt*) di->loctab_fndn_ix)[locno]; break;
+ default: vg_assert(0);
+ }
+ return fndn_ix;
+}
+
+static inline void set_fndn_ix (struct _DebugInfo* di, Word locno, UInt fndn_ix)
+{
+ Word i;
+
+ switch(di->sizeof_fndn_ix) {
+ case 1:
+ if (LIKELY (fndn_ix <= 255)) {
+ ((UChar*) di->loctab_fndn_ix)[locno] = fndn_ix;
+ return;
+ }
+ {
+ UChar* old = (UChar*) di->loctab_fndn_ix;
+ UShort* new = ML_(dinfo_zalloc)( "di.storage.sfix.1",
+ di->loctab_size * 2 );
+ for (i = 0; i < di->loctab_used; i++)
+ new[i] = old[i];
+ ML_(dinfo_free)(old);
+ di->sizeof_fndn_ix = 2;
+ di->loctab_fndn_ix = new;
+ }
+ // Fallthrough
+
+ case 2:
+ if (LIKELY (fndn_ix <= 65535)) {
+ ((UShort*) di->loctab_fndn_ix)[locno] = fndn_ix;
+ return;
+ }
+ {
+ UShort* old = (UShort*) di->loctab_fndn_ix;
+ UInt* new = ML_(dinfo_zalloc)( "di.storage.sfix.2",
+ di->loctab_size * 4 );
+ for (i = 0; i < di->loctab_used; i++)
+ new[i] = old[i];
+ ML_(dinfo_free)(old);
+ di->sizeof_fndn_ix = 4;
+ di->loctab_fndn_ix = new;
+ }
+ // Fallthrough
+
+ case 4:
+ ((UInt*) di->loctab_fndn_ix)[locno] = fndn_ix;
+ return;
+
+ default: vg_assert(0);
+ }
+}
/* Add a location to the location table.
*/
-static void addLoc ( struct _DebugInfo* di, DiLoc* loc )
+static void addLoc ( struct _DebugInfo* di, DiLoc* loc, UInt fndn_ix )
{
- UInt new_sz, i;
- DiLoc* new_tab;
-
/* Zero-sized locs should have been ignored earlier */
vg_assert(loc->size > 0);
if (di->loctab_used == di->loctab_size) {
+ UInt new_sz;
+ DiLoc* new_loctab;
+ void* new_loctab_fndn_ix;
+
new_sz = 2 * di->loctab_size;
if (new_sz == 0) new_sz = 500;
- new_tab = ML_(dinfo_zalloc)( "di.storage.addLoc.1",
- new_sz * sizeof(DiLoc) );
+ new_loctab = ML_(dinfo_zalloc)( "di.storage.addLoc.1",
+ new_sz * sizeof(DiLoc) );
+ if (di->sizeof_fndn_ix == 0)
+ di->sizeof_fndn_ix = 1; // To start with.
+ new_loctab_fndn_ix = ML_(dinfo_zalloc)( "di.storage.addLoc.2",
+ new_sz * di->sizeof_fndn_ix );
if (di->loctab != NULL) {
- for (i = 0; i < di->loctab_used; i++)
- new_tab[i] = di->loctab[i];
+ VG_(memcpy)(new_loctab, di->loctab,
+ di->loctab_used * sizeof(DiLoc));
+ VG_(memcpy)(new_loctab_fndn_ix, di->loctab_fndn_ix,
+ di->loctab_used * di->sizeof_fndn_ix);
ML_(dinfo_free)(di->loctab);
+ ML_(dinfo_free)(di->loctab_fndn_ix);
}
- di->loctab = new_tab;
+ di->loctab = new_loctab;
+ di->loctab_fndn_ix = new_loctab_fndn_ix;
di->loctab_size = new_sz;
}
di->loctab[di->loctab_used] = *loc;
+ set_fndn_ix (di, di->loctab_used, fndn_ix);
di->loctab_used++;
vg_assert(di->loctab_used <= di->loctab_size);
}
if (new_sz == di->loctab_size) return;
vg_assert(new_sz < di->loctab_size);
ML_(dinfo_shrink_block)( di->loctab, new_sz * sizeof(DiLoc));
+ ML_(dinfo_shrink_block)( di->loctab_fndn_ix, new_sz * di->sizeof_fndn_ix);
di->loctab_size = new_sz;
}
/* Top-level place to call to add a source-location mapping entry.
*/
void ML_(addLineInfo) ( struct _DebugInfo* di,
- const HChar* filename,
- const HChar* dirname, /* NULL == directory is unknown */
+ UInt fndn_ix,
Addr this,
Addr next,
Int lineno,
/* Ignore zero-sized locs */
if (this == next) return;
- if (debug)
- VG_(printf)( " src %s %s line %d %#lx-%#lx\n",
- dirname ? dirname : "(unknown)",
- filename, lineno, this, next );
+ if (debug) {
+ FnDn *fndn = VG_(indexEltNumber) (di->fndnpool, fndn_ix);
+ VG_(printf)( " src ix %u %s %s line %d %#lx-%#lx\n",
+ fndn_ix,
+ fndn->dirname ? fndn->dirname : "(unknown)",
+ fndn->filename, lineno, this, next );
+ }
/* Maximum sanity checking. Some versions of GNU as do a shabby
* job with stabs entries; if anything looks suspicious, revert to
loc.addr = this;
loc.size = (UShort)size;
loc.lineno = lineno;
- loc.filename = filename;
- loc.dirname = dirname;
if (0) VG_(message)(Vg_DebugMsg,
- "addLoc: addr %#lx, size %lu, line %d, file %s\n",
- this,size,lineno,filename);
+ "addLoc: addr %#lx, size %lu, line %d, fndn_ix %u\n",
+ this,size,lineno,fndn_ix);
- addLoc ( di, &loc );
+ addLoc ( di, &loc, fndn_ix );
}
/* Add an inlined call info to the inlined call table.
Addr addr_lo, Addr addr_hi,
const HChar* inlinedfn,
const HChar* filename,
- const HChar* dirname, /* NULL is allowable */
Int lineno, UShort level)
{
DiInlLoc inl;
inl.inlinedfn = inlinedfn;
// caller:
inl.filename = filename;
- inl.dirname = dirname;
inl.lineno = lineno;
inl.level = level;
if (0) VG_(message)
(Vg_DebugMsg,
"addInlInfo: fn %s inlined as addr_lo %#lx,addr_hi %#lx,"
- "caller %s:%d (dir %s)\n",
- inlinedfn, addr_lo, addr_hi, filename, lineno,
- dirname ? dirname : "???");
+ "caller %s:%d\n",
+ inlinedfn, addr_lo, addr_hi, filename, lineno);
addInl ( di, &inl );
}
UInt cfsi_m_ix;
vg_assert(pos >= 0 && pos < di->cfsi_used);
- switch (di->sizeof_ix) {
+ switch (di->sizeof_cfsi_m_ix) {
case 1: cfsi_m_ix = ((UChar*) di->cfsi_m_ix)[pos]; break;
case 2: cfsi_m_ix = ((UShort*) di->cfsi_m_ix)[pos]; break;
case 4: cfsi_m_ix = ((UInt*) di->cfsi_m_ix)[pos]; break;
}
-/* Sort the location table by starting address. Mash the table around
- so as to establish the property that addresses are in order and the
- ranges do not overlap. This facilitates using binary search to map
- addresses to locations when we come to query the table.
-*/
-static Int compare_DiLoc ( const void* va, const void* vb )
+static DiLoc* sorting_loctab = NULL;
+static Int compare_DiLoc_via_ix ( const void* va, const void* vb )
{
- const DiLoc* a = va;
- const DiLoc* b = vb;
+ const DiLoc* a = &sorting_loctab[*(UInt*)va];
+ const DiLoc* b = &sorting_loctab[*(UInt*)vb];
if (a->addr < b->addr) return -1;
if (a->addr > b->addr) return 1;
return 0;
}
+static void sort_loctab_and_loctab_fndn_ix (struct _DebugInfo* di )
+{
+ /* We have to sort the array loctab by addr
+ together with its "parallel" array loctab_fndn_ix.
+ We first build sort_ix : an array of indexes in loctab,
+ that we sort by loctab address. Then we can reorder both
+ arrays according to sort_ix. */
+ UInt *sort_ix = ML_(dinfo_zalloc)("di.storage.six",
+ di->loctab_used*sizeof(UInt));
+ Word i, j, k;
+
+ for (i = 0; i < di->loctab_used; i++) sort_ix[i] = i;
+ sorting_loctab = di->loctab;
+ VG_(ssort)(sort_ix, di->loctab_used,
+ sizeof(*sort_ix), compare_DiLoc_via_ix);
+ sorting_loctab = NULL;
+
+ // Permute in place, using the sort_ix.
+ for (i=0; i < di->loctab_used; i++) {
+ DiLoc tmp_diloc;
+ UInt tmp_fndn_ix;
+
+ if (i == sort_ix[i])
+ continue; // i already at the good place
+
+ tmp_diloc = di->loctab[i];
+ tmp_fndn_ix = ML_(fndn_ix)(di, i);
+ j = i;
+ for (;;) {
+ k = sort_ix[j];
+ sort_ix[j] = j;
+ if (k == i)
+ break;
+ di->loctab[j] = di->loctab[k];
+ set_fndn_ix (di, j, ML_(fndn_ix)(di, k));
+ j = k;
+ }
+ di->loctab[j] = tmp_diloc;
+ set_fndn_ix (di, j, tmp_fndn_ix);
+ }
+ ML_(dinfo_free)(sort_ix);
+}
+/* Sort the location table by starting address. Mash the table around
+ so as to establish the property that addresses are in order and the
+ ranges do not overlap. This facilitates using binary search to map
+ addresses to locations when we come to query the table.
+*/
static void canonicaliseLoctab ( struct _DebugInfo* di )
{
Word i, j;
-# define SWAP(ty,aa,bb) \
- do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
-
if (di->loctab_used == 0)
return;
- /* Sort by start address. */
- VG_(ssort)(di->loctab, di->loctab_used,
- sizeof(*di->loctab), compare_DiLoc);
+ /* sort loctab and loctab_fndn_ix by addr. */
+ sort_loctab_and_loctab_fndn_ix (di);
/* If two adjacent entries overlap, truncate the first. */
for (i = 0; i < ((Word)di->loctab_used)-1; i++) {
j = 0;
for (i = 0; i < (Word)di->loctab_used; i++) {
if (di->loctab[i].size > 0) {
- if (j != i)
+ if (j != i) {
di->loctab[j] = di->loctab[i];
+ set_fndn_ix(di, j, ML_(fndn_ix)(di, i));
+ }
j++;
}
}
/* Ensure relevant postconditions hold. */
for (i = 0; i < ((Word)di->loctab_used)-1; i++) {
- /*
- VG_(printf)("%d (%d) %d 0x%x\n",
- i, di->loctab[i+1].confident,
- di->loctab[i+1].size, di->loctab[i+1].addr );
- */
+ if (0)
+ VG_(printf)("%lu 0x%p lno:%d sz:%d fndn_ix:%d i+1 0x%p\n",
+ i,
+ (void*)di->loctab[i].addr,
+ di->loctab[i].lineno,
+ di->loctab[i].size,
+ ML_(fndn_ix)(di, i),
+ (void*)di->loctab[i+1].addr);
+
/* No zero-sized symbols. */
vg_assert(di->loctab[i].size > 0);
/* In order. */
vg_assert(di->loctab[i].addr + di->loctab[i].size - 1
< di->loctab[i+1].addr);
}
-# undef SWAP
/* Free up unused space at the end of the table. */
shrinkLocTab(di);
sz_cfsi_m_pool = VG_(sizeDedupPA)(di->cfsi_m_pool);
vg_assert (sz_cfsi_m_pool > 0);
if (sz_cfsi_m_pool <= 255)
- di->sizeof_ix = 1;
+ di->sizeof_cfsi_m_ix = 1;
else if (sz_cfsi_m_pool <= 65535)
- di->sizeof_ix = 2;
+ di->sizeof_cfsi_m_ix = 2;
else
- di->sizeof_ix = 4;
+ di->sizeof_cfsi_m_ix = 4;
di->cfsi_base = ML_(dinfo_zalloc)( "di.storage.finCfSI.1",
new_used * sizeof(Addr) );
di->cfsi_m_ix = ML_(dinfo_zalloc)( "di.storage.finCfSI.2",
- new_used * sizeof(UChar)*di->sizeof_ix);
+ new_used * sizeof(UChar)*di->sizeof_cfsi_m_ix);
pos = 0;
f_mergeables = 0;
if (sep > 1) {
f_holes++;
di->cfsi_base[pos] = prev_max + 1;
- switch (di->sizeof_ix) {
+ switch (di->sizeof_cfsi_m_ix) {
case 1: ((UChar*) di->cfsi_m_ix)[pos] = 0; break;
case 2: ((UShort*)di->cfsi_m_ix)[pos] = 0; break;
case 4: ((UInt*) di->cfsi_m_ix)[pos] = 0; break;
// Insert the cfsi entry i.
di->cfsi_base[pos] = di->cfsi_rd[i].base;
- switch (di->sizeof_ix) {
+ switch (di->sizeof_cfsi_m_ix) {
case 1: ((UChar*) di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
case 2: ((UShort*)di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
case 4: ((UInt*) di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
ML_(canonicaliseCFI) ( di );
if (di->cfsi_m_pool)
VG_(freezeDedupPA) (di->cfsi_m_pool, ML_(dinfo_shrink_block));
- /// TBD prepare cfsi_base and cfsi_m_ix
canonicaliseVarInfo ( di );
if (di->strpool)
VG_(freezeDedupPA) (di->strpool, ML_(dinfo_shrink_block));
+ if (di->fndnpool)
+ VG_(freezeDedupPA) (di->fndnpool, ML_(dinfo_shrink_block));
}