Re: [RFC/dwarf-2] Add support for included files

Joel Brobecker
2004-04-16T23:08:28Z

[-- Attachment #1: Type: text/plain, Size: 1644 bytes --]

Hello Jim,

> If you add a comment above dwarf_decode_lines explaining how it's
> called, and that PST determines whether we're building psymtabs or
> symtabs, we'll call it even.
>
> I just approved Daniel's mondo psymtab construction patch, so one of
> you is going to get in the others' way. Have fun.

Here is an updated version of the previous patch, adapted to fit in
the current dwarf2read.c after Daniel's changes, and with comments
added. It's actually slightly smaller thanks to Daniel's changes :-).

2004-04-16 Joel Brobecker <brobecker@gnat.com>

* dwarf2read.c (dwarf2_create_include_psymtab): New function.
(dwarf2_build_include_psymtabs): New function.
(read_partial_die): Add new parameter.
(add_file_name): Add forward declaration.
(dwarf_decode_lines): Add new parameter. Enhance this procedure
to be able to determine the list of files included by the
given unit, and build their associated psymtabs.
(dwarf2_build_psymtabs_hard): Build the psymtabs for the
included files as well.
(psymtab_to_symtab_1): Build the symtabs of all dependencies
as well.
(read_file_scope): Update call to read_partial_die.
(load_partial_dies): Likewise.

Tested on x86-linux. No regression, and it fixes the following two
KFAILs:

KFAIL: gdb.base/sep.exp: list using location inside included file
(PRMS: symtab/1607)
KFAIL: gdb.base/sep.exp: breakpoint inside included file
(PRMS: symtab/1607)

If this patch is approved, I'll send another one removing the setup_kfails.

Thanks,
--
Joel

[-- Attachment #2: separate.diff --]
[-- Type: text/plain, Size: 15326 bytes --]

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.146
diff -u -p -r1.146 dwarf2read.c
--- dwarf2read.c 16 Apr 2004 16:12:52 -0000 1.146
+++ dwarf2read.c 16 Apr 2004 23:03:07 -0000
@@ -634,6 +634,13 @@ static void dwarf2_locate_sections (bfd
static void dwarf2_build_psymtabs_easy (struct objfile *, int);
#endif

+static void dwarf2_create_include_psymtab (char *, struct partial_symtab *,
+ struct objfile *);
+
+static void dwarf2_build_include_psymtabs (struct dwarf2_cu *,
+ const unsigned int,
+ struct partial_symtab *);
+
static void dwarf2_build_psymtabs_hard (struct objfile *, int);

static void scan_partial_symbols (struct partial_die_info *,
@@ -677,7 +684,8 @@ static struct partial_die_info *load_par

static char *read_partial_die (struct partial_die_info *,
struct abbrev_info *abbrev, unsigned int,
- bfd *, char *, struct dwarf2_cu *);
+ bfd *, char *, struct dwarf2_cu *,
+ unsigned int *);

static struct partial_die_info *find_partial_die (unsigned long,
struct dwarf2_cu *,
@@ -739,12 +747,15 @@ static struct die_info *die_specificatio

static void free_line_header (struct line_header *lh);

+static void add_file_name (struct line_header *, char *, unsigned int,
+ unsigned int, unsigned int);
+
static struct line_header *(dwarf_decode_line_header
(unsigned int offset,
bfd *abfd, struct dwarf2_cu *cu));

static void dwarf_decode_lines (struct line_header *, char *, bfd *,
- struct dwarf2_cu *);
+ struct dwarf2_cu *, struct partial_symtab *);

static void dwarf2_start_subfile (char *, char *);

@@ -1196,6 +1207,65 @@ partial_read_comp_unit_head (struct comp
return info_ptr;
}

+/* Allocate a new partial symtab for file named NAME and mark this new
+ partial symtab as being an include of PST. */
+
+static void
+dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst,
+ struct objfile *objfile)
+{
+ struct partial_symtab *subpst = allocate_psymtab (name, objfile);
+
+ subpst->section_offsets = pst->section_offsets;
+ subpst->textlow = 0;
+ subpst->texthigh = 0;
+
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset = 0;
+ subpst->n_global_syms = 0;
+ subpst->statics_offset = 0;
+ subpst->n_static_syms = 0;
+ subpst->symtab = NULL;
+ subpst->read_symtab = pst->read_symtab;
+ subpst->readin = 0;
+
+ /* No private part is necessary for include psymtabs. This property
+ can be used to differentiate between such include psymtabs and
+ the regular ones. If it ever happens that a regular psymtab can
+ legitimally have a NULL PST_PRIVATE part, then we'll have to add a
+ dedicated field for that in the dwarf2_pinfo structure. */
+ PST_PRIVATE (subpst) = NULL;
+}
+
+/* Read the line number information located at LINE_OFFSET,
+ and extract the list of sources files included by the
+ source file represented by PST. Build an include partial
+ symtab for each of these included files. */
+
+static void
+dwarf2_build_include_psymtabs (struct dwarf2_cu *cu,
+ const unsigned int line_offset,
+ struct partial_symtab *pst)
+{
+ struct objfile *objfile = cu->objfile;
+ bfd *abfd = objfile->obfd;
+ struct line_header *lh;
+
+ lh = dwarf_decode_line_header (line_offset, abfd, cu);
+ if (lh == NULL)
+ return; /* No linetable, so no includes. */
+
+ dwarf_decode_lines (lh, NULL, abfd, cu, pst);
+
+ free_line_header (lh);
+}
+
+
/* Build the partial symbol table by doing a quick pass through the
.debug_info and .debug_abbrev sections. */

@@ -1266,6 +1336,7 @@ dwarf2_build_psymtabs_hard (struct objfi
struct abbrev_info *abbrev;
unsigned int bytes_read;
struct dwarf2_per_cu_data *this_cu;
+ unsigned int line_offset = 0;

beg_of_comp_unit = info_ptr;

@@ -1294,7 +1365,7 @@ dwarf2_build_psymtabs_hard (struct objfi
/* Read the compilation unit die */
abbrev = peek_die_abbrev (info_ptr, &bytes_read, &cu);
info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read,
- abfd, info_ptr, &cu);
+ abfd, info_ptr, &cu, &line_offset);

/* Set the language we're debugging */
set_cu_language (comp_unit_die.language, &cu);
@@ -1358,6 +1429,10 @@ dwarf2_build_psymtabs_hard (struct objfi
info_ptr = beg_of_comp_unit + cu.header.length
+ cu.header.initial_length_size;

+ /* Get the list of files included in the current compilation unit,
+ and build a psymtab for each of them. */
+ dwarf2_build_include_psymtabs (&cu, line_offset, pst);
+
do_cleanups (back_to_inner);
}
do_cleanups (back_to);
@@ -2041,6 +2116,32 @@ psymtab_to_symtab_1 (struct partial_symt
struct cleanup *back_to;
struct attribute *attr;
CORE_ADDR baseaddr;
+ int i;
+
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", gdb_stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("%s...", pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ gdb_flush (gdb_stdout);
+ }
+ psymtab_to_symtab_1 (pst->dependencies[i]);
+ }
+
+ if (PST_PRIVATE (pst) == NULL)
+ {
+ /* It's an include file, no symbols to read for it.
+ Everything is in the parent symtab. */
+ pst->readin = 1;
+ return;
+ }

dwarf2_per_objfile = objfile_data (pst->objfile, dwarf2_objfile_data_key);

@@ -2329,7 +2430,7 @@ read_file_scope (struct die_info *die, s
{
make_cleanup ((make_cleanup_ftype *) free_line_header,
(void *) line_header);
- dwarf_decode_lines (line_header, comp_dir, abfd, cu);
+ dwarf_decode_lines (line_header, comp_dir, abfd, cu, NULL);
}
}

@@ -4636,7 +4737,7 @@ load_partial_dies (bfd *abfd, char *info
}

info_ptr = read_partial_die (part_die, abbrev, bytes_read,
- abfd, info_ptr, cu);
+ abfd, info_ptr, cu, NULL);

/* This two-pass algorithm for processing partial symbols has a
high cost in cache pressure. Thus, handle some simple cases
@@ -4768,13 +4869,16 @@ load_partial_dies (bfd *abfd, char *info
}
}

-/* Read a minimal amount of information into the minimal die structure. */
+/* Read a minimal amount of information into the minimal die structure.
+ If not NULL, the offset where the Line Number Information data is
+ stored will be saved in LINE_OFFSET. */

static char *
read_partial_die (struct partial_die_info *part_die,
struct abbrev_info *abbrev,
unsigned int abbrev_len, bfd *abfd,
- char *info_ptr, struct dwarf2_cu *cu)
+ char *info_ptr, struct dwarf2_cu *cu,
+ unsigned int *line_offset)
{
unsigned int bytes_read, i;
struct attribute attr;
@@ -4861,6 +4965,9 @@ read_partial_die (struct partial_die_inf
part_die->sibling = dwarf2_per_objfile->info_buffer
+ dwarf2_get_ref_die_offset (&attr, cu);
break;
+ case DW_AT_stmt_list:
+ if (line_offset != NULL)
+ *line_offset = DW_UNSND (&attr);
default:
break;
}
@@ -5801,13 +5908,23 @@ check_cu_functions (CORE_ADDR address, s
return fn->lowpc;
}

-/* Decode the line number information for the compilation unit whose
- line number info is at OFFSET in the .debug_line section.
- The compilation directory of the file is passed in COMP_DIR. */
+/* Decode the Line Number Program (LNP) for the given line_header
+ structure and CU. The actual information extracted and the type
+ of structures created from the LNP depends on the value of PST.
+
+ 1. If PST is NULL, then this procedure uses the data from the program
+ to create all necessary symbol tables, and their linetables.
+ The compilation directory of the file is passed in COMP_DIR,
+ and must not be NULL.
+
+ 2. If PST is not NULL, this procedure reads the program to determine
+ the list of files included by the unit represented by PST, and
+ builds all the associated partial symbol tables. In this case,
+ the value of COMP_DIR is ignored, and can thus be NULL. */

static void
dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
- struct dwarf2_cu *cu)
+ struct dwarf2_cu *cu, struct partial_symtab *pst)
{
char *line_ptr;
char *line_end;
@@ -5816,6 +5933,40 @@ dwarf_decode_lines (struct line_header *
CORE_ADDR baseaddr;
struct objfile *objfile = cu->objfile;

+ /* When decoding the Line Number Program for the purpose of building
+ the partial symtabs included by the current CU, we need to do
+ the following:
+
+ We first scan the Line Header. It contains a list of files referenced
+ by the Line Number Program. We then scan the Line Number Program
+ for opcodes changing the source file. For each file selected in
+ the program, we mark it as included using the FILE_IS_INCLUDED
+ array. Once we're finished scanning the Line Number Program, we can
+ then iterate over FILE_IS_INCLUDED and create a corresponding
+ include partial symtab for each file that was marked as included. */
+
+ /* FILE_IS_INCLUDED is only used when we're creating the psymtabs
+ for the files included by the current unit.
+
+ It is an array allocated on the heap, which size is stored in
+ SIZE_OF_FILE_IS_INCLUDED. Each element of this array corresponds
+ to the file of the same index in the Line Header, as stored in
+ the line_header struct we built for the current unit. Each element
+ is initially set to zero, and then to nonzero if the corresponding
+ file is included. The size of this array may be larger than
+ necessary, and the number of meaningful entries is stored in
+ lh->num_file_names. */
+ char *file_is_included = NULL;
+ int size_of_file_is_included = 0;
+ const int decode_for_pst_p = (pst != NULL);
+
+ if (decode_for_pst_p)
+ {
+ file_is_included = xmalloc (lh->file_names_size * sizeof (char));
+ memset (file_is_included, 0, lh->file_names_size * sizeof (char));
+ size_of_file_is_included = lh->file_names_size;
+ }
+
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));

line_ptr = lh->statement_program_start;
@@ -5833,9 +5984,9 @@ dwarf_decode_lines (struct line_header *
int basic_block = 0;
int end_sequence = 0;

- /* Start a subfile for the current file of the state machine. */
- if (lh->num_file_names >= file)
+ if (!decode_for_pst_p && lh->num_file_names >= file)
{
+ /* Start a subfile for the current file of the state machine. */
/* lh->include_dirs and lh->file_names are 0-based, but the
directory and file name numbers in the statement program
are 1-based. */
@@ -5860,9 +6011,12 @@ dwarf_decode_lines (struct line_header *
address += (adj_opcode / lh->line_range)
* lh->minimum_instruction_length;
line += lh->line_base + (adj_opcode % lh->line_range);
- /* append row to matrix using current values */
- record_line (current_subfile, line,
- check_cu_functions (address, cu));
+ if (!decode_for_pst_p)
+ {
+ /* append row to matrix using current values */
+ record_line (current_subfile, line,
+ check_cu_functions (address, cu));
+ }
basic_block = 1;
}
else switch (op_code)
@@ -5875,7 +6029,8 @@ dwarf_decode_lines (struct line_header *
{
case DW_LNE_end_sequence:
end_sequence = 1;
- record_line (current_subfile, 0, address);
+ if (!decode_for_pst_p)
+ record_line (current_subfile, 0, address);
break;
case DW_LNE_set_address:
address = read_address (abfd, line_ptr, cu, &bytes_read);
@@ -5899,6 +6054,20 @@ dwarf_decode_lines (struct line_header *
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
add_file_name (lh, cur_file, dir_index, mod_time, length);
+
+ if (decode_for_pst_p)
+ {
+ if (size_of_file_is_included != lh->file_names_size)
+ {
+ /* The add_file_name() operation above caused
+ the file_names array size in the line_header
+ struct to be increased. Increase our
+ file_is_included array size accordingly. */
+ file_is_included = xrealloc (file_is_included,
+ lh->file_names_size);
+ }
+ file_is_included [lh->num_file_names - 1] = 0;
+ }
}
break;
default:
@@ -5908,8 +6077,9 @@ dwarf_decode_lines (struct line_header *
}
break;
case DW_LNS_copy:
- record_line (current_subfile, line,
- check_cu_functions (address, cu));
+ if (!decode_for_pst_p)
+ record_line (current_subfile, line,
+ check_cu_functions (address, cu));
basic_block = 0;
break;
case DW_LNS_advance_pc:
@@ -5935,7 +6105,10 @@ dwarf_decode_lines (struct line_header *
dir = lh->include_dirs[fe->dir_index - 1];
else
dir = comp_dir;
- dwarf2_start_subfile (fe->name, dir);
+ if (decode_for_pst_p)
+ file_is_included[file - 1] = 1;
+ else
+ dwarf2_start_subfile (fe->name, dir);
}
break;
case DW_LNS_set_column:
@@ -5972,6 +6145,22 @@ dwarf_decode_lines (struct line_header *
}
}
}
+ }
+
+ if (decode_for_pst_p)
+ {
+ int file_index;
+
+ /* Now that we're done scanning the Line Header Program, we can
+ create the psymtab of each included file. */
+ for (file_index = 0; file_index < lh->num_file_names; file_index++)
+ if (file_is_included[file_index] == 1)
+ {
+ char *include_name = lh->file_names [file_index].name;
+
+ if (strcmp (include_name, pst->filename) != 0)
+ dwarf2_create_include_psymtab (include_name, pst, objfile);
+ }
}
}