This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [rfa/dwarf/doc] Inter-compilation-unit reference support for partial DIEs
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sources dot redhat dot com, jimb at redhat dot com
- Date: Thu, 16 Sep 2004 17:15:43 -0400
- Subject: Re: [rfa/dwarf/doc] Inter-compilation-unit reference support for partial DIEs
- References: <20040420170855.GA31548@nevyn.them.org>
On Tue, Apr 20, 2004 at 01:08:55PM -0400, Daniel Jacobowitz wrote:
> Here we go. This patch is enough to load binaries which use
> inter-compilation-unit references, as long as you don't do anything which
> would cause full symbol tables to be generated - of course, that's not
> especially useful!
>
> Here's how it works. First, when we read in the abbrevs for each
> compilation unit, we check whether there are any attributes which might
> indicate inter-cu references. If they are, we set a flag, and we build a
> tree of dwarf2_per_cu_data structures, which describe a minimal amount of
> information about every compilation unit in the objfile. If we see a
> reference, we look up the containing compilation unit in the tree.
> This lets us find the start offset of the needed compilation unit. We load
> it, and store a pointer to it in the tree.
>
> When we're finished processing a compilation unit, we age everything in the
> cache, and free things which have exceeded the user-settable cache age
> limit - it's a limit on how many compilation units can be processed in a row
> that do not mention a particular cached item. The default (5) is a
> reasonable tradeoff between speed and memory use; it's a factor of six
> faster than disabling caching, and a factor of twenty less memory usage than
> never releasing cached items, in some crude testing.
>
>
> The machinery used to age the cache probably looks a little overcomplicated;
> in particular, there's no need for dwarf2_mark in this patch. That's
> because a partial symbol table won't have dependencies on other partial
> symbol tables, given the way we currently support references in partial
> DIEs - more specifically, because of the way we build partial symbol tables.
> We only fetch name and flag information from references, so we can use a
> referenced compilation unit before we've built a symbol table for it.
>
> The machinery is necessary for full DIEs, because we can't use references to
> a comp unit before we've built its symbol table. I maintain the invariant
> that we load DIEs for all CUs which we are going to need in the processing
> of a particular CU before we begin building any symbol tables, so we have to
> track dependencies, and make sure things don't fall out of the cache
> unexpectedly. I think there's another valid approach to this problem,
> but it doesn't save much over this one, and it adds considerable complexity
> to demand-(re-)load the extra CUs.
>
>
> Dwarf changes OK? Doc changes OK? Comments/suggestions?
Doc changes already approved. Dwarf changes reposted with all
of Jim's feedback incorporated, as far as I can tell. Tested
i386-pc-linux-gnu, no regressions.
Jim, did I get everything? Does it look OK now?
--
Daniel Jacobowitz
2004-09-16 Daniel Jacobowitz <dan@debian.org>
* Makefile.in (dwarf2read.o): Update dependencies.
* dwarf2read.c: Include "command.h" and "gdbcmd.h".
(struct dwarf2_per_objfile): Add all_comp_units, n_comp_units,
and read_in_chain.
(struct dwarf2_cu): Add read_in_chain, per_cu, last_used,
mark, and has_form_ref_addr.
(struct dwarf2_per_cu_data): New.
(dwarf2_max_cache_age): New.
(dwarf2_build_psymtabs_hard): Free cached compilation units
after loading. Create and manage the list of compilation units.
Remove unnecessary NULL initialization. Fix indentation.
(psymtab_to_symtab_1): Initialize all of CU.
(dwarf2_read_abbrevs): Set has_form_ref_addr.
(find_partial_die): Use dwarf2_find_containing_comp_unit
and load_comp_unit.
(free_stack_comp_unit): Update comments. Clear the per-cu
pointer. Handle aging.
(dwarf2_find_containing_comp_unit, free_cached_comp_units)
(age_cached_comp_units, free_one_cached_comp_unit)
(dwarf2_mark, dwarf2_clear_marks, create_all_comp_units)
(load_comp_unit, dwarf2_find_comp_unit, free_one_comp_unit)
(set_dwarf2_cmdlist, show_dwarf2_cmdlist, set_dwarf2_cmd)
(show_dwarf2_cmd): New.
(_initialize_dwarf2_read): Provide "maint set dwarf2 max-cache-age"
and "maint show dwarf2 max-cache-age".
* gdbcmd.h (maintenance_set_cmdlist, maintenance_show_cmdlist): New
externs.
* maint.c (maintenance_set_cmdlist, maintenance_show_cmdlist): Make
global.
2004-09-16 Daniel Jacobowitz <dan@debian.org>
* gdb.texinfo (Maintenance Commands): Document "maint set dwarf2
max-cache-age" and "maint show dwarf2 max-cache-age".
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.619
diff -u -p -r1.619 Makefile.in
--- Makefile.in 13 Sep 2004 20:55:36 -0000 1.619
+++ Makefile.in 16 Sep 2004 21:13:21 -0000
@@ -1836,7 +1836,8 @@ dwarf2read.o: dwarf2read.c $(defs_h) $(b
$(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) $(demangle_h) \
$(expression_h) $(filenames_h) $(macrotab_h) $(language_h) \
$(complaints_h) $(bcache_h) $(dwarf2expr_h) $(dwarf2loc_h) \
- $(cp_support_h) $(hashtab_h) $(gdb_string_h) $(gdb_assert_h)
+ $(cp_support_h) $(hashtab_h) $(gdb_string_h) $(gdb_assert_h) \
+ $(command_h) $(gdbcmd_h)
dwarfread.o: dwarfread.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(objfiles_h) \
$(elf_dwarf_h) $(buildsym_h) $(demangle_h) $(expression_h) \
$(language_h) $(complaints_h) $(gdb_string_h)
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.160
diff -u -p -r1.160 dwarf2read.c
--- dwarf2read.c 1 Sep 2004 04:19:21 -0000 1.160
+++ dwarf2read.c 16 Sep 2004 21:13:22 -0000
@@ -45,6 +45,8 @@
#include "dwarf2loc.h"
#include "cp-support.h"
#include "hashtab.h"
+#include "command.h"
+#include "gdbcmd.h"
#include <fcntl.h>
#include "gdb_string.h"
@@ -166,6 +168,18 @@ struct dwarf2_per_objfile
char *macinfo_buffer;
char *ranges_buffer;
char *loc_buffer;
+
+ /* A list of all the compilation units. This will be set if and
+ only if we have encountered a compilation unit with inter-CU
+ references. */
+ struct dwarf2_per_cu_data **all_comp_units;
+
+ /* The number of compilation units in ALL_COMP_UNITS. */
+ int n_comp_units;
+
+ /* A chain of compilation units that are currently read in, so that
+ they can be freed later. */
+ struct dwarf2_per_cu_data *read_in_chain;
};
static struct dwarf2_per_objfile *dwarf2_per_objfile;
@@ -299,6 +313,25 @@ struct dwarf2_cu
unit, including partial DIEs. */
struct obstack comp_unit_obstack;
+ /* When multiple dwarf2_cu structures are living in memory, this field
+ chains them all together, so that they can be released efficiently.
+ We will probably also want a generation counter so that most-recently-used
+ compilation units are cached... */
+ struct dwarf2_per_cu_data *read_in_chain;
+
+ /* Backchain to our per_cu entry if the tree has been built. */
+ struct dwarf2_per_cu_data *per_cu;
+
+ /* How many compilation units ago was this CU last referenced? */
+ int last_used;
+
+ /* Mark used when releasing cached dies. */
+ unsigned int mark : 1;
+
+ /* This flag will be set if this compilation unit might include
+ inter-compilation-unit references. */
+ unsigned int has_form_ref_addr : 1;
+
/* This flag will be set if this compilation unit includes any
DW_TAG_namespace DIEs. If we know that there are explicit
DIEs for namespaces, we don't need to try to infer them
@@ -306,6 +339,22 @@ struct dwarf2_cu
unsigned int has_namespace_info : 1;
};
+struct dwarf2_per_cu_data
+{
+ /* The start offset and length of this compilation unit. 2**31-1
+ bytes should suffice to store the length of any compilation unit
+ - if it doesn't, GDB will fall over anyway. */
+ unsigned long offset;
+ unsigned long length : 31;
+
+ /* Flag indicating this compilation unit will be read in before
+ any of the current compilation units are processed. */
+ unsigned long queued : 1;
+
+ /* Set iff currently read in. */
+ struct dwarf2_cu *cu;
+};
+
/* The line number information for a compilation unit (found in the
.debug_line section) begins with a "statement program header",
which contains the following information. */
@@ -585,6 +634,13 @@ struct field_info
int nfnfields;
};
+/* Loaded secondary compilation units are kept in memory until they
+ have not been referenced for the processing of this many
+ compilation units. Set this to zero to disable caching. Cache
+ sizes of up to at least twenty will improve startup time for
+ typical inter-CU-reference binaries, at an obvious memory cost. */
+static int dwarf2_max_cache_age = 5;
+
/* Various complaints about symbol reading that don't abort the process */
static void
@@ -964,6 +1020,26 @@ static hashval_t partial_die_hash (const
static int partial_die_eq (const void *item_lhs, const void *item_rhs);
+static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
+ (unsigned long offset, struct objfile *objfile);
+
+static struct dwarf2_per_cu_data *dwarf2_find_comp_unit
+ (unsigned long offset, struct objfile *objfile);
+
+static void free_one_comp_unit (void *);
+
+static void free_cached_comp_units (void *);
+
+static void age_cached_comp_units (void);
+
+static void free_one_cached_comp_unit (void *);
+
+static void create_all_comp_units (struct objfile *);
+
+static void dwarf2_mark (struct dwarf2_cu *);
+
+static void dwarf2_clear_marks (struct dwarf2_per_cu_data *);
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
@@ -1290,10 +1366,15 @@ dwarf2_build_psymtabs_hard (struct objfi
char *beg_of_comp_unit;
struct partial_die_info comp_unit_die;
struct partial_symtab *pst;
+ struct cleanup *back_to;
CORE_ADDR lowpc, highpc, baseaddr;
info_ptr = dwarf2_per_objfile->info_buffer;
+ /* Any cached compilation units will be linked by the per-objfile
+ read_in_chain. Make sure to free them when we're done. */
+ back_to = make_cleanup (free_cached_comp_units, NULL);
+
/* Since the objects we're extracting from .debug_info vary in
length, only the individual functions to extract them (like
read_comp_unit_head and load_partial_die) can really know whether
@@ -1334,12 +1415,13 @@ dwarf2_build_psymtabs_hard (struct objfi
cu.list_in_scope = &file_symbols;
- cu.partial_dies = NULL;
-
/* Read the abbrevs for this compilation unit into a table */
dwarf2_read_abbrevs (abfd, &cu);
make_cleanup (dwarf2_free_abbrev_table, &cu);
+ if (cu.has_form_ref_addr && dwarf2_per_objfile->all_comp_units == NULL)
+ create_all_comp_units (objfile);
+
/* 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,
@@ -1355,8 +1437,8 @@ dwarf2_build_psymtabs_hard (struct objfi
objfile->global_psymbols.next,
objfile->static_psymbols.next);
- if (comp_unit_die.dirname)
- pst->dirname = xstrdup (comp_unit_die.dirname);
+ if (comp_unit_die.dirname)
+ pst->dirname = xstrdup (comp_unit_die.dirname);
pst->read_symtab_private = (char *)
obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_pinfo));
@@ -1366,6 +1448,32 @@ dwarf2_build_psymtabs_hard (struct objfi
/* Store the function that reads in the rest of the symbol table */
pst->read_symtab = dwarf2_psymtab_to_symtab;
+ if (dwarf2_per_objfile->all_comp_units != NULL)
+ {
+ struct dwarf2_per_cu_data *per_cu;
+
+ per_cu = dwarf2_find_comp_unit (cu.header.offset, objfile);
+
+ /* If this compilation unit was already read in, free the
+ cached copy in order to read it in again. This is
+ necessary because we skipped some symbols when we first
+ read in the compilation unit (see load_partial_dies).
+ This problem could be avoided, but the benefit is
+ unclear. */
+ if (per_cu->cu != NULL)
+ free_one_cached_comp_unit (per_cu->cu);
+
+ cu.per_cu = per_cu;
+
+ /* Note that this is a pointer to our stack frame, being
+ added to a global data structure. It will be cleaned up
+ in free_stack_comp_unit when we finish with this
+ compilation unit. */
+ per_cu->cu = &cu;
+ }
+ else
+ cu.per_cu = NULL;
+
/* Check if comp unit has_children.
If so, read the rest of the partial symbols from this comp unit.
If not, there's no more debug_info for this comp unit. */
@@ -1419,6 +1527,122 @@ dwarf2_build_psymtabs_hard (struct objfi
do_cleanups (back_to_inner);
}
+ do_cleanups (back_to);
+}
+
+/* Load the DIEs for a secondary CU into memory. */
+
+static void
+load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ char *info_ptr, *beg_of_comp_unit;
+ struct partial_die_info comp_unit_die;
+ struct dwarf2_cu *cu;
+ struct abbrev_info *abbrev;
+ unsigned int bytes_read;
+ struct cleanup *back_to;
+
+ info_ptr = dwarf2_per_objfile->info_buffer + this_cu->offset;
+ beg_of_comp_unit = info_ptr;
+
+ cu = xmalloc (sizeof (struct dwarf2_cu));
+ memset (cu, 0, sizeof (struct dwarf2_cu));
+
+ obstack_init (&cu->comp_unit_obstack);
+
+ cu->objfile = objfile;
+ info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr, abfd);
+
+ /* Complete the cu_header. */
+ cu->header.offset = beg_of_comp_unit - dwarf2_per_objfile->info_buffer;
+ cu->header.first_die_ptr = info_ptr;
+ cu->header.cu_head_ptr = beg_of_comp_unit;
+
+ /* Read the abbrevs for this compilation unit into a table. */
+ dwarf2_read_abbrevs (abfd, cu);
+ back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+
+ /* 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);
+
+ /* Set the language we're debugging. */
+ set_cu_language (comp_unit_die.language, cu);
+
+ /* Link this compilation unit into the compilation unit tree. */
+ this_cu->cu = cu;
+ cu->per_cu = this_cu;
+
+ /* Check if comp unit has_children.
+ If so, read the rest of the partial symbols from this comp unit.
+ If not, there's no more debug_info for this comp unit. */
+ if (comp_unit_die.has_children)
+ load_partial_dies (abfd, info_ptr, 0, cu);
+
+ do_cleanups (back_to);
+}
+
+/* Create a list of all compilation units in OBJFILE. We do this only
+ if an inter-comp-unit reference is found; presumably if there is one,
+ there will be many, and one will occur early in the .debug_info section.
+ So there's no point in building this list incrementally. */
+
+static void
+create_all_comp_units (struct objfile *objfile)
+{
+ int n_allocated;
+ int n_comp_units;
+ struct dwarf2_per_cu_data **all_comp_units;
+ char *info_ptr = dwarf2_per_objfile->info_buffer;
+
+ n_comp_units = 0;
+ n_allocated = 10;
+ all_comp_units = xmalloc (n_allocated
+ * sizeof (struct dwarf2_per_cu_data *));
+
+ while (info_ptr < dwarf2_per_objfile->info_buffer + dwarf2_per_objfile->info_size)
+ {
+ struct comp_unit_head cu_header;
+ char *beg_of_comp_unit;
+ struct dwarf2_per_cu_data *this_cu;
+ unsigned long offset;
+ int bytes_read;
+
+ offset = info_ptr - dwarf2_per_objfile->info_buffer;
+
+ /* Read just enough information to find out where the next
+ compilation unit is. */
+ cu_header.length = read_initial_length (objfile->obfd, info_ptr,
+ &cu_header, &bytes_read);
+
+ /* Save the compilation unit for later lookup. */
+ this_cu = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_per_cu_data));
+ memset (this_cu, 0, sizeof (*this_cu));
+ this_cu->offset = offset;
+ this_cu->length = cu_header.length + cu_header.initial_length_size;
+
+ if (n_comp_units == n_allocated)
+ {
+ n_allocated *= 2;
+ all_comp_units = xrealloc (all_comp_units,
+ n_allocated
+ * sizeof (struct dwarf2_per_cu_data *));
+ }
+ all_comp_units[n_comp_units++] = this_cu;
+
+ info_ptr = info_ptr + this_cu->length;
+ }
+
+ dwarf2_per_objfile->all_comp_units
+ = obstack_alloc (&objfile->objfile_obstack,
+ n_comp_units * sizeof (struct dwarf2_per_cu_data *));
+ memcpy (dwarf2_per_objfile->all_comp_units, all_comp_units,
+ n_comp_units * sizeof (struct dwarf2_per_cu_data *));
+ xfree (all_comp_units);
+ dwarf2_per_objfile->n_comp_units = n_comp_units;
}
/* Process all loaded DIEs for compilation unit CU, starting at FIRST_DIE.
@@ -2138,6 +2362,7 @@ psymtab_to_symtab_1 (struct partial_symt
/* We're in the global namespace. */
processing_current_prefix = "";
+ memset (&cu, 0, sizeof (struct dwarf2_cu));
obstack_init (&cu.comp_unit_obstack);
back_to = make_cleanup (free_stack_comp_unit, &cu);
@@ -4607,6 +4832,17 @@ dwarf2_read_abbrevs (bfd *abfd, struct d
= xrealloc (cur_attrs, (allocated_attrs
* sizeof (struct attr_abbrev)));
}
+
+ /* Record whether this compilation unit might have
+ inter-compilation-unit references. If we don't know what form
+ this attribute will have, then it might potentially be a
+ DW_FORM_ref_addr, so we conservatively expect inter-CU
+ references. */
+
+ if (abbrev_form == DW_FORM_ref_addr
+ || abbrev_form == DW_FORM_indirect)
+ cu->has_form_ref_addr = 1;
+
cur_attrs[cur_abbrev->num_attrs].name = abbrev_name;
cur_attrs[cur_abbrev->num_attrs++].form = abbrev_form;
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
@@ -5058,8 +5294,25 @@ find_partial_die (unsigned long offset,
return find_partial_die_in_comp_unit (offset, cu);
}
- internal_error (__FILE__, __LINE__,
- "unsupported inter-compilation-unit reference");
+ per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile);
+
+ /* If this offset isn't pointing into a known compilation unit,
+ the debug information is probably corrupted. */
+ if (per_cu == NULL)
+ error ("Dwarf Error: could not find partial DIE containing "
+ "offset 0x%lx [in module %s]",
+ (long) offset, bfd_get_filename (cu->objfile->obfd));
+
+ if (per_cu->cu == NULL)
+ {
+ load_comp_unit (per_cu, cu->objfile);
+ per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+ dwarf2_per_objfile->read_in_chain = per_cu;
+ }
+
+ per_cu->cu->last_used = 0;
+ *target_cu = per_cu->cu;
+ return find_partial_die_in_comp_unit (offset, per_cu->cu);
}
/* Adjust PART_DIE before generating a symbol for it. This function
@@ -8777,9 +9030,81 @@ dwarf2_symbol_mark_computed (struct attr
}
}
+/* Locate the compilation unit from CU's objfile which contains the
+ DIE at OFFSET. Returns NULL on failure. */
+
+static struct dwarf2_per_cu_data *
+dwarf2_find_containing_comp_unit (unsigned long offset,
+ struct objfile *objfile)
+{
+ struct dwarf2_per_cu_data *this_cu;
+ int low, high;
+
+ if (dwarf2_per_objfile->all_comp_units == NULL)
+ error ("Dwarf Error: offset 0x%lx points outside this "
+ "compilation unit [in module %s]",
+ offset, bfd_get_filename (objfile->obfd));
+
+ low = 0;
+ high = dwarf2_per_objfile->n_comp_units - 1;
+ while (high > low)
+ {
+ int mid = low + (high - low) / 2;
+ if (dwarf2_per_objfile->all_comp_units[mid]->offset >= offset)
+ high = mid;
+ else
+ low = mid + 1;
+ }
+ gdb_assert (low == high);
+ if (dwarf2_per_objfile->all_comp_units[low]->offset > offset)
+ {
+ gdb_assert (low > 0);
+ gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->offset <= offset);
+ return dwarf2_per_objfile->all_comp_units[low-1];
+ }
+ else
+ {
+ this_cu = dwarf2_per_objfile->all_comp_units[low];
+ if (low == dwarf2_per_objfile->n_comp_units - 1
+ && offset >= this_cu->offset + this_cu->length)
+ error ("invalid dwarf2 offset %ld", offset);
+ gdb_assert (offset < this_cu->offset + this_cu->length);
+ return this_cu;
+ }
+}
+
+static struct dwarf2_per_cu_data *
+dwarf2_find_comp_unit (unsigned long offset, struct objfile *objfile)
+{
+ struct dwarf2_per_cu_data *this_cu;
+ this_cu = dwarf2_find_containing_comp_unit (offset, objfile);
+ if (this_cu->offset != offset)
+ error ("no compilation unit with offset %ld\n", offset);
+ return this_cu;
+}
+
+/* Release one cached compilation unit, CU. We unlink it from the tree
+ of compilation units, but we don't remove it from the read_in_chain;
+ the caller is responsible for that. */
+
+static void
+free_one_comp_unit (void *data)
+{
+ struct dwarf2_cu *cu = data;
+
+ if (cu->per_cu != NULL)
+ cu->per_cu->cu = NULL;
+ cu->per_cu = NULL;
+
+ obstack_free (&cu->comp_unit_obstack, NULL);
+
+ xfree (cu);
+}
+
/* This cleanup function is passed the address of a dwarf2_cu on the stack
- when we're finished with it. We can't free the pointer itself, but
- release any associated storage.
+ when we're finished with it. We can't free the pointer itself, but be
+ sure to unlink it from the cache. Also release any associated storage
+ and perform cache maintenance.
Only used during partial symbol parsing. */
@@ -8790,6 +9115,127 @@ free_stack_comp_unit (void *data)
obstack_free (&cu->comp_unit_obstack, NULL);
cu->partial_dies = NULL;
+
+ if (cu->per_cu != NULL)
+ {
+ /* This compilation unit is on the stack in our caller, so we
+ should not xfree it. Just unlink it. */
+ cu->per_cu->cu = NULL;
+ cu->per_cu = NULL;
+
+ /* If we had a per-cu pointer, then we may have other compilation
+ units loaded, so age them now. */
+ age_cached_comp_units ();
+ }
+}
+
+/* Free all cached compilation units. */
+
+static void
+free_cached_comp_units (void *data)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+
+ per_cu = next_cu;
+ }
+}
+
+/* Increase the age counter on each cached compilation unit, and free
+ any that are too old. */
+
+static void
+age_cached_comp_units (void)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ dwarf2_clear_marks (dwarf2_per_objfile->read_in_chain);
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ per_cu->cu->last_used ++;
+ if (per_cu->cu->last_used <= dwarf2_max_cache_age)
+ dwarf2_mark (per_cu->cu);
+ per_cu = per_cu->cu->read_in_chain;
+ }
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ if (!per_cu->cu->mark)
+ {
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+ }
+ else
+ last_chain = &per_cu->cu->read_in_chain;
+
+ per_cu = next_cu;
+ }
+}
+
+/* Remove a single compilation unit from the cache. */
+
+static void
+free_one_cached_comp_unit (void *target_cu)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ if (per_cu->cu == target_cu)
+ {
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+ break;
+ }
+ else
+ last_chain = &per_cu->cu->read_in_chain;
+
+ per_cu = next_cu;
+ }
+}
+
+/* Set the mark field in CU and in every other compilation unit in the
+ cache that we must keep because we are keeping CU. */
+
+static void
+dwarf2_mark (struct dwarf2_cu *cu)
+{
+ if (cu->mark)
+ return;
+ cu->mark = 1;
+}
+
+static void
+dwarf2_clear_marks (struct dwarf2_per_cu_data *per_cu)
+{
+ while (per_cu)
+ {
+ per_cu->cu->mark = 0;
+ per_cu = per_cu->cu->read_in_chain;
+ }
}
/* Allocation function for the libiberty hash table which uses an
@@ -8835,10 +9281,53 @@ partial_die_eq (const void *item_lhs, co
return part_die_lhs->offset == part_die_rhs->offset;
}
+static struct cmd_list_element *set_dwarf2_cmdlist;
+static struct cmd_list_element *show_dwarf2_cmdlist;
+
+static void
+set_dwarf2_cmd (char *args, int from_tty)
+{
+ help_list (set_dwarf2_cmdlist, "maintenance set dwarf2 ", -1, gdb_stdout);
+}
+
+static void
+show_dwarf2_cmd (char *args, int from_tty)
+{
+ cmd_show_list (show_dwarf2_cmdlist, from_tty, "");
+}
+
void _initialize_dwarf2_read (void);
void
_initialize_dwarf2_read (void)
{
dwarf2_objfile_data_key = register_objfile_data ();
+
+ add_prefix_cmd ("dwarf2", class_maintenance, set_dwarf2_cmd,
+ "Set DWARF 2 specific variables.\n"
+ "Configure DWARF 2 variables such as the cache size",
+ &set_dwarf2_cmdlist, "maintenance set dwarf2 ",
+ 0/*allow-unknown*/, &maintenance_set_cmdlist);
+
+ add_prefix_cmd ("dwarf2", class_maintenance, show_dwarf2_cmd,
+ "Show DWARF 2 specific variables\n"
+ "Show DWARF 2 variables such as the cache size",
+ &show_dwarf2_cmdlist, "maintenance show dwarf2 ",
+ 0/*allow-unknown*/, &maintenance_show_cmdlist);
+
+ add_setshow_zinteger_cmd ("max-cache-age", class_obscure,
+ &dwarf2_max_cache_age,
+ "Set the upper bound on the age of cached "
+ "dwarf2 compilation units.",
+ "Show the upper bound on the age of cached "
+ "dwarf2 compilation units.",
+ "A higher limit means that cached "
+ "compilation units will be stored\n"
+ "in memory longer, and more total memory will "
+ "be used. Zero disables\n"
+ "caching, which can slow down startup.",
+ "The upper bound on the age of cached "
+ "dwarf2 compilation units is %d.",
+ NULL, NULL, &set_dwarf2_cmdlist,
+ &show_dwarf2_cmdlist);
}
Index: gdbcmd.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbcmd.h,v
retrieving revision 1.10
diff -u -p -r1.10 gdbcmd.h
--- gdbcmd.h 7 May 2003 21:42:47 -0000 1.10
+++ gdbcmd.h 16 Sep 2004 21:13:22 -0000
@@ -98,6 +98,14 @@ extern struct cmd_list_element *maintena
extern struct cmd_list_element *maintenanceprintlist;
+/* Chain containing all defined "maintenance set" subcommands. */
+
+extern struct cmd_list_element *maintenance_set_cmdlist;
+
+/* Chain containing all defined "maintenance show" subcommands. */
+
+extern struct cmd_list_element *maintenance_show_cmdlist;
+
extern struct cmd_list_element *setprintlist;
extern struct cmd_list_element *showprintlist;
Index: maint.c
===================================================================
RCS file: /cvs/src/src/gdb/maint.c,v
retrieving revision 1.44
diff -u -p -r1.44 maint.c
--- maint.c 11 Sep 2004 10:24:49 -0000 1.44
+++ maint.c 16 Sep 2004 21:13:22 -0000
@@ -609,8 +609,8 @@ maintenance_do_deprecate (char *text, in
/* Maintenance set/show framework. */
-static struct cmd_list_element *maintenance_set_cmdlist;
-static struct cmd_list_element *maintenance_show_cmdlist;
+struct cmd_list_element *maintenance_set_cmdlist;
+struct cmd_list_element *maintenance_show_cmdlist;
static void
maintenance_set_cmd (char *args, int from_tty)
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.212
diff -u -p -r1.212 gdb.texinfo
--- doc/gdb.texinfo 30 Jul 2004 19:23:54 -0000 1.212
+++ doc/gdb.texinfo 16 Sep 2004 21:13:25 -0000
@@ -19542,6 +19542,19 @@ data in a @file{gmon.out} file, be sure
Configuring with @samp{--enable-profiling} arranges for @value{GDBN} to be
compiled with the @samp{-pg} compiler option.
+@kindex maint set dwarf2 max-cache-age
+@kindex maint show dwarf2 max-cache-age
+@item maint set dwarf2 max-cache-age
+@itemx maint show dwarf2 max-cache-age
+Control the DWARF 2 compilation unit cache.
+
+In object files with inter-compilation-unit references, such as those
+produced by the GCC option @samp{-feliminate-dwarf2-dups}, the DWARF 2
+reader needs to frequently refer to previously read compilation units.
+This setting controls how long a compilation unit will remain in the cache
+if it is not referenced. Setting it to zero disables caching, which will
+slow down @value{GDBN} startup but reduce memory consumption.
+
@end table