mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 02:18:37 +00:00
Partially merge in a (heavily modified) patch from Eric Estievenart
which adds support for reading directory names from DWARF2 debug info. Also rework the representation of file and directory tables in the DWARF2 reader. This removes a longstanding but only-just-discovered curiousity that the previous code expanded the filename table one entry at a time, so that reading file names from a DWARF2 object was quadratic in the number of file names. It's now N log N. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3908
This commit is contained in:
parent
ced9276574
commit
56b4d07c7d
@ -36,6 +36,81 @@
|
||||
#include "pub_core_options.h"
|
||||
#include "priv_symtab.h"
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- 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);
|
||||
VG_(arena_free)(VG_AR_SYMTAB, wa->tab);
|
||||
}
|
||||
init_WordArray(wa);
|
||||
}
|
||||
|
||||
static void addto_WordArray ( WordArray* wa, Word w )
|
||||
{
|
||||
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 = VG_(arena_malloc)(VG_AR_SYMTAB,
|
||||
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)
|
||||
VG_(arena_free)(VG_AR_SYMTAB, 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++;
|
||||
}
|
||||
|
||||
static Word index_WordArray ( WordArray* wa, Int i )
|
||||
{
|
||||
vg_assert(i >= 0 && i < wa->tab_used);
|
||||
return wa->tab[i];
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Read DWARF2 format line number info. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/* Structure found in the .debug_line section. */
|
||||
typedef struct
|
||||
{
|
||||
@ -105,9 +180,6 @@ typedef struct State_Machine_Registers
|
||||
Int is_stmt;
|
||||
Int basic_block;
|
||||
Int end_sequence;
|
||||
/* This variable hold the number of the last entry seen
|
||||
in the File Table. */
|
||||
UInt last_file_entry;
|
||||
} SMR;
|
||||
|
||||
|
||||
@ -157,13 +229,27 @@ void reset_state_machine ( Int is_stmt )
|
||||
state_machine_regs.is_stmt = is_stmt;
|
||||
state_machine_regs.basic_block = 0;
|
||||
state_machine_regs.end_sequence = 0;
|
||||
state_machine_regs.last_file_entry = 0;
|
||||
}
|
||||
|
||||
/* Look up a directory name, or return NULL if unknown. */
|
||||
static
|
||||
Char* lookupDir ( Int filename_index,
|
||||
WordArray* fnidx2dir,
|
||||
WordArray* dirnames )
|
||||
{
|
||||
Word diridx = index_WordArray( fnidx2dir, filename_index );
|
||||
Word dirname = index_WordArray( dirnames, (Int)diridx );
|
||||
return (Char*)dirname;
|
||||
}
|
||||
|
||||
|
||||
/* Handled an extend line op. Returns true if this is the end
|
||||
of sequence. */
|
||||
static
|
||||
int process_extended_line_op( SegInfo *si, Char*** fnames,
|
||||
int process_extended_line_op( SegInfo *si,
|
||||
WordArray* filenames,
|
||||
WordArray* dirnames,
|
||||
WordArray* fnidx2dir,
|
||||
UChar* data, Int is_stmt)
|
||||
{
|
||||
UChar op_code;
|
||||
@ -197,10 +283,15 @@ int process_extended_line_op( SegInfo *si, Char*** fnames,
|
||||
*/
|
||||
if (state_machine_regs.is_stmt) {
|
||||
if (state_machine_regs.last_address)
|
||||
VG_(addLineInfo) (si, (*fnames)[state_machine_regs.last_file],
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line, 0);
|
||||
VG_(addLineInfo) (
|
||||
si,
|
||||
(Char*)index_WordArray(filenames, state_machine_regs.last_file),
|
||||
lookupDir( state_machine_regs.last_file,
|
||||
fnidx2dir, dirnames ),
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line, 0
|
||||
);
|
||||
}
|
||||
reset_state_machine (is_stmt);
|
||||
break;
|
||||
@ -212,15 +303,8 @@ int process_extended_line_op( SegInfo *si, Char*** fnames,
|
||||
break;
|
||||
|
||||
case DW_LNE_define_file:
|
||||
++ state_machine_regs.last_file_entry;
|
||||
name = data;
|
||||
if (*fnames == NULL)
|
||||
*fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (Char *) * 2);
|
||||
else
|
||||
*fnames = VG_(arena_realloc)(
|
||||
VG_AR_SYMTAB, *fnames,
|
||||
sizeof(Char *) * (state_machine_regs.last_file_entry + 1));
|
||||
(*fnames)[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1);
|
||||
addto_WordArray( filenames, (Word)VG_(addStr)(si,name,-1) );
|
||||
data += VG_(strlen) ((char *) data) + 1;
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
@ -239,37 +323,78 @@ int process_extended_line_op( SegInfo *si, Char*** fnames,
|
||||
|
||||
void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
{
|
||||
DWARF2_External_LineInfo * external;
|
||||
DWARF2_Internal_LineInfo info;
|
||||
UChar * standard_opcodes;
|
||||
UChar * data = dwarf2;
|
||||
UChar * end = dwarf2 + dwarf2_sz;
|
||||
UChar * end_of_sequence;
|
||||
Char ** fnames = NULL;
|
||||
DWARF2_External_LineInfo* external;
|
||||
DWARF2_Internal_LineInfo info;
|
||||
UChar* standard_opcodes;
|
||||
UChar* data = dwarf2;
|
||||
UChar* end = dwarf2 + dwarf2_sz;
|
||||
UChar* end_of_sequence;
|
||||
WordArray filenames;
|
||||
WordArray dirnames;
|
||||
WordArray fnidx2dir;
|
||||
|
||||
/* 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.
|
||||
|
||||
Similarly, dirnames is an array 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],
|
||||
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 diretory is dirnames[ fnidx2dir[i] ] */
|
||||
|
||||
/* Fails due to gcc padding ...
|
||||
vg_assert(sizeof(DWARF2_External_LineInfo)
|
||||
== sizeof(DWARF2_Internal_LineInfo));
|
||||
*/
|
||||
|
||||
while (data < end)
|
||||
{
|
||||
init_WordArray(&filenames);
|
||||
init_WordArray(&dirnames);
|
||||
init_WordArray(&fnidx2dir);
|
||||
|
||||
while (data < end) {
|
||||
|
||||
/* Dump the file/dirname tables and start over. */
|
||||
free_WordArray(&filenames);
|
||||
free_WordArray(&dirnames);
|
||||
free_WordArray(&fnidx2dir);
|
||||
|
||||
init_WordArray(&filenames);
|
||||
init_WordArray(&dirnames);
|
||||
init_WordArray(&fnidx2dir);
|
||||
|
||||
/* 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 );
|
||||
addto_WordArray( &dirnames, (Word)VG_(addStr)(si,".",-1) );
|
||||
addto_WordArray( &fnidx2dir, (Word)0 ); /* "." */
|
||||
|
||||
external = (DWARF2_External_LineInfo *) data;
|
||||
|
||||
/* Check the length of the block. */
|
||||
info.li_length = * ((UInt *)(external->li_length));
|
||||
|
||||
if (info.li_length == 0xffffffff)
|
||||
if (info.li_length == 0xffffffff)
|
||||
{
|
||||
VG_(symerr)("64-bit DWARF line info is not supported yet.");
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info.li_length + sizeof (external->li_length) > dwarf2_sz)
|
||||
{
|
||||
VG_(symerr)("DWARF line info appears to be corrupt "
|
||||
"- the section is too small");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check its version number. */
|
||||
@ -278,7 +403,7 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
{
|
||||
VG_(symerr)("Only DWARF version 2 line info "
|
||||
"is currently supported.");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info.li_prologue_length = * ((UInt *) (external->li_prologue_length));
|
||||
@ -313,7 +438,7 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
info.li_opcode_base = * ((UChar *)(external->li_opcode_base));
|
||||
|
||||
if (0) VG_(printf)("dwarf2: line base: %d, range %d, opc base: %d\n",
|
||||
info.li_line_base, info.li_line_range, info.li_opcode_base);
|
||||
info.li_line_base, info.li_line_range, info.li_opcode_base);
|
||||
|
||||
/* Sign extend the line base field. */
|
||||
info.li_line_base <<= 24;
|
||||
@ -330,64 +455,39 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
/* Read the contents of the Directory table. */
|
||||
data = standard_opcodes + info.li_opcode_base - 1;
|
||||
|
||||
if (* data == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We ignore the directory table, since gcc gives the entire
|
||||
path as part of the filename */
|
||||
while (* data != 0)
|
||||
{
|
||||
data += VG_(strlen) ((char *) data) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip the NUL at the end of the table. */
|
||||
while (* data != 0) {
|
||||
addto_WordArray( &dirnames, (Word)VG_(addStr)(si,data,-1) );
|
||||
data += VG_(strlen) ((char *) data) + 1;
|
||||
}
|
||||
if (*data != 0) {
|
||||
VG_(symerr)("can't find NUL at end of DWARF2 directory table");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
data ++;
|
||||
|
||||
/* Read the contents of the File Name table. */
|
||||
if (* data == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
while (* data != 0)
|
||||
{
|
||||
UChar * name;
|
||||
Int bytes_read;
|
||||
/* Read the contents of the File Name table. This produces a
|
||||
bunch of file names, and for each, an index to the
|
||||
corresponding direcory name entry. */
|
||||
while (* data != 0) {
|
||||
UChar* name;
|
||||
Int bytes_read, diridx;
|
||||
name = data;
|
||||
data += VG_(strlen) ((Char *) data) + 1;
|
||||
|
||||
++ state_machine_regs.last_file_entry;
|
||||
name = data;
|
||||
/* Since we don't have realloc (0, ....) == malloc (...)
|
||||
semantics, we need to malloc the first time. */
|
||||
diridx = read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
|
||||
if (fnames == NULL)
|
||||
fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (Char *) * 2);
|
||||
else
|
||||
fnames = VG_(arena_realloc)(VG_AR_SYMTAB, fnames,
|
||||
sizeof(Char *)
|
||||
* (state_machine_regs.last_file_entry + 1));
|
||||
data += VG_(strlen) ((Char *) data) + 1;
|
||||
fnames[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1);
|
||||
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
read_leb128 (data, & bytes_read, 0);
|
||||
data += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip the NUL at the end of the table. */
|
||||
addto_WordArray( &filenames, (Word)VG_(addStr)(si,name,-1) );
|
||||
addto_WordArray( &fnidx2dir, (Word)diridx );
|
||||
if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
|
||||
}
|
||||
if (*data != 0) {
|
||||
VG_(symerr)("can't find NUL at end of DWARF2 file name table");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
data ++;
|
||||
|
||||
@ -401,7 +501,7 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
|
||||
op_code = * data ++;
|
||||
|
||||
if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code);
|
||||
if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code);
|
||||
|
||||
if (op_code >= info.li_opcode_base)
|
||||
{
|
||||
@ -420,10 +520,17 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
if (state_machine_regs.is_stmt) {
|
||||
/* only add a statement if there was a previous boundary */
|
||||
if (state_machine_regs.last_address)
|
||||
VG_(addLineInfo) (si, fnames[state_machine_regs.last_file],
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line, 0);
|
||||
VG_(addLineInfo)(
|
||||
si,
|
||||
(Char*)index_WordArray( &filenames,
|
||||
state_machine_regs.last_file ),
|
||||
lookupDir( state_machine_regs.last_file,
|
||||
&fnidx2dir, &dirnames ),
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line,
|
||||
0
|
||||
);
|
||||
state_machine_regs.last_address = state_machine_regs.address;
|
||||
state_machine_regs.last_file = state_machine_regs.file;
|
||||
state_machine_regs.last_line = state_machine_regs.line;
|
||||
@ -433,8 +540,8 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
{
|
||||
case DW_LNS_extended_op:
|
||||
data += process_extended_line_op (
|
||||
si, &fnames, data,
|
||||
info.li_default_is_stmt);
|
||||
si, &filenames, &dirnames, &fnidx2dir,
|
||||
data, info.li_default_is_stmt);
|
||||
break;
|
||||
|
||||
case DW_LNS_copy:
|
||||
@ -443,10 +550,17 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
if (state_machine_regs.is_stmt) {
|
||||
/* only add a statement if there was a previous boundary */
|
||||
if (state_machine_regs.last_address)
|
||||
VG_(addLineInfo) (si, fnames[state_machine_regs.last_file],
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line, 0);
|
||||
VG_(addLineInfo)(
|
||||
si,
|
||||
(Char*)index_WordArray( &filenames,
|
||||
state_machine_regs.last_file ),
|
||||
lookupDir( state_machine_regs.last_file,
|
||||
&fnidx2dir, &dirnames ),
|
||||
si->offset + state_machine_regs.last_address,
|
||||
si->offset + state_machine_regs.address,
|
||||
state_machine_regs.last_line,
|
||||
0
|
||||
);
|
||||
state_machine_regs.last_address = state_machine_regs.address;
|
||||
state_machine_regs.last_file = state_machine_regs.file;
|
||||
state_machine_regs.last_line = state_machine_regs.line;
|
||||
@ -527,10 +641,14 @@ void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz )
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
VG_(arena_free)(VG_AR_SYMTAB, fnames);
|
||||
fnames = NULL;
|
||||
}
|
||||
} /* while (data < end_of_sequence) */
|
||||
|
||||
} /* while (data < end) */
|
||||
|
||||
out:
|
||||
free_WordArray(&filenames);
|
||||
free_WordArray(&dirnames);
|
||||
free_WordArray(&fnidx2dir);
|
||||
}
|
||||
|
||||
|
||||
@ -813,7 +931,7 @@ void VG_(read_debuginfo_dwarf1) (
|
||||
if (delta > 0 && prev_line > 0) {
|
||||
if (0) VG_(printf) (" %d %d-%d\n",
|
||||
prev_line, prev_delta, delta-1);
|
||||
VG_(addLineInfo) ( si, curr_filenm,
|
||||
VG_(addLineInfo) ( si, curr_filenm, NULL,
|
||||
base + prev_delta, base + delta,
|
||||
prev_line, 0 );
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user