aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2024-03-25 15:57:25 -0400
committerAaron Merey <amerey@redhat.com>2024-04-11 12:34:43 -0400
commitd4b0848be5f575ff9464fee12ce7be416e4fb392 (patch)
tree069c99466a5e380ed949dedac2c695f9a576339e
parentdb33cb0cac3253c34881c0377ada51d9803eaae0 (diff)
downloadelfutils-d4b0848be5f575ff9464fee12ce7be416e4fb392.tar.gz
libdw: dwarf_getsrcfiles should not imply dwarf_getsrclines
dwarf_getsrcfiles causes line data to be read in addition to file data. This is wasteful for programs which only need file or directory names. Debuginfod server is one such example. Fix this by moving the srcfile reading in read_srclines into a separate function read_srcfiles. This change improves debuginfod server's max resident set size by up to 75% during rpm indexing. * libdw/dwarf_getsrcfiles.c (dwarf_getsrcfiles): Replace dwarf_getsrclines and __libdw_getsrclines with __libdw_getsrcfiles. * libdw/dwarf_getsrclines.c (read_line_header): New function. (read_srcfiles): New function. (read_srclines): Move srcfile reading into read_srcfiles. Add parameter to use cached srcfiles if available. Also merge srcfiles with any files from DW_LNE_define_file. (__libdw_getsrclines): Changed to call get_lines_or_files. (__libdw_getsrcfiles): New function. Calls get_lines_or_files. (get_lines_or_files): New function based on the old __libdw_getsrclines. Call read_srcfiles if linesp is NULL, otherwise call read_srclines. Pass previously read srcfiles to read_srclines if available. * libdw/dwarf_macro_getsrcfiles.c (dwarf_macro_getsrcfiles): Replace __libdw_getsrclines with __libdw_getsrcfiles. * libdw/libdwP.h (__libdw_getsrcfiles): New declaration. * tests/.gitignore: Add new test binary. * tests/get-files.c: Verify that dwarf_getsrcfiles does not cause srclines to be read. * tests/get-lines.c: Verify that srclines can be read after srcfiles have been read. * tests/Makefile.am: Add new testfiles. * tests/get-files-define-file.c: Print file names before and after reading DW_LNE_define_file. * tests/run-get-files.sh: Add get-files-define-file test. * tests/testfile-define-file.bz2: New testfile. Copy of testfile36.debug but with a line program consisting of two DW_LNE_define_file opcodes. https://sourceware.org/bugzilla/show_bug.cgi?id=27405 Signed-off-by: Aaron Merey <amerey@redhat.com>
-rw-r--r--libdw/dwarf_getsrcfiles.c24
-rw-r--r--libdw/dwarf_getsrclines.c571
-rw-r--r--libdw/dwarf_macro_getsrcfiles.c4
-rw-r--r--libdw/libdwP.h10
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/get-files-define-file.c162
-rw-r--r--tests/get-files.c8
-rw-r--r--tests/get-lines.c20
-rwxr-xr-xtests/run-get-files.sh73
-rw-r--r--tests/testfile-define-file.bz2bin0 -> 24910 bytes
11 files changed, 697 insertions, 182 deletions
diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c
index cd2e5b5a..24e4b7d2 100644
--- a/libdw/dwarf_getsrcfiles.c
+++ b/libdw/dwarf_getsrcfiles.c
@@ -70,10 +70,9 @@ dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
{
/* We are only interested in the files, the lines will
always come from the skeleton. */
- res = __libdw_getsrclines (cu->dbg, dwp_off,
+ res = __libdw_getsrcfiles (cu->dbg, dwp_off,
__libdw_getcompdir (cudie),
- cu->address_size, NULL,
- &cu->files);
+ cu->address_size, &cu->files);
}
}
else
@@ -89,12 +88,19 @@ dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
}
else
{
- Dwarf_Lines *lines;
- size_t nlines;
-
- /* Let the more generic function do the work. It'll create more
- data but that will be needed in an real program anyway. */
- res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines);
+ /* The die must have a statement list associated. */
+ Dwarf_Attribute stmt_list_mem;
+ Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
+ &stmt_list_mem);
+
+ Dwarf_Off debug_line_offset;
+ if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
+ NULL, &debug_line_offset) == NULL)
+ return -1;
+
+ res = __libdw_getsrcfiles (cu->dbg, debug_line_offset,
+ __libdw_getcompdir (cudie),
+ cu->address_size, &cu->files);
}
}
else if (cu->files != (void *) -1l)
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index 69e10c7b..987a86fd 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -52,6 +52,11 @@ struct linelist
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
@@ -77,6 +82,28 @@ compare_lines (const void *a, const void *b)
: 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;
@@ -155,127 +182,81 @@ add_new_line (struct line_state *state, struct linelist *new_line)
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;
}
@@ -285,23 +266,71 @@ read_srclines (Dwarf *dbg,
/* 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
@@ -311,12 +340,18 @@ read_srclines (Dwarf *dbg,
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,
@@ -324,7 +359,7 @@ read_srclines (Dwarf *dbg,
/* 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)
@@ -395,7 +430,7 @@ read_srclines (Dwarf *dbg,
/* 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. */
@@ -482,7 +517,7 @@ read_srclines (Dwarf *dbg,
fl; })
/* Now read the files. */
- if (version < 5)
+ if (lh->version < 5)
{
if (unlikely (linep >= lineendp))
goto invalid_data;
@@ -662,29 +697,114 @@ read_srclines (Dwarf *dbg,
}
}
- 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. */
@@ -697,12 +817,26 @@ read_srclines (Dwarf *dbg,
? &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;
@@ -713,9 +847,9 @@ read_srclines (Dwarf *dbg,
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
@@ -724,12 +858,12 @@ read_srclines (Dwarf *dbg,
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);
@@ -768,7 +902,7 @@ read_srclines (Dwarf *dbg,
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;
@@ -803,7 +937,9 @@ read_srclines (Dwarf *dbg,
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;
@@ -817,23 +953,43 @@ read_srclines (Dwarf *dbg,
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);
@@ -846,7 +1002,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -861,14 +1017,14 @@ read_srclines (Dwarf *dbg,
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:
@@ -886,7 +1042,7 @@ read_srclines (Dwarf *dbg,
{
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. */
@@ -902,7 +1058,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -914,7 +1070,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -925,7 +1081,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -936,7 +1092,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -947,7 +1103,7 @@ read_srclines (Dwarf *dbg,
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;
@@ -955,7 +1111,7 @@ read_srclines (Dwarf *dbg,
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;
@@ -963,19 +1119,19 @@ read_srclines (Dwarf *dbg,
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;
@@ -985,7 +1141,7 @@ read_srclines (Dwarf *dbg,
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;
@@ -993,7 +1149,7 @@ read_srclines (Dwarf *dbg,
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;
@@ -1001,7 +1157,7 @@ read_srclines (Dwarf *dbg,
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))
@@ -1015,7 +1171,7 @@ read_srclines (Dwarf *dbg,
/* 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;
@@ -1027,32 +1183,49 @@ read_srclines (Dwarf *dbg,
}
}
- /* 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));
@@ -1087,7 +1260,7 @@ read_srclines (Dwarf *dbg,
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.
@@ -1102,8 +1275,12 @@ read_srclines (Dwarf *dbg,
/* 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++)
{
@@ -1111,14 +1288,14 @@ read_srclines (Dwarf *dbg,
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;
}
@@ -1137,17 +1314,17 @@ files_lines_compare (const void *p1, const void *p2)
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,
@@ -1160,8 +1337,19 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
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;
@@ -1173,6 +1361,35 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off 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;
@@ -1183,6 +1400,26 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
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)
diff --git a/libdw/dwarf_macro_getsrcfiles.c b/libdw/dwarf_macro_getsrcfiles.c
index 11c587af..5e02935d 100644
--- a/libdw/dwarf_macro_getsrcfiles.c
+++ b/libdw/dwarf_macro_getsrcfiles.c
@@ -74,8 +74,8 @@ dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
the same unit through dwarf_getsrcfiles, and the file names
will be broken. */
- if (__libdw_getsrclines (table->dbg, line_offset, table->comp_dir,
- table->address_size, NULL, &table->files) < 0)
+ if (__libdw_getsrcfiles (table->dbg, line_offset, table->comp_dir,
+ table->address_size, &table->files) < 0)
table->files = (void *) -1;
}
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index c1c84ed3..e55ff50a 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1108,6 +1108,16 @@ int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
internal_function
__nonnull_attribute__ (1);
+/* Load .debug_line unit at DEBUG_LINE_OFFSET. COMP_DIR is a value of
+ DW_AT_comp_dir or NULL if that attribute is not available. Caches
+ the loaded unit and set *FILESP with loaded information. Returns 0
+ for success or a negative value for failure. */
+int __libdw_getsrcfiles (Dwarf *dbg, Dwarf_Off debug_line_offset,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Files **filesp)
+ internal_function
+ __nonnull_attribute__ (1);
+
/* Load and return value of DW_AT_comp_dir from CUDIE. */
const char *__libdw_getcompdir (Dwarf_Die *cudie);
diff --git a/tests/.gitignore b/tests/.gitignore
index 772c7881..4937f0d1 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -75,6 +75,7 @@
/funcscopes
/get-aranges
/get-files
+/get-files-define_file
/get-lines
/get-pubnames
/get-units-invalid
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b7fb7238..7aae3d8a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -35,7 +35,7 @@ endif
check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
showptable update1 update2 update3 update4 test-nlist \
show-die-info get-files next-files get-lines next-lines \
- get-pubnames \
+ get-pubnames get-files-define-file \
get-aranges allfcts line2addr addrscopes funcscopes \
show-abbrev hash newscn ecp dwflmodtest \
find-prologues funcretval allregs rdwrmmap \
@@ -655,7 +655,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile-dwp-5-cu-index-overflow.dwp.bz2 \
testfile-dwp-4-cu-index-overflow.bz2 \
testfile-dwp-4-cu-index-overflow.dwp.bz2 \
- testfile-dwp-cu-index-overflow.source
+ testfile-dwp-cu-index-overflow.source \
+ testfile-define-file.bz2
if USE_VALGRIND
@@ -734,6 +735,7 @@ show_abbrev_LDADD = $(libdw) $(libelf)
get_lines_LDADD = $(libdw) $(libelf)
next_lines_LDADD = $(libdw) $(libelf)
get_files_LDADD = $(libdw) $(libelf)
+get_files_define_file_LDADD = $(libdw) $(libelf)
next_files_LDADD = $(libdw) $(libelf)
get_aranges_LDADD = $(libdw) $(libelf)
allfcts_LDADD = $(libdw) $(libelf)
diff --git a/tests/get-files-define-file.c b/tests/get-files-define-file.c
new file mode 100644
index 00000000..583f9852
--- /dev/null
+++ b/tests/get-files-define-file.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002, 2004, 2005, 2007 Red Hat, Inc.
+ This file is part of elfutils.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <libelf.h>
+#include ELFUTILS_HEADER(dw)
+#include <stdio.h>
+#include <unistd.h>
+#include "../libdw/libdwP.h"
+
+static void
+print_dirs_and_files (Dwarf_Files *files, const char *const *dirs,
+ size_t nfiles, size_t ndirs)
+{
+ if (dirs[0] == NULL)
+ puts (" dirs[0] = (null)");
+ else
+ printf (" dirs[0] = \"%s\"\n", dirs[0]);
+ for (size_t i = 1; i < ndirs; ++i)
+ printf (" dirs[%zu] = \"%s\"\n", i, dirs[i]);
+
+ for (size_t i = 0; i < nfiles; ++i)
+ printf (" file[%zu] = \"%s\"\n", i,
+ dwarf_filesrc (files, i, NULL, NULL));
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int result = 0;
+ int cnt = argc - 1;
+
+ int fd = open (argv[cnt], O_RDONLY);
+
+ Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
+ if (dbg == NULL)
+ {
+ printf ("%s not usable\n", argv[cnt]);
+ result = 1;
+ if (fd != -1)
+ close (fd);
+ goto out;
+ }
+
+ Dwarf_Off o = 0;
+ Dwarf_Off ncu;
+ size_t cuhl;
+
+ /* Just inspect the first CU. */
+ if (dwarf_nextcu (dbg, o, &ncu, &cuhl, NULL, NULL, NULL) != 0)
+ {
+ printf ("%s: cannot get CU\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ Dwarf_Die die_mem;
+ Dwarf_Die *die = dwarf_offdie (dbg, o + cuhl, &die_mem);
+
+ if (die == NULL)
+ {
+ printf ("%s: cannot get CU die\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ Dwarf_Files *files;
+ size_t nfiles;
+
+ /* The files from DW_LNE_define_file should not be included
+ until dwarf_getsrclines is called. */
+ if (dwarf_getsrcfiles (die, &files, &nfiles) != 0)
+ {
+ printf ("%s: cannot get files\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ if (die->cu->lines != NULL)
+ {
+ printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ const char *const *dirs;
+ size_t ndirs;
+ if (dwarf_getsrcdirs (files, &dirs, &ndirs) != 0)
+ {
+ printf ("%s: cannot get include directories\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ /* Print file info without files from DW_LNE_define_file. */
+ print_dirs_and_files (files, dirs, nfiles, ndirs);
+
+ Dwarf_Lines *lines;
+ size_t nlines;
+
+ /* Reading the line program should add the new files. */
+ if (dwarf_getsrclines (die, &lines, &nlines) != 0)
+ {
+ printf ("%s: cannot get lines\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ Dwarf_Files *updated_files;
+ size_t num_updated_files;
+
+ /* Get the new files. */
+ if (dwarf_getsrcfiles (die, &updated_files, &num_updated_files) != 0)
+ {
+ printf ("%s: cannot get files\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ const char *const *updated_dirs;
+ size_t num_updated_dirs;
+
+ /* The dirs shouldn't change but verify that getsrcdirs still works. */
+ if (dwarf_getsrcdirs (updated_files, &updated_dirs, &num_updated_dirs) != 0)
+ {
+ printf ("%s: cannot get include directories\n", argv[cnt]);
+ result = 1;
+ goto out;
+ }
+
+ /* Verify that we didn't invalidate the old file info. */
+ print_dirs_and_files (files, dirs, nfiles, ndirs);
+
+ /* Print all files including those from DW_LNE_define_file. */
+ print_dirs_and_files (updated_files, updated_dirs,
+ num_updated_files, num_updated_dirs);
+
+out:
+ dwarf_end (dbg);
+ close (fd);
+
+ return result;
+}
diff --git a/tests/get-files.c b/tests/get-files.c
index 04091733..fa65aa93 100644
--- a/tests/get-files.c
+++ b/tests/get-files.c
@@ -24,6 +24,7 @@
#include ELFUTILS_HEADER(dw)
#include <stdio.h>
#include <unistd.h>
+#include "../libdw/libdwP.h"
int
@@ -76,6 +77,13 @@ main (int argc, char *argv[])
break;
}
+ if (die->cu->lines != NULL)
+ {
+ printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+ result = 1;
+ break;
+ }
+
const char *const *dirs;
size_t ndirs;
if (dwarf_getsrcdirs (files, &dirs, &ndirs) != 0)
diff --git a/tests/get-lines.c b/tests/get-lines.c
index 188d0162..77fb3c54 100644
--- a/tests/get-lines.c
+++ b/tests/get-lines.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include "../libdw/libdwP.h"
int
@@ -69,6 +70,24 @@ main (int argc, char *argv[])
}
old_cuoff = cuoff;
+ Dwarf_Files *files;
+ size_t nfiles;
+
+ /* Get files first to test that lines are read separately. */
+ if (dwarf_getsrcfiles (&die, &files, &nfiles) != 0)
+ {
+ printf ("%s: cannot get files\n", argv[cnt]);
+ result = 1;
+ break;
+ }
+
+ if (die.cu->lines != NULL)
+ {
+ printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+ result = 1;
+ break;
+ }
+
Dwarf_Lines *lb;
size_t nlb;
if (dwarf_getsrclines (&die, &lb, &nlb) != 0)
@@ -103,7 +122,6 @@ main (int argc, char *argv[])
/* Getting the file path through the Dwarf_Files should
result in the same path. */
- Dwarf_Files *files;
size_t idx;
if (dwarf_line_file (l, &files, &idx) != 0)
{
diff --git a/tests/run-get-files.sh b/tests/run-get-files.sh
index 1306544d..baf107d6 100755
--- a/tests/run-get-files.sh
+++ b/tests/run-get-files.sh
@@ -18,7 +18,7 @@
. $srcdir/test-subr.sh
-testfiles testfile testfile2
+testfiles testfile testfile2 testfile-define-file
testrun_compare ${abs_builddir}/get-files testfile testfile2 <<\EOF
cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 191
@@ -245,4 +245,75 @@ cuhl = 11, o = 0, asz = 8, osz = 4, ncu = 857
file[3] = "/usr/include/stdc-predef.h"
EOF
+tempfiles files define-files.out get-files-define-file.out
+
+cat > files <<\EOF
+ dirs[0] = "session"
+ dirs[1] = "/home/wcohen/minimal_mod"
+ dirs[2] = "include/asm"
+ dirs[3] = "include/linux"
+ dirs[4] = "include/asm-generic"
+ file[0] = "???"
+ file[1] = "/home/wcohen/minimal_mod/minimal_mod.c"
+ file[2] = "include/asm/gcc_intrin.h"
+ file[3] = "include/linux/kernel.h"
+ file[4] = "include/asm/processor.h"
+ file[5] = "include/asm/types.h"
+ file[6] = "include/asm/ptrace.h"
+ file[7] = "include/linux/sched.h"
+ file[8] = "include/asm/thread_info.h"
+ file[9] = "include/linux/thread_info.h"
+ file[10] = "include/asm/atomic.h"
+ file[11] = "include/linux/list.h"
+ file[12] = "include/linux/cpumask.h"
+ file[13] = "include/linux/rbtree.h"
+ file[14] = "include/asm/page.h"
+ file[15] = "include/linux/rwsem.h"
+ file[16] = "include/asm/rwsem.h"
+ file[17] = "include/asm/spinlock.h"
+ file[18] = "include/linux/completion.h"
+ file[19] = "include/linux/wait.h"
+ file[20] = "include/linux/aio.h"
+ file[21] = "include/linux/workqueue.h"
+ file[22] = "include/linux/timer.h"
+ file[23] = "include/linux/types.h"
+ file[24] = "include/asm/posix_types.h"
+ file[25] = "include/linux/pid.h"
+ file[26] = "include/linux/time.h"
+ file[27] = "include/linux/capability.h"
+ file[28] = "include/linux/signal.h"
+ file[29] = "include/linux/resource.h"
+ file[30] = "include/linux/sem.h"
+ file[31] = "include/asm/fpu.h"
+ file[32] = "include/linux/fs_struct.h"
+ file[33] = "include/asm/signal.h"
+ file[34] = "include/asm/siginfo.h"
+ file[35] = "include/asm-generic/siginfo.h"
+ file[36] = "include/asm/nodedata.h"
+ file[37] = "include/linux/mmzone.h"
+ file[38] = "include/linux/jiffies.h"
+ file[39] = "include/asm/io.h"
+ file[40] = "include/asm/machvec.h"
+ file[41] = "include/asm/smp.h"
+ file[42] = "include/asm/numa.h"
+ file[43] = "include/linux/slab.h"
+EOF
+
+# Files should be printed 3 times, followed by the two files from
+# DW_LNE_define_file
+cat files > define-files.out
+cat files >> define-files.out
+cat files >> define-files.out
+echo ' file[44] = "include/asm/abc.c"' >> define-files.out
+echo ' file[45] = "include/linux/01.c"' >> define-files.out
+
+# testfile-define-file is a copy of testfile36.debug but with a modified
+# line program. The line program in testfile-define-file consists of
+# two DW_LNE_define_file opcodes.
+#
+# xxd was used to create a hexdump of testfile36.debug and a text editor
+# was used to modify the line program. The modified hexdump was converted
+# back to a binary with xxd -r.
+cat define-files.out | testrun_compare ${abs_builddir}/get-files-define-file testfile-define-file
+
exit 0
diff --git a/tests/testfile-define-file.bz2 b/tests/testfile-define-file.bz2
new file mode 100644
index 00000000..32ee7b76
--- /dev/null
+++ b/tests/testfile-define-file.bz2
Binary files differ