size_t sequence;
};
+struct dirlist
+{
+ const char *dir;
+ size_t len;
+};
/* Compare by Dwarf_Line.addr, given pointers into an array of pointers. */
static int
: 0;
}
+/* Decoded .debug_line program header. */
+struct line_header
+{
+ /* Header entries */
+ Dwarf_Word unit_length;
+ unsigned int length;
+ uint_fast16_t version;
+ size_t line_address_size;
+ size_t segment_selector_size;
+ Dwarf_Word header_length;
+ const unsigned char *header_start;
+ uint_fast8_t minimum_instr_len;
+ uint_fast8_t max_ops_per_instr;
+ uint_fast8_t default_is_stmt;
+ int_fast8_t line_base;
+ uint_fast8_t line_range;
+ uint_fast8_t opcode_base;
+ const uint8_t *standard_opcode_lengths;
+ unsigned int debug_str_offset; /* CUBIN only */
+ size_t files_start;
+};
+
struct line_state
{
Dwarf_Word addr;
return false;
}
+/* Read the .debug_line program header. Return 0 if sucessful, otherwise set
+ libdw errno and return -1. */
+
static int
-read_srclines (Dwarf *dbg,
- const unsigned char *linep, const unsigned char *lineendp,
- const char *comp_dir, unsigned address_size,
- Dwarf_Lines **linesp, Dwarf_Files **filesp)
+read_line_header (Dwarf *dbg, unsigned address_size,
+ const unsigned char *linep, const unsigned char *lineendp,
+ struct line_header *lh)
{
- int res = -1;
-
- struct filelist *filelist = NULL;
- size_t nfilelist = 0;
- size_t ndirlist = 0;
-
- /* If there are a large number of lines, files or dirs don't blow up
- the stack. Stack allocate some entries, only dynamically malloc
- when more than MAX. */
-#define MAX_STACK_ALLOC 4096
-#define MAX_STACK_LINES (MAX_STACK_ALLOC / 2)
-#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
-#define MAX_STACK_DIRS (MAX_STACK_ALLOC / 16)
-
- /* Initial statement program state (except for stmt_list, see below). */
- struct line_state state =
- {
- .linelist = NULL,
- .nlinelist = 0,
- .addr = 0,
- .op_index = 0,
- .file = 1,
- /* We only store int but want to check for overflow (see SET above). */
- .line = 1,
- .column = 0,
- .basic_block = false,
- .prologue_end = false,
- .epilogue_begin = false,
- .isa = 0,
- .discriminator = 0,
- .context = 0,
- .function_name = 0
- };
-
- /* The dirs normally go on the stack, but if there are too many
- we alloc them all. Set up stack storage early, so we can check on
- error if we need to free them or not. */
- struct dirlist
- {
- const char *dir;
- size_t len;
- };
- struct dirlist dirstack[MAX_STACK_DIRS];
- struct dirlist *dirarray = dirstack;
+ const unsigned char *line_start = linep;
if (unlikely (linep + 4 > lineendp))
- {
- invalid_data:
- __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
- goto out;
- }
+ goto invalid_data;
- Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
- unsigned int length = 4;
- if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
+ lh->unit_length = read_4ubyte_unaligned_inc (dbg, linep);
+ lh->length = 4;
+ if (unlikely (lh->unit_length == DWARF3_LENGTH_64_BIT))
{
if (unlikely (linep + 8 > lineendp))
goto invalid_data;
- unit_length = read_8ubyte_unaligned_inc (dbg, linep);
- length = 8;
+ lh->unit_length = read_8ubyte_unaligned_inc (dbg, linep);
+ lh->length = 8;
}
/* Check whether we have enough room in the section. */
- if (unlikely (unit_length > (size_t) (lineendp - linep)))
+ if (unlikely (lh->unit_length > (size_t) (lineendp - linep)))
goto invalid_data;
- lineendp = linep + unit_length;
+ lineendp = linep + lh->unit_length;
/* The next element of the header is the version identifier. */
if ((size_t) (lineendp - linep) < 2)
goto invalid_data;
- uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
- if (unlikely (version < 2) || unlikely (version > 5))
+ lh->version = read_2ubyte_unaligned_inc (dbg, linep);
+ if (unlikely (lh->version < 2) || unlikely (lh->version > 5))
{
__libdw_seterrno (DWARF_E_VERSION);
- goto out;
+ return -1;
}
/* DWARF5 explicitly lists address and segment_selector sizes. */
- if (version >= 5)
+ if (lh->version >= 5)
{
if ((size_t) (lineendp - linep) < 2)
goto invalid_data;
- size_t line_address_size = *linep++;
- size_t segment_selector_size = *linep++;
- if (line_address_size != address_size || segment_selector_size != 0)
+ lh->line_address_size = *linep++;
+ lh->segment_selector_size = *linep++;
+ if (lh->line_address_size != address_size || lh->segment_selector_size != 0)
goto invalid_data;
}
/* Next comes the header length. */
- Dwarf_Word header_length;
- if (length == 4)
+ if (lh->length == 4)
{
if ((size_t) (lineendp - linep) < 4)
goto invalid_data;
- header_length = read_4ubyte_unaligned_inc (dbg, linep);
+ lh->header_length = read_4ubyte_unaligned_inc (dbg, linep);
}
else
{
if ((size_t) (lineendp - linep) < 8)
goto invalid_data;
- header_length = read_8ubyte_unaligned_inc (dbg, linep);
+ lh->header_length = read_8ubyte_unaligned_inc (dbg, linep);
}
- const unsigned char *header_start = linep;
+ lh->header_start = linep;
/* Next the minimum instruction length. */
- uint_fast8_t minimum_instr_len = *linep++;
+ lh->minimum_instr_len = *linep++;
/* Next the maximum operations per instruction, in version 4 format. */
- uint_fast8_t max_ops_per_instr = 1;
- if (version >= 4)
+ lh->max_ops_per_instr = 1;
+ if (lh->version >= 4)
{
if (unlikely ((size_t) (lineendp - linep) < 1))
goto invalid_data;
- max_ops_per_instr = *linep++;
- if (unlikely (max_ops_per_instr == 0))
+ lh->max_ops_per_instr = *linep++;
+ if (unlikely (lh->max_ops_per_instr == 0))
goto invalid_data;
}
/* Then the flag determining the default value of the is_stmt
register. */
- uint_fast8_t default_is_stmt = *linep++;
+ lh->default_is_stmt = *linep++;
/* Now the line base. */
- int_fast8_t line_base = (int8_t) *linep++;
+ lh->line_base = (int8_t) *linep++;
/* And the line range. */
- uint_fast8_t line_range = *linep++;
+ lh->line_range = *linep++;
/* The opcode base. */
- uint_fast8_t opcode_base = *linep++;
+ lh->opcode_base = *linep++;
/* Remember array with the standard opcode length (-1 to account for
the opcode with value zero not being mentioned). */
- const uint8_t *standard_opcode_lengths = linep - 1;
- if (unlikely (lineendp - linep < opcode_base - 1))
+ lh->standard_opcode_lengths = linep - 1;
+ if (unlikely (lineendp - linep < lh->opcode_base - 1))
goto invalid_data;
- linep += opcode_base - 1;
+ linep += lh->opcode_base - 1;
+
+ /* Record beginning of the file information. */
+ lh->files_start = (size_t) (linep - line_start);
+
+ return 0;
+
+invalid_data:
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+ return -1;
+}
+
+/* If there are a large number of lines, files or dirs don't blow up
+ the stack. Stack allocate some entries, only dynamically malloc
+ when more than MAX. */
+#define MAX_STACK_ALLOC 4096
+#define MAX_STACK_LINES (MAX_STACK_ALLOC / 2)
+#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
+#define MAX_STACK_DIRS (MAX_STACK_ALLOC / 16)
+
+static int
+read_srcfiles (Dwarf *dbg,
+ const unsigned char *linep, const unsigned char *lineendp,
+ const char *comp_dir, unsigned address_size,
+ struct line_header *lh, Dwarf_Files **filesp)
+{
+ if (filesp == NULL)
+ return -1;
+
+ struct line_header lh_local;
+
+ if (lh == NULL)
+ {
+ if (read_line_header (dbg, address_size, linep, lineendp, &lh_local) != 0)
+ return -1;
+ lh = &lh_local;
+ }
+
+ int res = -1;
+
+ struct filelist *filelist = NULL;
+ size_t nfilelist = 0;
+ size_t ndirlist = 0;
+
+ /* The dirs normally go on the stack, but if there are too many
+ we alloc them all. Set up stack storage early, so we can check on
+ error if we need to free them or not. */
+ struct dirlist dirstack[MAX_STACK_DIRS];
+ struct dirlist *dirarray = dirstack;
/* To read DWARF5 dir and file lists we need to know the forms. For
now we skip everything, except the DW_LNCT_path and
unsigned char form_path = -1; /* Which forms is DW_LNCT_path. */
unsigned char form_idx = -1; /* And which is DW_LNCT_directory_index. */
+ /* Set lineendp to the end of the file information. */
+ lineendp = lh->header_start + lh->header_length;
+
+ /* Advance linep to the beginning of the header's srcfile information. */
+ linep += lh->files_start;
+
/* To read/skip form data. */
Dwarf_CU fake_cu = {
.dbg = dbg,
.sec_idx = IDX_debug_line,
.version = 5,
- .offset_size = length,
+ .offset_size = lh->length,
.address_size = address_size,
.startp = (void *) linep,
.endp = (void *) lineendp,
/* First count the entries. */
size_t ndirs = 0;
- if (version < 5)
+ if (lh->version < 5)
{
const unsigned char *dirp = linep;
while (dirp < lineendp && *dirp != 0)
/* Entry zero is implicit for older versions, but explicit for 5+. */
struct dirlist comp_dir_elem;
- if (version < 5)
+ if (lh->version < 5)
{
/* First comes the list of directories. Add the compilation
directory first since the index zero is used for it. */
fl; })
/* Now read the files. */
- if (version < 5)
+ if (lh->version < 5)
{
if (unlikely (linep >= lineendp))
goto invalid_data;
}
}
- unsigned int debug_str_offset = 0;
- if (unlikely (linep == header_start + header_length - 4))
+ if (unlikely (linep == lh->header_start + lh->header_length - 4))
{
/* CUBINs contain an unsigned 4-byte offset */
- debug_str_offset = read_4ubyte_unaligned_inc (dbg, linep);
+ lh->debug_str_offset = read_4ubyte_unaligned_inc (dbg, linep);
}
/* Consistency check. */
- if (unlikely (linep != header_start + header_length))
+ if (unlikely (linep != lh->header_start + lh->header_length))
+ goto invalid_data;
+
+ /* Put all the files in an array. */
+ Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
+ sizeof (Dwarf_Files)
+ + nfilelist * sizeof (Dwarf_Fileinfo)
+ + (ndirlist + 1) * sizeof (char *),
+ 1);
+
+ if (unlikely (files == NULL))
+ goto no_mem;
+
+ const char **dirs = (void *) &files->info[nfilelist];
+
+ struct filelist *fileslist = filelist;
+ files->nfiles = nfilelist;
+ for (size_t n = nfilelist; n > 0; n--)
{
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- goto out;
+ files->info[n - 1] = fileslist->info;
+ fileslist = fileslist->next;
+ }
+ assert (fileslist == NULL);
+
+ /* Put all the directory strings in an array. */
+ files->ndirs = ndirlist;
+ for (unsigned int i = 0; i < ndirlist; ++i)
+ dirs[i] = dirarray[i].dir;
+ dirs[ndirlist] = NULL;
+
+ /* Pass the file data structure to the caller. */
+ *filesp = files;
+
+ res = 0;
+ goto out;
+
+invalid_data:
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+
+out:
+ if (dirarray != dirstack)
+ free (dirarray);
+ for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
+ {
+ struct filelist *fl = filelist->next;
+ free (filelist);
+ filelist = fl;
}
+ return res;
+}
+
+static int
+read_srclines (Dwarf *dbg,
+ const unsigned char *linep, const unsigned char *lineendp,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Lines **linesp, Dwarf_Files **filesp,
+ bool use_cached_files)
+{
+ int res = -1;
+ struct line_header lh;
+
+ if (read_line_header (dbg, address_size, linep, lineendp, &lh) != 0)
+ return res;
+
+ /* Use the filesp srcfiles if they've already been read. */
+ if (!use_cached_files
+ && read_srcfiles (dbg, linep, lineendp, comp_dir,
+ address_size, &lh, filesp) != 0)
+ return res;
+
+ /* Initial statement program state (except for stmt_list, see below). */
+ struct line_state state =
+ {
+ .linelist = NULL,
+ .nlinelist = 0,
+ .addr = 0,
+ .op_index = 0,
+ .file = 1,
+ /* We only store int but want to check for overflow (see SET above). */
+ .line = 1,
+ .column = 0,
+ .basic_block = false,
+ .prologue_end = false,
+ .epilogue_begin = false,
+ .isa = 0,
+ .discriminator = 0,
+ .context = 0,
+ .function_name = 0
+ };
+
/* We are about to process the statement program. Most state machine
registers have already been initialize above. Just add the is_stmt
default. See 6.2.2 in the v2.1 specification. */
- state.is_stmt = default_is_stmt;
+ state.is_stmt = lh.default_is_stmt;
/* Apply the "operation advance" from a special opcode or
DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */
#define advance_pc(op_advance) \
- run_advance_pc (&state, op_advance, minimum_instr_len, max_ops_per_instr)
+ run_advance_pc (&state, op_advance, lh.minimum_instr_len, \
+ lh.max_ops_per_instr)
/* Process the instructions. */
? &llstack[state.nlinelist] \
: malloc (sizeof (struct linelist))); \
if (unlikely (ll == NULL)) \
- goto no_mem; \
+ { \
+ __libdw_seterrno (DWARF_E_NOMEM); \
+ goto out; \
+ } \
state.end_sequence = end_seq; \
if (unlikely (add_new_line (&state, ll))) \
goto invalid_data; \
} while (0)
+ /* If DW_LNE_define_file is present, then additional files will be
+ added to filesp. */
+ size_t nfilelist = 0;
+ struct filelist *filelist = NULL;
+
+ /* Set lineendp to the end of the line program. */
+ lineendp = linep + lh.length + lh.unit_length;
+
+ /* Set linep to the beginning of the line program. */
+ linep = lh.header_start + lh.header_length;
+
while (linep < lineendp)
{
unsigned int opcode;
opcode = *linep++;
/* Is this a special opcode? */
- if (likely (opcode >= opcode_base))
+ if (likely (opcode >= lh.opcode_base))
{
- if (unlikely (line_range == 0))
+ if (unlikely (lh.line_range == 0))
goto invalid_data;
/* Yes. Handling this is quite easy since the opcode value
opcode = (desired line increment - line_base)
+ (line_range * address advance) + opcode_base
*/
- int line_increment = (line_base
- + (opcode - opcode_base) % line_range);
+ int line_increment = (lh.line_base
+ + (opcode - lh.opcode_base) % lh.line_range);
/* Perform the increments. */
state.line += line_increment;
- advance_pc ((opcode - opcode_base) / line_range);
+ advance_pc ((opcode - lh.opcode_base) / lh.line_range);
/* Add a new line with the current state machine values. */
NEW_LINE (0);
state.file = 1;
state.line = 1;
state.column = 0;
- state.is_stmt = default_is_stmt;
+ state.is_stmt = lh.default_is_stmt;
state.basic_block = false;
state.prologue_end = false;
state.epilogue_begin = false;
if (unlikely (linep >= lineendp))
goto invalid_data;
get_uleb128 (diridx, linep, lineendp);
- if (unlikely (diridx >= ndirlist))
+
+ size_t ndirs = (*filesp)->ndirs;
+ if (unlikely (diridx >= ndirs))
{
__libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
goto invalid_data;
goto invalid_data;
get_uleb128 (filelength, linep, lineendp);
- struct filelist *new_file = NEW_FILE ();
+ /* Add new_file to filelist that will be merged with filesp. */
+ struct filelist *new_file = malloc (sizeof (struct filelist));
+ if (unlikely (new_file == NULL))
+ {
+ __libdw_seterrno (DWARF_E_NOMEM);
+ goto out;
+ }
+ nfilelist++;
+ new_file->next = filelist;
+ filelist = new_file;
+
if (fname[0] == '/')
new_file->info.name = fname;
else
{
+ /* Directory names are stored in a char *[ndirs] located
+ after the last Dwarf_Fileinfo_s. */
+ size_t nfiles = (*filesp)->nfiles;
+ const char **dirarray
+ = (const char **) &((*filesp)->info[nfiles]);
+
+ const char *dname = dirarray[diridx];
+ size_t dnamelen = strlen (dname);
+
new_file->info.name =
- libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
- + fnamelen + 1));
+ libdw_alloc (dbg, char, 1, (dnamelen + fnamelen + 2));
char *cp = new_file->info.name;
- if (dirarray[diridx].dir != NULL)
+ if (dname != NULL)
+
/* This value could be NULL in case the
DW_AT_comp_dir was not present. We
cannot do much in this case. Just
keep the file relative. */
+
{
- cp = stpcpy (cp, dirarray[diridx].dir);
+ cp = stpcpy (cp, dname);
*cp++ = '/';
}
strcpy (cp, fname);
case DW_LNE_set_discriminator:
/* Takes one ULEB128 parameter, the discriminator. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
if (unlikely (linep >= lineendp))
goto invalid_data;
get_uleb128 (state.function_name, linep, lineendp);
- state.function_name += debug_str_offset;
+ state.function_name += lh.debug_str_offset;
break;
case DW_LNE_NVIDIA_set_function_name:
if (unlikely (linep >= lineendp))
goto invalid_data;
get_uleb128 (state.function_name, linep, lineendp);
- state.function_name += debug_str_offset;
+ state.function_name += lh.debug_str_offset;
break;
default:
{
case DW_LNS_copy:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
/* Add a new line with the current state machine values. */
case DW_LNS_advance_pc:
/* Takes one uleb128 parameter which is added to the
address. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
case DW_LNS_advance_line:
/* Takes one sleb128 parameter which is added to the
line. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
case DW_LNS_set_file:
/* Takes one uleb128 parameter which is stored in file. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
case DW_LNS_set_column:
/* Takes one uleb128 parameter which is stored in column. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
case DW_LNS_negate_stmt:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
state.is_stmt = 1 - state.is_stmt;
case DW_LNS_set_basic_block:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
state.basic_block = true;
case DW_LNS_const_add_pc:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
- if (unlikely (line_range == 0))
+ if (unlikely (lh.line_range == 0))
goto invalid_data;
- advance_pc ((255 - opcode_base) / line_range);
+ advance_pc ((255 - lh.opcode_base) / lh.line_range);
break;
case DW_LNS_fixed_advance_pc:
/* Takes one 16 bit parameter which is added to the
address. */
- if (unlikely (standard_opcode_lengths[opcode] != 1)
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1)
|| unlikely (lineendp - linep < 2))
goto invalid_data;
case DW_LNS_set_prologue_end:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
state.prologue_end = true;
case DW_LNS_set_epilogue_begin:
/* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
goto invalid_data;
state.epilogue_begin = true;
case DW_LNS_set_isa:
/* Takes one uleb128 parameter which is stored in isa. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
+ if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
goto invalid_data;
if (unlikely (linep >= lineendp))
/* This is a new opcode the generator but not we know about.
Read the parameters associated with it but then discard
everything. Read all the parameters for this opcode. */
- for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
+ for (int n = lh.standard_opcode_lengths[opcode]; n > 0; --n)
{
if (unlikely (linep >= lineendp))
goto invalid_data;
}
}
- /* Put all the files in an array. */
- Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
- sizeof (Dwarf_Files)
- + nfilelist * sizeof (Dwarf_Fileinfo)
- + (ndirlist + 1) * sizeof (char *),
- 1);
- const char **dirs = (void *) &files->info[nfilelist];
-
- struct filelist *fileslist = filelist;
- files->nfiles = nfilelist;
- for (size_t n = nfilelist; n > 0; n--)
+ /* Merge filesp with the files from DW_LNE_define_file, if any. */
+ if (unlikely (filelist != NULL))
{
- files->info[n - 1] = fileslist->info;
- fileslist = fileslist->next;
- }
- assert (fileslist == NULL);
+ Dwarf_Files *prevfiles = *filesp;
+ size_t ndirs = prevfiles->ndirs;
+ size_t nprevfiles = prevfiles->nfiles;
+ size_t nnewfiles = nprevfiles + nfilelist;
+
+ Dwarf_Files *newfiles
+ = libdw_alloc (dbg, Dwarf_Files,
+ sizeof (Dwarf_Files)
+ + nnewfiles * sizeof (Dwarf_Fileinfo)
+ + (ndirs + 1) * sizeof (char *),
+ 1);
+
+
+ /* Copy prevfiles to newfiles. */
+ for (size_t n = 0; n < nprevfiles; n++)
+ newfiles->info[n] = prevfiles->info[n];
+
+ /* Add files from DW_LNE_define_file to newfiles. */
+ struct filelist *fileslist = filelist;
+ for (size_t n = nfilelist; n > 0; n--)
+ {
+ newfiles->info[nprevfiles + n - 1] = fileslist->info;
+ fileslist = fileslist->next;
+ }
- /* Put all the directory strings in an array. */
- files->ndirs = ndirlist;
- for (unsigned int i = 0; i < ndirlist; ++i)
- dirs[i] = dirarray[i].dir;
- dirs[ndirlist] = NULL;
+ if (fileslist != NULL)
+ goto invalid_data;
- /* Pass the file data structure to the caller. */
- if (filesp != NULL)
- *filesp = files;
+ const char **newdirs = (void *) &newfiles->info[nnewfiles];
+ const char **prevdirs = (void *) &prevfiles->info[nprevfiles];
+
+ /* Copy prevdirs to newdirs. */
+ for (size_t n = 0; n < ndirs; n++)
+ newdirs[n] = prevdirs[n];
+
+ /* Update filesp. */
+ newfiles->nfiles = nnewfiles;
+ newfiles->ndirs = prevfiles->ndirs;
+ *filesp = newfiles;
+ }
size_t buf_size = (sizeof (Dwarf_Lines)
+ (sizeof (Dwarf_Line) * state.nlinelist));
for (size_t i = 0; i < state.nlinelist; ++i)
{
lines->info[i] = sortlines[i]->line;
- lines->info[i].files = files;
+ lines->info[i].files = *filesp;
}
/* Make sure the highest address for the CU is marked as end_sequence.
/* Success. */
res = 0;
+ goto out;
- out:
+invalid_data:
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+
+out:
/* Free malloced line records, if any. */
for (size_t i = MAX_STACK_LINES; i < state.nlinelist; i++)
{
free (state.linelist);
state.linelist = ll;
}
- if (dirarray != dirstack)
- free (dirarray);
- for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
- {
- struct filelist *fl = filelist->next;
- free (filelist);
- filelist = fl;
- }
+
+ /* Free file records from DW_LNE_define_file, if any. */
+ for (size_t i = 0; i < nfilelist; i++)
+ {
+ struct filelist *fl = filelist->next;
+ free (filelist);
+ filelist = fl;
+ }
return res;
}
return 0;
}
-int
-internal_function
-__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
- const char *comp_dir, unsigned address_size,
- Dwarf_Lines **linesp, Dwarf_Files **filesp)
+static int
+get_lines_or_files (Dwarf *dbg, Dwarf_Off debug_line_offset,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Lines **linesp, Dwarf_Files **filesp)
{
struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
files_lines_compare);
if (found == NULL)
{
+ /* This .debug_line is being read for the first time. */
Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
if (data == NULL
|| __libdw_offset_in_section (dbg, IDX_debug_line,
struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s,
sizeof *node, 1);
- if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
- &node->lines, &node->files) != 0)
+ /* Srcfiles will be read but srclines might not. Set lines here
+ to avoid possible uninitialized value errors. */
+ node->lines = NULL;
+
+ /* If linesp is NULL then read srcfiles without reading srclines. */
+ if (linesp == NULL)
+ {
+ if (read_srcfiles (dbg, linep, lineendp, comp_dir, address_size,
+ NULL, &node->files) != 0)
+ return -1;
+ }
+ else if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
+ &node->lines, &node->files, false) != 0)
return -1;
node->debug_line_offset = debug_line_offset;
return -1;
}
}
+ else if (*found != NULL
+ && (*found)->files != NULL
+ && (*found)->lines == NULL)
+ {
+ /* Srcfiles were already read from this .debug_line. Now read
+ srclines. */
+ Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
+ if (data == NULL
+ || __libdw_offset_in_section (dbg, IDX_debug_line,
+ debug_line_offset, 1) != 0)
+ return -1;
+
+ const unsigned char *linep = data->d_buf + debug_line_offset;
+ const unsigned char *lineendp = data->d_buf + data->d_size;
+
+ struct files_lines_s *node = *found;
+
+ if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
+ &node->lines, &node->files, true) != 0)
+ return -1;
+ }
+ else if (*found != NULL
+ && (*found)->files == NULL
+ && (*found)->lines != NULL)
+ {
+ /* If srclines were read then srcfiles should have also been read. */
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+ return -1;
+ }
if (linesp != NULL)
*linesp = (*found)->lines;
return 0;
}
+int
+internal_function
+__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Lines **linesp, Dwarf_Files **filesp)
+{
+ return get_lines_or_files (dbg, debug_line_offset, comp_dir,
+ address_size, linesp, filesp);
+}
+
+int
+internal_function
+__libdw_getsrcfiles (Dwarf *dbg, Dwarf_Off debug_line_offset,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Files **filesp)
+{
+ return get_lines_or_files (dbg, debug_line_offset, comp_dir,
+ address_size, NULL, filesp);
+}
+
/* Get the compilation directory, if any is set. */
const char *
__libdw_getcompdir (Dwarf_Die *cudie)