From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18176 invoked by alias); 20 Apr 2004 17:09:02 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 18131 invoked from network); 20 Apr 2004 17:08:55 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sources.redhat.com with SMTP; 20 Apr 2004 17:08:55 -0000 Received: from drow by nevyn.them.org with local (Exim 4.32 #1 (Debian)) id 1BFyjv-0008Hk-5q; Tue, 20 Apr 2004 13:08:55 -0400 Date: Tue, 20 Apr 2004 17:09:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Cc: jimb@redhat.com, ezannoni@redhat.com, eliz@gnu.org Subject: [rfa/dwarf/doc] Inter-compilation-unit reference support for partial DIEs Message-ID: <20040420170855.GA31548@nevyn.them.org> Mail-Followup-To: gdb-patches@sources.redhat.com, jimb@redhat.com, ezannoni@redhat.com, eliz@gnu.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.5.1+cvs20040105i X-SW-Source: 2004-04/txt/msg00467.txt.bz2 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? -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer 2004-04-20 Daniel Jacobowitz * Makefile.in (dwarf2read.o): Update dependencies. * dwarf2read.c: Include "splay-tree.h", "command.h", and "gdbcmd.h". (struct dwarf2_per_objfile): Add cu_tree 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 cu_tree. (psymtab_to_symtab_1): Initialize 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, splay_tree_obstack_allocate) (create_comp_unit_tree, load_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-04-20 Daniel Jacobowitz * 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.546 diff -u -p -r1.546 Makefile.in --- Makefile.in 18 Apr 2004 16:50:29 -0000 1.546 +++ Makefile.in 20 Apr 2004 16:29:31 -0000 @@ -1730,7 +1730,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) $(gdb_string_h) $(gdb_assert_h) $(hashtab_h) + $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) $(hashtab_h) \ + $(splay_tree_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.148 diff -u -p -r1.148 dwarf2read.c --- dwarf2read.c 19 Apr 2004 18:20:50 -0000 1.148 +++ dwarf2read.c 20 Apr 2004 16:29:32 -0000 @@ -44,7 +44,10 @@ #include "dwarf2expr.h" #include "dwarf2loc.h" #include "cp-support.h" +#include "splay-tree.h" #include "hashtab.h" +#include "command.h" +#include "gdbcmd.h" #include #include "gdb_string.h" @@ -166,6 +169,15 @@ struct dwarf2_per_objfile char *macinfo_buffer; char *ranges_buffer; char *loc_buffer; + + /* A tree of all the compilation units. Each member is a pointer + to a struct dwarf2_cu. This will be set if and only if we have + encountered a compilation unit with inter-CU references. */ + splay_tree cu_tree; + + /* 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; @@ -297,6 +309,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 @@ -304,6 +335,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. */ @@ -577,6 +624,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 @@ -933,12 +987,27 @@ dwarf2_symbol_mark_computed (struct attr static char *skip_one_die (char *info_ptr, struct abbrev_info *abbrev, struct dwarf2_cu *cu); +static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit + (unsigned long offset, struct dwarf2_cu *cu); + static void free_stack_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 dwarf2_mark (struct dwarf2_cu *); + +static void dwarf2_clear_marks (struct dwarf2_per_cu_data *); + static void *hashtab_obstack_allocate (void *data, size_t size, size_t count); static void dummy_obstack_deallocate (void *object, void *data); +static void *splay_tree_obstack_allocate (int size, void *data); + static hashval_t partial_die_hash (const void *item); static int partial_die_eq (const void *item_lhs, const void *item_rhs); @@ -1194,6 +1263,52 @@ partial_read_comp_unit_head (struct comp return info_ptr; } +/* Create a tree 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 tree incrementally. */ + +static void +create_comp_unit_tree (struct objfile *objfile) +{ + char *info_ptr = dwarf2_per_objfile->info_buffer; + + /* Initialize the compilation unit tree. */ + dwarf2_per_objfile->cu_tree + = splay_tree_new_with_allocator (splay_tree_compare_ints, + NULL, NULL, + splay_tree_obstack_allocate, + dummy_obstack_deallocate, + &objfile->objfile_obstack); + + 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; + splay_tree_insert (dwarf2_per_objfile->cu_tree, this_cu->offset, + (splay_tree_value) this_cu); + + info_ptr = info_ptr + this_cu->length; + } +} + /* Build the partial symbol table by doing a quick pass through the .debug_info and .debug_abbrev sections. */ @@ -1207,13 +1322,19 @@ 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; + splay_tree cu_tree = NULL; 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 + read_comp_unit_head and read_partial_die) can really know whether the buffer is large enough to hold another complete object. At the moment, they don't actually check that. If .debug_info @@ -1251,12 +1372,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->cu_tree == NULL) + create_comp_unit_tree (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, @@ -1280,6 +1402,36 @@ 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->cu_tree != NULL) + { + splay_tree_node node; + struct dwarf2_per_cu_data *per_cu; + + node = splay_tree_lookup (dwarf2_per_objfile->cu_tree, + cu.header.offset); + gdb_assert (node != NULL); + per_cu = (struct dwarf2_per_cu_data *) node->value; + + /* 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. */ @@ -1326,6 +1478,64 @@ 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 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); + + cu->read_in_chain = dwarf2_per_objfile->read_in_chain; + dwarf2_per_objfile->read_in_chain = this_cu; } /* Process all loaded DIEs for compilation unit CU, starting at FIRST_DIE. @@ -2018,6 +2228,7 @@ psymtab_to_symtab_1 (struct partial_symt /* We're in the global namespace. */ processing_current_prefix = ""; + memset (&cu, 0, sizeof (cu)); obstack_init (&cu.comp_unit_obstack); back_to = make_cleanup (free_stack_comp_unit, &cu); @@ -4437,6 +4648,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); @@ -4880,8 +5102,15 @@ 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); + gdb_assert (per_cu != NULL); + + if (per_cu->cu == NULL) + load_comp_unit (per_cu, cu->objfile); + + 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 @@ -8557,11 +8786,56 @@ dwarf2_symbol_mark_computed (struct attr } } -/* 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. +/* Locate the compilation unit from CU's objfile which contains the + DIE at OFFSET. Returns NULL on failure. + + We assume that OFFSET is not the start of the compilation unit header + (it can be the compilation unit DIE, though, which comes after the + header). */ + +static struct dwarf2_per_cu_data * +dwarf2_find_containing_comp_unit (unsigned long offset, + struct dwarf2_cu *cu) +{ + struct objfile *objfile = cu->objfile; + struct dwarf2_per_cu_data *this_cu; + splay_tree cu_tree; + splay_tree_node node; + + cu_tree = dwarf2_per_objfile->cu_tree; + gdb_assert (cu_tree != NULL); + + node = splay_tree_predecessor (cu_tree, offset); + gdb_assert (node != NULL); + + this_cu = (struct dwarf2_per_cu_data *) node->value; + gdb_assert (offset >= this_cu->offset); + gdb_assert (offset < this_cu->offset + this_cu->length); + 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; - Only used during partial symbol parsing. */ + 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 be + sure to unlink it from the cache. Also release any associated storage + and perform cache maintenance. */ static void free_stack_comp_unit (void *data) @@ -8570,6 +8844,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 @@ -8594,6 +8989,14 @@ dummy_obstack_deallocate (void *object, return; } +/* Allocation function for the libiberty splay tree which uses an obstack. */ + +static void * +splay_tree_obstack_allocate (int size, void *data) +{ + return obstack_alloc ((struct obstack *) data, size); +} + /* Trivial hash function for partial_die_info: the hash value of a DIE is its offset in .debug_info for this objfile. */ @@ -8615,10 +9018,51 @@ 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_cmd ("max-cache-age", class_obscure, var_zinteger, + &dwarf2_max_cache_age, + "Set an upper bound on the age of cached " + "compilation units.\n" + "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.", + "Show the upper bound on the age of cached " + "dwarf2 compilation units.", + 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 20 Apr 2004 16:29:32 -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.41 diff -u -p -r1.41 maint.c --- maint.c 19 Jan 2004 01:20:11 -0000 1.41 +++ maint.c 20 Apr 2004 16:29:32 -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.202 diff -u -p -r1.202 gdb.texinfo --- doc/gdb.texinfo 28 Mar 2004 12:22:55 -0000 1.202 +++ doc/gdb.texinfo 20 Apr 2004 16:29:35 -0000 @@ -19499,6 +19499,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