From 80626a55b99a0cb91546f334fc683f7a9f351101 Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Mon, 5 Nov 2012 15:50:22 +0000 Subject: [PATCH] Add support for DWP files. http://gcc.gnu.org/wiki/DebugFissionDWP * contrib/cc-with-tweaks.sh: Add -p parameter to invoke dwp. * dwarf2read.c: #include "elf-bfd.h". (struct dwarf2_per_objfile): New members dwp_checked, dwp_file. (dwop_section_names): Renamed from dwo_section names. All uses updated. Add entries for .debug_cu_index, .debug_tu_index. (struct dwo_file): Rename dwo_name to name, dwo_bfd to dbfd. All uses updated. (struct dwp_sections): New type. (struct virtual_dwo_sections): New type. (struct dwp_hash_table): New type. (struct dwp_file): New type. (init_cutu_and_read_dies): Ensure DWO info/types section has been read in. Handle DWOs coming from DWP files. (lookup_dwo_file_slot): New function. (dwarf2_locate_dwo_sections): Move definition closer to use. (create_dwo_debug_info_hash_table_reader): Renamed from create_debug_info_hash_table_reader. All callers updated. (create_dwo_debug_info_hash_table): Renamed from create_debug_info_hash_table. All callers updated. (create_dwp_hash_table): New function. (locate_virtual_dwo_sections, create_dwo_in_dwp): New functions. (lookup_dwo_in_dwp): New function. (try_open_dwop_file): Renamed from try_open_dwo_file. New parameter is_dwp. All callers updated. (open_dwop_file): Renamed from open_dwo_file. All callers updated. (open_and_init_dwo_file): Renamed from init_dwo_file. All callers updated. (lookup_dwo_file): Delete. (dwarf2_locate_dwp_sections): New function. (hash_dwp_loaded_cutus, eq_dwp_loaded_cutus): New functions. (allocate_dwp_loaded_cutus_table): New function. (open_and_init_dwp_file): New function. (lookup_dwo_cutu): New function. (lookup_dwo_comp_unit, lookup_dwo_type_unit): Call it. --- gdb/ChangeLog | 38 ++ gdb/contrib/cc-with-tweaks.sh | 11 + gdb/dwarf2read.c | 1057 +++++++++++++++++++++++++++++++++-------- 3 files changed, 921 insertions(+), 185 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f7808a4..ecf6239 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,41 @@ +2012-11-05 Doug Evans + + Add support for DWP files. http://gcc.gnu.org/wiki/DebugFissionDWP + * contrib/cc-with-tweaks.sh: Add -p parameter to invoke dwp. + * dwarf2read.c: #include "elf-bfd.h". + (struct dwarf2_per_objfile): New members dwp_checked, dwp_file. + (dwop_section_names): Renamed from dwo_section names. All uses + updated. Add entries for .debug_cu_index, .debug_tu_index. + (struct dwo_file): Rename dwo_name to name, dwo_bfd to dbfd. + All uses updated. + (struct dwp_sections): New type. + (struct virtual_dwo_sections): New type. + (struct dwp_hash_table): New type. + (struct dwp_file): New type. + (init_cutu_and_read_dies): Ensure DWO info/types section has been + read in. Handle DWOs coming from DWP files. + (lookup_dwo_file_slot): New function. + (dwarf2_locate_dwo_sections): Move definition closer to use. + (create_dwo_debug_info_hash_table_reader): Renamed from + create_debug_info_hash_table_reader. All callers updated. + (create_dwo_debug_info_hash_table): Renamed from + create_debug_info_hash_table. All callers updated. + (create_dwp_hash_table): New function. + (locate_virtual_dwo_sections, create_dwo_in_dwp): New functions. + (lookup_dwo_in_dwp): New function. + (try_open_dwop_file): Renamed from try_open_dwo_file. New parameter + is_dwp. All callers updated. + (open_dwop_file): Renamed from open_dwo_file. All callers updated. + (open_and_init_dwo_file): Renamed from init_dwo_file. + All callers updated. + (lookup_dwo_file): Delete. + (dwarf2_locate_dwp_sections): New function. + (hash_dwp_loaded_cutus, eq_dwp_loaded_cutus): New functions. + (allocate_dwp_loaded_cutus_table): New function. + (open_and_init_dwp_file): New function. + (lookup_dwo_cutu): New function. + (lookup_dwo_comp_unit, lookup_dwo_type_unit): Call it. + 2012-11-03 Yao Qi Fix PR gdb/14617. diff --git a/gdb/contrib/cc-with-tweaks.sh b/gdb/contrib/cc-with-tweaks.sh index bdbdf7d..ccc9c5a 100755 --- a/gdb/contrib/cc-with-tweaks.sh +++ b/gdb/contrib/cc-with-tweaks.sh @@ -61,8 +61,10 @@ then fi OBJCOPY=${OBJCOPY:-objcopy} +READELF=${READELF:-readelf} DWZ=${DWZ:-dwz} +DWP=${DWP:-dwp} have_link=unknown next_is_output_file=no @@ -71,12 +73,14 @@ output_file=a.out want_index=false want_dwz=false want_multi=false +want_dwp=false while [ $# -gt 0 ]; do case "$1" in -z) want_dwz=true ;; -i) want_index=true ;; -m) want_multi=true ;; + -p) want_dwp=true ;; *) break ;; esac shift @@ -159,5 +163,12 @@ elif [ "$want_multi" = true ]; then $DWZ -m ${output_file}.dwz "$output_file" ${output_file}.alt > /dev/null 2>&1 fi +if [ "$want_dwp" = true ]; then + dwo_files=$($READELF -wi "${output_file}" | grep _dwo_name | \ + sed -e 's/^.*: //' | sort | uniq) + $DWP -o "${output_file}.dwp" ${dwo_files} > /dev/null + rm -f ${dwo_files} +fi + rm -f "$index_file" exit $rc diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 2dcba207..1cc8f8a 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -30,6 +30,7 @@ #include "defs.h" #include "bfd.h" +#include "elf-bfd.h" #include "symtab.h" #include "gdbtypes.h" #include "objfiles.h" @@ -234,6 +235,12 @@ struct dwarf2_per_objfile This is NULL if the table hasn't been allocated yet. */ htab_t dwo_files; + /* Non-zero if we've check for whether there is a DWP file. */ + int dwp_checked; + + /* The DWP file if there is one, or NULL. */ + struct dwp_file *dwp_file; + /* The shared '.dwz' file, if one exists. This is used when the original data was compressed using 'dwz -m'. */ struct dwz_file *dwz_file; @@ -293,9 +300,9 @@ static const struct dwarf2_debug_sections dwarf2_elf_names = 23 }; -/* List of DWO sections. */ +/* List of DWO/DWP sections. */ -static const struct dwo_section_names +static const struct dwop_section_names { struct dwarf2_section_names abbrev_dwo; struct dwarf2_section_names info_dwo; @@ -306,8 +313,10 @@ static const struct dwo_section_names struct dwarf2_section_names str_dwo; struct dwarf2_section_names str_offsets_dwo; struct dwarf2_section_names types_dwo; + struct dwarf2_section_names cu_index; + struct dwarf2_section_names tu_index; } -dwo_section_names = +dwop_section_names = { { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo" }, { ".debug_info.dwo", ".zdebug_info.dwo" }, @@ -318,6 +327,8 @@ dwo_section_names = { ".debug_str.dwo", ".zdebug_str.dwo" }, { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" }, { ".debug_types.dwo", ".zdebug_types.dwo" }, + { ".debug_cu_index", ".zdebug_cu_index" }, + { ".debug_tu_index", ".zdebug_tu_index" }, }; /* local data types */ @@ -646,18 +657,19 @@ struct type_unit_group struct symtab **symtabs; }; -/* These sections are what may appear in a "dwo" file. */ +/* These sections are what may appear in a DWO file. */ struct dwo_sections { struct dwarf2_section_info abbrev; - struct dwarf2_section_info info; struct dwarf2_section_info line; struct dwarf2_section_info loc; struct dwarf2_section_info macinfo; struct dwarf2_section_info macro; struct dwarf2_section_info str; struct dwarf2_section_info str_offsets; + /* In the case of a virtual DWO file, these two are unused. */ + struct dwarf2_section_info info; VEC (dwarf2_section_info_def) *types; }; @@ -684,16 +696,21 @@ struct dwo_unit cu_offset type_offset_in_tu; }; -/* Data for one DWO file. */ +/* Data for one DWO file. + This includes virtual DWO files that have been packaged into a + DWP file. */ struct dwo_file { - /* The DW_AT_GNU_dwo_name attribute. - We don't manage space for this, it's an attribute. */ - const char *dwo_name; + /* The DW_AT_GNU_dwo_name attribute. This is the hash key. + For virtual DWO files the name is constructed from the section offsets + of abbrev,line,loc,str_offsets so that we combine virtual DWO files + from related CU+TUs. */ + const char *name; - /* The bfd, when the file is open. Otherwise this is NULL. */ - bfd *dwo_bfd; + /* The bfd, when the file is open. Otherwise this is NULL. + This is unused(NULL) for virtual DWO files where we use dwp_file.dbfd. */ + bfd *dbfd; /* Section info for this file. */ struct dwo_sections sections; @@ -707,6 +724,67 @@ struct dwo_file htab_t tus; }; +/* These sections are what may appear in a DWP file. */ + +struct dwp_sections +{ + struct dwarf2_section_info str; + struct dwarf2_section_info cu_index; + struct dwarf2_section_info tu_index; + /* The .debug_info.dwo, .debug_types.dwo, and other sections are referenced + by section number. We don't need to record them here. */ +}; + +/* These sections are what may appear in a virtual DWO file. */ + +struct virtual_dwo_sections +{ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info line; + struct dwarf2_section_info loc; + struct dwarf2_section_info macinfo; + struct dwarf2_section_info macro; + struct dwarf2_section_info str_offsets; + /* Each DWP hash table entry records one CU or one TU. + That is recorded here, and copied to dwo_unit.info_or_types_section. */ + struct dwarf2_section_info info_or_types; +}; + +/* Contents of DWP hash tables. */ + +struct dwp_hash_table +{ + uint32_t nr_units, nr_slots; + const gdb_byte *hash_table, *unit_table, *section_pool; +}; + +/* Data for one DWP file. */ + +struct dwp_file +{ + /* Name of the file. */ + const char *name; + + /* The bfd, when the file is open. Otherwise this is NULL. */ + bfd *dbfd; + + /* Section info for this file. */ + struct dwp_sections sections; + + /* Table of CUs in the file. */ + const struct dwp_hash_table *cus; + + /* Table of TUs in the file. */ + const struct dwp_hash_table *tus; + + /* Table of loaded CUs/TUs. Each entry is a struct dwo_unit *. */ + htab_t loaded_cutus; + + /* Table to map ELF section numbers to their sections. */ + unsigned int num_sections; + asection **elf_sections; +}; + /* This represents a '.dwz' file. */ struct dwz_file @@ -736,7 +814,7 @@ struct die_reader_specs /* The CU of the DIE we are parsing. */ struct dwarf2_cu *cu; - /* Non-NULL if reading a DWO file. */ + /* Non-NULL if reading a DWO file (including one packaged into a DWP). */ struct dwo_file *dwo_file; /* The section the die comes from. @@ -4030,7 +4108,9 @@ add_signatured_type_cu_to_table (void **slot, void *datum) } /* Create the hash table of all entries in the .debug_types section. - DWO_FILE is a pointer to the DWO file for .debug_types.dwo, NULL otherwise. + DWO_FILE is a pointer to the DWO file for .debug_types.dwo, + NULL otherwise. + Note: This function processes DWO files only, not DWP files. The result is a pointer to the hash table or NULL if there are no types. */ @@ -4511,6 +4591,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, /* Set up for reading the DWO CU/TU. */ cu->dwo_unit = dwo_unit; section = dwo_unit->info_or_types_section; + dwarf2_read_section (objfile, section); begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off; dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev; init_cu_die_reader (&reader, cu, section, dwo_unit->dwo_file); @@ -4518,14 +4599,19 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, if (this_cu->is_debug_types) { ULONGEST signature; + cu_offset type_offset_in_tu; info_ptr = read_and_check_type_unit_head (&cu->header, section, dwo_abbrev_section, info_ptr, - &signature, NULL); + &signature, + &type_offset_in_tu); gdb_assert (sig_type->signature == signature); gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off); - gdb_assert (dwo_unit->length == get_cu_length (&cu->header)); + /* For DWOs coming from DWP files, we don't know the CU length + nor the type's offset in the TU until now. */ + dwo_unit->length = get_cu_length (&cu->header); + dwo_unit->type_offset_in_tu = type_offset_in_tu; /* Establish the type offset that can be used to lookup the type. For DWO files, we don't know it until now. */ @@ -4538,7 +4624,9 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, dwo_abbrev_section, info_ptr, 0); gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off); - gdb_assert (dwo_unit->length == get_cu_length (&cu->header)); + /* For DWOs coming from DWP files, we don't know the CU length + until now. */ + dwo_unit->length = get_cu_length (&cu->header); } /* Discard the original CU's abbrev table, and read the DWO's. */ @@ -4614,8 +4702,8 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, /* Read CU/TU THIS_CU in section SECTION, but do not follow DW_AT_GNU_dwo_name if present. - DWO_FILE, if non-NULL, is the DWO file to read (the caller is assumed to - have already done the lookup to find the DWO file). + DWOP_FILE, if non-NULL, is the DWO/DWP file to read (the caller is assumed + to have already done the lookup to find the DWO/DWP file). The caller is required to fill in THIS_CU->section, THIS_CU->offset, and THIS_CU->is_debug_types, but nothing else. @@ -8005,14 +8093,21 @@ read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu) } } -/* DWO files. */ +/* DWO/DWP files. + + http://gcc.gnu.org/wiki/DebugFission + http://gcc.gnu.org/wiki/DebugFissionDWP + + To simplify handling of both DWO files ("object" files with the DWARF info) + and DWP files (a file with the DWOs packaged up into one file), we treat + DWP files as having a collection of virtual DWO files. */ static hashval_t hash_dwo_file (const void *item) { const struct dwo_file *dwo_file = item; - return htab_hash_string (dwo_file->dwo_name); + return htab_hash_string (dwo_file->name); } static int @@ -8021,7 +8116,7 @@ eq_dwo_file (const void *item_lhs, const void *item_rhs) const struct dwo_file *lhs = item_lhs; const struct dwo_file *rhs = item_rhs; - return strcmp (lhs->dwo_name, rhs->dwo_name) == 0; + return strcmp (lhs->name, rhs->name) == 0; } /* Allocate a hash table for DWO files. */ @@ -8040,6 +8135,24 @@ allocate_dwo_file_hash_table (void) dummy_obstack_deallocate); } +/* Lookup DWO file DWO_NAME. */ + +static void ** +lookup_dwo_file_slot (const char *dwo_name) +{ + struct dwo_file find_entry; + void **slot; + + if (dwarf2_per_objfile->dwo_files == NULL) + dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table (); + + memset (&find_entry, 0, sizeof (find_entry)); + find_entry.name = dwo_name; + slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT); + + return slot; +} + static hashval_t hash_dwo_unit (const void *item) { @@ -8079,68 +8192,7 @@ allocate_dwo_unit_table (struct objfile *objfile) dummy_obstack_deallocate); } -/* This function is mapped across the sections and remembers the offset and - size of each of the DWO debugging sections we are interested in. */ - -static void -dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_file_ptr) -{ - struct dwo_file *dwo_file = dwo_file_ptr; - const struct dwo_section_names *names = &dwo_section_names; - - if (section_is_p (sectp->name, &names->abbrev_dwo)) - { - dwo_file->sections.abbrev.asection = sectp; - dwo_file->sections.abbrev.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->info_dwo)) - { - dwo_file->sections.info.asection = sectp; - dwo_file->sections.info.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->line_dwo)) - { - dwo_file->sections.line.asection = sectp; - dwo_file->sections.line.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->loc_dwo)) - { - dwo_file->sections.loc.asection = sectp; - dwo_file->sections.loc.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->macinfo_dwo)) - { - dwo_file->sections.macinfo.asection = sectp; - dwo_file->sections.macinfo.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->macro_dwo)) - { - dwo_file->sections.macro.asection = sectp; - dwo_file->sections.macro.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->str_dwo)) - { - dwo_file->sections.str.asection = sectp; - dwo_file->sections.str.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->str_offsets_dwo)) - { - dwo_file->sections.str_offsets.asection = sectp; - dwo_file->sections.str_offsets.size = bfd_get_section_size (sectp); - } - else if (section_is_p (sectp->name, &names->types_dwo)) - { - struct dwarf2_section_info type_section; - - memset (&type_section, 0, sizeof (type_section)); - type_section.asection = sectp; - type_section.size = bfd_get_section_size (sectp); - VEC_safe_push (dwarf2_section_info_def, dwo_file->sections.types, - &type_section); - } -} - -/* Structure used to pass data to create_debug_info_hash_table_reader. */ +/* Structure used to pass data to create_dwo_debug_info_hash_table_reader. */ struct create_dwo_info_table_data { @@ -8148,14 +8200,14 @@ struct create_dwo_info_table_data htab_t cu_htab; }; -/* die_reader_func for create_debug_info_hash_table. */ +/* die_reader_func for create_dwo_debug_info_hash_table. */ static void -create_debug_info_hash_table_reader (const struct die_reader_specs *reader, - gdb_byte *info_ptr, - struct die_info *comp_unit_die, - int has_children, - void *datap) +create_dwo_debug_info_hash_table_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *datap) { struct dwarf2_cu *cu = reader->cu; struct objfile *objfile = dwarf2_per_objfile->objfile; @@ -8173,7 +8225,7 @@ create_debug_info_hash_table_reader (const struct die_reader_specs *reader, { error (_("Dwarf Error: debug entry at offset 0x%x is missing" " its dwo_id [in module %s]"), - offset.sect_off, dwo_file->dwo_name); + offset.sect_off, dwo_file->name); return; } @@ -8195,7 +8247,7 @@ create_debug_info_hash_table_reader (const struct die_reader_specs *reader, " offset 0x%x, dwo_id 0x%s [in module %s]"), offset.sect_off, dup_dwo_unit->offset.sect_off, phex (dwo_unit->signature, sizeof (dwo_unit->signature)), - dwo_file->dwo_name); + dwo_file->name); } else *slot = dwo_unit; @@ -8207,10 +8259,12 @@ create_debug_info_hash_table_reader (const struct die_reader_specs *reader, sizeof (dwo_unit->signature))); } -/* Create a hash table to map DWO IDs to their CU entry in .debug_info.dwo. */ +/* Create a hash table to map DWO IDs to their CU entry in + .debug_info.dwo in DWO_FILE. + Note: This function processes DWO files only, not DWP files. */ static htab_t -create_debug_info_hash_table (struct dwo_file *dwo_file) +create_dwo_debug_info_hash_table (struct dwo_file *dwo_file) { struct objfile *objfile = dwarf2_per_objfile->objfile; struct dwarf2_section_info *section = &dwo_file->sections.info; @@ -8252,7 +8306,7 @@ create_debug_info_hash_table (struct dwo_file *dwo_file) init_cutu_and_read_dies_no_follow (&per_cu, &dwo_file->sections.abbrev, dwo_file, - create_debug_info_hash_table_reader, + create_dwo_debug_info_hash_table_reader, &create_dwo_info_table_data); info_ptr += per_cu.length; @@ -8261,21 +8315,428 @@ create_debug_info_hash_table (struct dwo_file *dwo_file) return cu_htab; } -/* Subroutine of open_dwo_file to simplify it. +/* DWP file .debug_{cu,tu}_index section format: + [ref: http://gcc.gnu.org/wiki/DebugFissionDWP] + + Both index sections have the same format, and serve to map a 64-bit + signature to a set of section numbers. Each section begins with a header, + followed by a hash table of 64-bit signatures, a parallel table of 32-bit + indexes, and a pool of 32-bit section numbers. The index sections will be + aligned at 8-byte boundaries in the file. + + The index section header contains two unsigned 32-bit values (using the + byte order of the application binary): + + N, the number of compilation units or type units in the index + M, the number of slots in the hash table + + (We assume that N and M will not exceed 2^32 - 1.) + + The size of the hash table, M, must be 2^k such that 2^k > 3*N/2. + + The hash table begins at offset 8 in the section, and consists of an array + of M 64-bit slots. Each slot contains a 64-bit signature (using the byte + order of the application binary). Unused slots in the hash table are 0. + (We rely on the extreme unlikeliness of a signature being exactly 0.) + + The parallel table begins immediately after the hash table + (at offset 8 + 8 * M from the beginning of the section), and consists of an + array of 32-bit indexes (using the byte order of the application binary), + corresponding 1-1 with slots in the hash table. Each entry in the parallel + table contains a 32-bit index into the pool of section numbers. For unused + hash table slots, the corresponding entry in the parallel table will be 0. + + Given a 64-bit compilation unit signature or a type signature S, an entry + in the hash table is located as follows: + + 1) Calculate a primary hash H = S & MASK(k), where MASK(k) is a mask with + the low-order k bits all set to 1. + + 2) Calculate a secondary hash H' = (((S >> 32) & MASK(k)) | 1). + + 3) If the hash table entry at index H matches the signature, use that + entry. If the hash table entry at index H is unused (all zeroes), + terminate the search: the signature is not present in the table. + + 4) Let H = (H + H') modulo M. Repeat at Step 3. + + Because M > N and H' and M are relatively prime, the search is guaranteed + to stop at an unused slot or find the match. + + The pool of section numbers begins immediately following the hash table + (at offset 8 + 12 * M from the beginning of the section). The pool of + section numbers consists of an array of 32-bit words (using the byte order + of the application binary). Each item in the array is indexed starting + from 0. The hash table entry provides the index of the first section + number in the set. Additional section numbers in the set follow, and the + set is terminated by a 0 entry (section number 0 is not used in ELF). + + In each set of section numbers, the .debug_info.dwo or .debug_types.dwo + section must be the first entry in the set, and the .debug_abbrev.dwo must + be the second entry. Other members of the set may follow in any order. */ + +/* Create a hash table to map DWO IDs to their CU/TU entry in + .debug_{info,types}.dwo in DWP_FILE. + Returns NULL if there isn't one. + Note: This function processes DWP files only, not DWO files. */ + +static struct dwp_hash_table * +create_dwp_hash_table (struct dwp_file *dwp_file, int is_debug_types) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *dbfd = dwp_file->dbfd; + char *index_ptr, *index_end; + struct dwarf2_section_info *index; + uint32_t version, nr_units, nr_slots; + struct dwp_hash_table *htab; + + if (is_debug_types) + index = &dwp_file->sections.tu_index; + else + index = &dwp_file->sections.cu_index; + + if (dwarf2_section_empty_p (index)) + return NULL; + dwarf2_read_section (objfile, index); + + index_ptr = index->buffer; + index_end = index_ptr + index->size; + + version = read_4_bytes (dbfd, index_ptr); + index_ptr += 8; /* Skip the unused word. */ + nr_units = read_4_bytes (dbfd, index_ptr); + index_ptr += 4; + nr_slots = read_4_bytes (dbfd, index_ptr); + index_ptr += 4; + + if (version != 1) + { + error (_("Dwarf Error: unsupported DWP file version (%u)" + " [in module %s]"), + version, dwp_file->name); + } + if (nr_slots != (nr_slots & -nr_slots)) + { + error (_("Dwarf Error: number of slots in DWP hash table (%u)" + " is not power of 2 [in module %s]"), + nr_slots, dwp_file->name); + } + + htab = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_hash_table); + htab->nr_units = nr_units; + htab->nr_slots = nr_slots; + htab->hash_table = index_ptr; + htab->unit_table = htab->hash_table + sizeof (uint64_t) * nr_slots; + htab->section_pool = htab->unit_table + sizeof (uint32_t) * nr_slots; + + return htab; +} + +/* Update SECTIONS with the data from SECTP. + + This function is like the other "locate" section routines that are + passed to bfd_map_over_sections, but in this context the sections to + read comes from the DWP hash table, not the full ELF section table. + + The result is non-zero for success, or zero if an error was found. */ + +static int +locate_virtual_dwo_sections (asection *sectp, + struct virtual_dwo_sections *sections) +{ + const struct dwop_section_names *names = &dwop_section_names; + + if (section_is_p (sectp->name, &names->abbrev_dwo)) + { + /* There can be only one. */ + if (sections->abbrev.asection != NULL) + return 0; + sections->abbrev.asection = sectp; + sections->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->info_dwo) + || section_is_p (sectp->name, &names->types_dwo)) + { + /* There can be only one. */ + if (sections->info_or_types.asection != NULL) + return 0; + sections->info_or_types.asection = sectp; + sections->info_or_types.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->line_dwo)) + { + /* There can be only one. */ + if (sections->line.asection != NULL) + return 0; + sections->line.asection = sectp; + sections->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->loc_dwo)) + { + /* There can be only one. */ + if (sections->loc.asection != NULL) + return 0; + sections->loc.asection = sectp; + sections->loc.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macinfo_dwo)) + { + /* There can be only one. */ + if (sections->macinfo.asection != NULL) + return 0; + sections->macinfo.asection = sectp; + sections->macinfo.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macro_dwo)) + { + /* There can be only one. */ + if (sections->macro.asection != NULL) + return 0; + sections->macro.asection = sectp; + sections->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_offsets_dwo)) + { + /* There can be only one. */ + if (sections->str_offsets.asection != NULL) + return 0; + sections->str_offsets.asection = sectp; + sections->str_offsets.size = bfd_get_section_size (sectp); + } + else + { + /* No other kind of section is valid. */ + return 0; + } + + return 1; +} + +/* Create a dwo_unit object for the DWO with signature SIGNATURE. + HTAB is the hash table from the DWP file. + SECTION_INDEX is the index of the DWO in HTAB. */ + +static struct dwo_unit * +create_dwo_in_dwp (struct dwp_file *dwp_file, + const struct dwp_hash_table *htab, + uint32_t section_index, + ULONGEST signature, int is_debug_types) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *dbfd = dwp_file->dbfd; + const char *kind = is_debug_types ? "TU" : "CU"; + struct dwo_file *dwo_file; + struct dwo_unit *dwo_unit; + struct virtual_dwo_sections sections; + void **dwo_file_slot; + char *virtual_dwo_name; + struct dwarf2_section_info *cutu; + struct cleanup *cleanups; + int i; + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Reading %s %u/0x%s in DWP file: %s\n", + kind, + section_index, phex (signature, sizeof (signature)), + dwp_file->name); + } + + /* Fetch the sections of this DWO. + Put a limit on the number of sections we look for so that bad data + doesn't cause us to loop forever. */ + +#define MAX_NR_DWO_SECTIONS \ + (1 /* .debug_info or .debug_types */ \ + + 1 /* .debug_abbrev */ \ + + 1 /* .debug_line */ \ + + 1 /* .debug_loc */ \ + + 1 /* .debug_str_offsets */ \ + + 1 /* .debug_macro */ \ + + 1 /* .debug_macinfo */ \ + + 1 /* trailing zero */) + + memset (§ions, 0, sizeof (sections)); + cleanups = make_cleanup (null_cleanup, 0); + + for (i = 0; i < MAX_NR_DWO_SECTIONS; ++i) + { + asection *sectp; + uint32_t section_nr = + read_4_bytes (dbfd, + htab->section_pool + + (section_index + i) * sizeof (uint32_t)); + + if (section_nr == 0) + break; + if (section_nr >= dwp_file->num_sections) + { + error (_("Dwarf Error: bad DWP hash table, section number too large" + " [in module %s]"), + dwp_file->name); + } + + sectp = dwp_file->elf_sections[section_nr]; + if (! locate_virtual_dwo_sections (sectp, §ions)) + { + error (_("Dwarf Error: bad DWP hash table, invalid section found" + " [in module %s]"), + dwp_file->name); + } + } + + if (i < 2 + || sections.info_or_types.asection == NULL + || sections.abbrev.asection == NULL) + { + error (_("Dwarf Error: bad DWP hash table, missing DWO sections" + " [in module %s]"), + dwp_file->name); + } + if (i == MAX_NR_DWO_SECTIONS) + { + error (_("Dwarf Error: bad DWP hash table, too many DWO sections" + " [in module %s]"), + dwp_file->name); + } + + /* It's easier for the rest of the code if we fake a struct dwo_file and + have dwo_unit "live" in that. At least for now. + + The DWP file can be made up of a random collection of CUs and TUs. + However, for each CU + set of TUs that came from the same original + DWO file, we want combine them back into a virtual DWO file to save space + (fewer struct dwo_file objects to allocated). Remember that for really + large apps there can be on the order of 8K CUs and 200K TUs, or more. */ + + xasprintf (&virtual_dwo_name, "virtual-dwo/%d-%d-%d-%d", + sections.abbrev.asection ? sections.abbrev.asection->id : 0, + sections.line.asection ? sections.line.asection->id : 0, + sections.loc.asection ? sections.loc.asection->id : 0, + (sections.str_offsets.asection + ? sections.str_offsets.asection->id + : 0)); + make_cleanup (xfree, virtual_dwo_name); + /* Can we use an existing virtual DWO file? */ + dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name); + /* Create one if necessary. */ + if (*dwo_file_slot == NULL) + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n", + virtual_dwo_name); + } + dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file); + dwo_file->name = obstack_copy0 (&objfile->objfile_obstack, + virtual_dwo_name, + strlen (virtual_dwo_name)); + dwo_file->sections.abbrev = sections.abbrev; + dwo_file->sections.line = sections.line; + dwo_file->sections.loc = sections.loc; + dwo_file->sections.macinfo = sections.macinfo; + dwo_file->sections.macro = sections.macro; + dwo_file->sections.str_offsets = sections.str_offsets; + /* The "str" section is global to the entire DWP file. */ + dwo_file->sections.str = dwp_file->sections.str; + /* The info or types section is assigned later to dwo_unit, + there's no need to record it in dwo_file. + Also, we can't simply record type sections in dwo_file because + we record a pointer into the vector in dwo_unit. As we collect more + types we'll grow the vector and eventually have to reallocate space + for it, invalidating all the pointers into the current copy. */ + *dwo_file_slot = dwo_file; + } + else + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n", + virtual_dwo_name); + } + dwo_file = *dwo_file_slot; + } + do_cleanups (cleanups); + + dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit); + dwo_unit->dwo_file = dwo_file; + dwo_unit->signature = signature; + dwo_unit->info_or_types_section = + obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_section_info)); + *dwo_unit->info_or_types_section = sections.info_or_types; + /* offset, length, type_offset_in_tu are set later. */ + + return dwo_unit; +} + +/* Lookup the DWO with SIGNATURE in DWP_FILE. */ + +static struct dwo_unit * +lookup_dwo_in_dwp (struct dwp_file *dwp_file, + const struct dwp_hash_table *htab, + ULONGEST signature, int is_debug_types) +{ + bfd *dbfd = dwp_file->dbfd; + uint32_t mask = htab->nr_slots - 1; + uint32_t hash = signature & mask; + uint32_t hash2 = ((signature >> 32) & mask) | 1; + unsigned int i; + void **slot; + struct dwo_unit find_dwo_cu, *dwo_cu; + + memset (&find_dwo_cu, 0, sizeof (find_dwo_cu)); + find_dwo_cu.signature = signature; + slot = htab_find_slot (dwp_file->loaded_cutus, &find_dwo_cu, INSERT); + + if (*slot != NULL) + return *slot; + + /* Use a for loop so that we don't loop forever on bad debug info. */ + for (i = 0; i < htab->nr_slots; ++i) + { + ULONGEST signature_in_table; + + signature_in_table = + read_8_bytes (dbfd, htab->hash_table + hash * sizeof (uint64_t)); + if (signature_in_table == signature) + { + uint32_t section_index = + read_4_bytes (dbfd, htab->unit_table + hash * sizeof (uint32_t)); + + *slot = create_dwo_in_dwp (dwp_file, htab, section_index, + signature, is_debug_types); + return *slot; + } + if (signature_in_table == 0) + return NULL; + hash = (hash + hash2) & mask; + } + + error (_("Dwarf Error: bad DWP hash table, lookup didn't terminate" + " [in module %s]"), + dwp_file->name); +} + +/* Subroutine of open_dwop_file to simplify it. Open the file specified by FILE_NAME and hand it off to BFD for preliminary analysis. Return a newly initialized bfd *, which includes a canonicalized copy of FILE_NAME. + If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file. In case of trouble, return NULL. NOTE: This function is derived from symfile_bfd_open. */ static bfd * -try_open_dwo_file (const char *file_name) +try_open_dwop_file (const char *file_name, int is_dwp) { bfd *sym_bfd; - int desc; + int desc, flags; char *absolute_name; - desc = openp (debug_file_directory, OPF_TRY_CWD_FIRST, file_name, + flags = OPF_TRY_CWD_FIRST; + if (is_dwp) + flags |= OPF_SEARCH_IN_PATH; + desc = openp (debug_file_directory, flags, file_name, O_RDONLY | O_BINARY, &absolute_name); if (desc < 0) return NULL; @@ -8298,30 +8759,31 @@ try_open_dwo_file (const char *file_name) return sym_bfd; } -/* Try to open DWO file DWO_NAME. +/* Try to open DWO/DWP file FILE_NAME. COMP_DIR is the DW_AT_comp_dir attribute. + If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file. The result is the bfd handle of the file. If there is a problem finding or opening the file, return NULL. Upon success, the canonicalized path of the file is stored in the bfd, same as symfile_bfd_open. */ static bfd * -open_dwo_file (const char *dwo_name, const char *comp_dir) +open_dwop_file (const char *file_name, const char *comp_dir, int is_dwp) { bfd *abfd; - if (IS_ABSOLUTE_PATH (dwo_name)) - return try_open_dwo_file (dwo_name); + if (IS_ABSOLUTE_PATH (file_name)) + return try_open_dwop_file (file_name, is_dwp); /* Before trying the search path, try DWO_NAME in COMP_DIR. */ if (comp_dir != NULL) { - char *path_to_try = concat (comp_dir, SLASH_STRING, dwo_name, NULL); + char *path_to_try = concat (comp_dir, SLASH_STRING, file_name, NULL); /* NOTE: If comp_dir is a relative path, this will also try the search path, which seems useful. */ - abfd = try_open_dwo_file (path_to_try); + abfd = try_open_dwop_file (path_to_try, is_dwp); xfree (path_to_try); if (abfd != NULL) return abfd; @@ -8333,148 +8795,373 @@ open_dwo_file (const char *dwo_name, const char *comp_dir) if (*debug_file_directory == '\0') return NULL; - return try_open_dwo_file (dwo_name); + return try_open_dwop_file (file_name, is_dwp); +} + +/* This function is mapped across the sections and remembers the offset and + size of each of the DWO debugging sections we are interested in. */ + +static void +dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_sections_ptr) +{ + struct dwo_sections *dwo_sections = dwo_sections_ptr; + const struct dwop_section_names *names = &dwop_section_names; + + if (section_is_p (sectp->name, &names->abbrev_dwo)) + { + dwo_sections->abbrev.asection = sectp; + dwo_sections->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->info_dwo)) + { + dwo_sections->info.asection = sectp; + dwo_sections->info.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->line_dwo)) + { + dwo_sections->line.asection = sectp; + dwo_sections->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->loc_dwo)) + { + dwo_sections->loc.asection = sectp; + dwo_sections->loc.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macinfo_dwo)) + { + dwo_sections->macinfo.asection = sectp; + dwo_sections->macinfo.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macro_dwo)) + { + dwo_sections->macro.asection = sectp; + dwo_sections->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_dwo)) + { + dwo_sections->str.asection = sectp; + dwo_sections->str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_offsets_dwo)) + { + dwo_sections->str_offsets.asection = sectp; + dwo_sections->str_offsets.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->types_dwo)) + { + struct dwarf2_section_info type_section; + + memset (&type_section, 0, sizeof (type_section)); + type_section.asection = sectp; + type_section.size = bfd_get_section_size (sectp); + VEC_safe_push (dwarf2_section_info_def, dwo_sections->types, + &type_section); + } } -/* Initialize the use of the DWO file specified by DWO_NAME. */ +/* Initialize the use of the DWO file specified by DWO_NAME. + The result is NULL if DWO_NAME can't be found. */ static struct dwo_file * -init_dwo_file (const char *dwo_name, const char *comp_dir) +open_and_init_dwo_file (const char *dwo_name, const char *comp_dir) { struct objfile *objfile = dwarf2_per_objfile->objfile; - struct dwo_file *dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, - struct dwo_file); - bfd *abfd; + struct dwo_file *dwo_file; + bfd *dbfd; struct cleanup *cleanups; - if (dwarf2_read_debug) - fprintf_unfiltered (gdb_stdlog, "Reading DWO file %s:\n", dwo_name); - - abfd = open_dwo_file (dwo_name, comp_dir); - if (abfd == NULL) - return NULL; - dwo_file->dwo_name = dwo_name; - dwo_file->dwo_bfd = abfd; + dbfd = open_dwop_file (dwo_name, comp_dir, 0); + if (dbfd == NULL) + { + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWO file not found: %s\n", dwo_name); + return NULL; + } + dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file); + dwo_file->name = obstack_copy0 (&objfile->objfile_obstack, + dwo_name, strlen (dwo_name)); + dwo_file->dbfd = dbfd; cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file); - bfd_map_over_sections (abfd, dwarf2_locate_dwo_sections, dwo_file); + bfd_map_over_sections (dbfd, dwarf2_locate_dwo_sections, &dwo_file->sections); - dwo_file->cus = create_debug_info_hash_table (dwo_file); + dwo_file->cus = create_dwo_debug_info_hash_table (dwo_file); dwo_file->tus = create_debug_types_hash_table (dwo_file, dwo_file->sections.types); discard_cleanups (cleanups); + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWO file found: %s\n", dwo_name); + return dwo_file; } -/* Lookup DWO file DWO_NAME. */ +/* This function is mapped across the sections and remembers the offset and + size of each of the DWP debugging sections we are interested in. */ -static struct dwo_file * -lookup_dwo_file (const char *dwo_name, const char *comp_dir) +static void +dwarf2_locate_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr) { - struct dwo_file *dwo_file; - struct dwo_file find_entry; - void **slot; + struct dwp_file *dwp_file = dwp_file_ptr; + const struct dwop_section_names *names = &dwop_section_names; + unsigned int elf_section_nr = elf_section_data (sectp)->this_idx; - if (dwarf2_per_objfile->dwo_files == NULL) - dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table (); + /* Record the ELF section number for later lookup: this is what the + .debug_cu_index,.debug_tu_index tables use. */ + gdb_assert (elf_section_nr < dwp_file->num_sections); + dwp_file->elf_sections[elf_section_nr] = sectp; - /* Have we already seen this DWO file? */ - find_entry.dwo_name = dwo_name; - slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT); + /* Look for specific sections that we need. */ + if (section_is_p (sectp->name, &names->str_dwo)) + { + dwp_file->sections.str.asection = sectp; + dwp_file->sections.str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->cu_index)) + { + dwp_file->sections.cu_index.asection = sectp; + dwp_file->sections.cu_index.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->tu_index)) + { + dwp_file->sections.tu_index.asection = sectp; + dwp_file->sections.tu_index.size = bfd_get_section_size (sectp); + } +} - /* If not, read it in and build a table of the DWOs it contains. */ - if (*slot == NULL) - *slot = init_dwo_file (dwo_name, comp_dir); +/* Hash function for dwp_file loaded CUs/TUs. */ - /* NOTE: This will be NULL if unable to open the file. */ - dwo_file = *slot; +static hashval_t +hash_dwp_loaded_cutus (const void *item) +{ + const struct dwo_unit *dwo_unit = item; - return dwo_file; + /* This drops the top 32 bits of the signature, but is ok for a hash. */ + return dwo_unit->signature; } -/* Lookup the DWO CU referenced from THIS_CU in DWO file DWO_NAME. - If non-NULL, comp_dir is the DW_AT_comp_dir attribute. - SIGNATURE is the "dwo_id" of the CU (for consistency we use the same - nomenclature as TUs). - The result is a pointer to the dwo_unit object or NULL if we didn't find it - (dwo_id mismatch or couldn't find the DWO file). */ +/* Equality function for dwp_file loaded CUs/TUs. */ -static struct dwo_unit * -lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu, - const char *dwo_name, const char *comp_dir, - ULONGEST signature) +static int +eq_dwp_loaded_cutus (const void *a, const void *b) { - struct objfile *objfile = dwarf2_per_objfile->objfile; - struct dwo_file *dwo_file; + const struct dwo_unit *dua = a; + const struct dwo_unit *dub = b; - dwo_file = lookup_dwo_file (dwo_name, comp_dir); - if (dwo_file == NULL) - return NULL; + return dua->signature == dub->signature; +} - /* Look up the DWO using its signature(dwo_id). */ +/* Allocate a hash table for dwp_file loaded CUs/TUs. */ - if (dwo_file->cus != NULL) - { - struct dwo_unit find_dwo_cu, *dwo_cu; +static htab_t +allocate_dwp_loaded_cutus_table (struct objfile *objfile) +{ + return htab_create_alloc_ex (3, + hash_dwp_loaded_cutus, + eq_dwp_loaded_cutus, + NULL, + &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); +} - find_dwo_cu.signature = signature; - dwo_cu = htab_find (dwo_file->cus, &find_dwo_cu); +/* Initialize the use of the DWP file for the current objfile. + By convention the name of the DWP file is ${objfile}.dwp. + The result is NULL if it can't be found. */ - if (dwo_cu != NULL) - return dwo_cu; +static struct dwp_file * +open_and_init_dwp_file (const char *comp_dir) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwp_file *dwp_file; + char *dwp_name; + bfd *dbfd; + struct cleanup *cleanups; + + xasprintf (&dwp_name, "%s.dwp", dwarf2_per_objfile->objfile->name); + cleanups = make_cleanup (xfree, dwp_name); + + dbfd = open_dwop_file (dwp_name, comp_dir, 1); + if (dbfd == NULL) + { + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name); + do_cleanups (cleanups); + return NULL; } + dwp_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_file); + dwp_file->name = obstack_copy0 (&objfile->objfile_obstack, + dwp_name, strlen (dwp_name)); + dwp_file->dbfd = dbfd; + do_cleanups (cleanups); - /* We didn't find it. This must mean a dwo_id mismatch. */ + cleanups = make_cleanup (free_dwo_file_cleanup, dwp_file); - complaint (&symfile_complaints, - _("Could not find DWO CU referenced by CU at offset 0x%x" - " [in module %s]"), - this_cu->offset.sect_off, objfile->name); - return NULL; + /* +1: section 0 is unused */ + dwp_file->num_sections = bfd_count_sections (dbfd) + 1; + dwp_file->elf_sections = + OBSTACK_CALLOC (&objfile->objfile_obstack, + dwp_file->num_sections, asection *); + + bfd_map_over_sections (dbfd, dwarf2_locate_dwp_sections, dwp_file); + + dwp_file->cus = create_dwp_hash_table (dwp_file, 0); + + dwp_file->tus = create_dwp_hash_table (dwp_file, 1); + + dwp_file->loaded_cutus = allocate_dwp_loaded_cutus_table (objfile); + + discard_cleanups (cleanups); + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "DWP file found: %s\n", dwp_file->name); + fprintf_unfiltered (gdb_stdlog, + " %u CUs, %u TUs\n", + dwp_file->cus ? dwp_file->cus->nr_units : 0, + dwp_file->tus ? dwp_file->tus->nr_units : 0); + } + + return dwp_file; } -/* Lookup the DWO TU referenced from THIS_TU in DWO file DWO_NAME. +/* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit. + Look up the CU/TU with signature SIGNATURE, either in DWO file DWO_NAME + or in the DWP file for the objfile, referenced by THIS_UNIT. If non-NULL, comp_dir is the DW_AT_comp_dir attribute. + IS_DEBUG_TYPES is non-zero if reading a TU, otherwise read a CU. + + This is called, for example, when wanting to read a variable with a + complex location. Therefore we don't want to do file i/o for every call. + Therefore we don't want to look for a DWO file on every call. + Therefore we first see if we've already seen SIGNATURE in a DWP file, + then we check if we've already seen DWO_NAME, and only THEN do we check + for a DWO file. + The result is a pointer to the dwo_unit object or NULL if we didn't find it - (dwo_id mismatch or couldn't find the DWO file). */ + (dwo_id mismatch or couldn't find the DWO/DWP file). */ static struct dwo_unit * -lookup_dwo_type_unit (struct signatured_type *this_tu, - const char *dwo_name, const char *comp_dir) +lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit, + const char *dwo_name, const char *comp_dir, + ULONGEST signature, int is_debug_types) { struct objfile *objfile = dwarf2_per_objfile->objfile; + const char *kind = is_debug_types ? "TU" : "CU"; + void **dwo_file_slot; struct dwo_file *dwo_file; + struct dwp_file *dwp_file; - dwo_file = lookup_dwo_file (dwo_name, comp_dir); - if (dwo_file == NULL) - return NULL; + /* Have we already read SIGNATURE from a DWP file? */ - /* Look up the DWO using its signature(dwo_id). */ + if (! dwarf2_per_objfile->dwp_checked) + { + dwarf2_per_objfile->dwp_file = open_and_init_dwp_file (comp_dir); + dwarf2_per_objfile->dwp_checked = 1; + } + dwp_file = dwarf2_per_objfile->dwp_file; - if (dwo_file->tus != NULL) + if (dwp_file != NULL) { - struct dwo_unit find_dwo_tu, *dwo_tu; + const struct dwp_hash_table *dwp_htab = + is_debug_types ? dwp_file->tus : dwp_file->cus; + + if (dwp_htab != NULL) + { + struct dwo_unit *dwo_cutu = + lookup_dwo_in_dwp (dwp_file, dwp_htab, signature, is_debug_types); + + if (dwo_cutu != NULL) + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Virtual DWO %s %s found: @%s\n", + kind, hex_string (signature), + host_address_to_string (dwo_cutu)); + } + return dwo_cutu; + } + } + } - find_dwo_tu.signature = this_tu->signature; - dwo_tu = htab_find (dwo_file->tus, &find_dwo_tu); + /* Have we already seen DWO_NAME? */ - if (dwo_tu != NULL) - return dwo_tu; + dwo_file_slot = lookup_dwo_file_slot (dwo_name); + if (*dwo_file_slot == NULL) + { + /* Read in the file and build a table of the DWOs it contains. */ + *dwo_file_slot = open_and_init_dwo_file (dwo_name, comp_dir); } + /* NOTE: This will be NULL if unable to open the file. */ + dwo_file = *dwo_file_slot; - /* We didn't find it. This must mean a dwo_id mismatch. */ + if (dwo_file != NULL) + { + htab_t htab = is_debug_types ? dwo_file->tus : dwo_file->cus; + + if (htab != NULL) + { + struct dwo_unit find_dwo_cutu, *dwo_cutu; + + memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu)); + find_dwo_cutu.signature = signature; + dwo_cutu = htab_find (htab, &find_dwo_cutu); + + if (dwo_cutu != NULL) + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) found: @%s\n", + kind, dwo_name, hex_string (signature), + host_address_to_string (dwo_cutu)); + } + return dwo_cutu; + } + } + } + + /* We didn't find it. This could mean a dwo_id mismatch, or + someone deleted the DWO/DWP file, or the search path isn't set up + correctly to find the file. */ + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) not found\n", + kind, dwo_name, hex_string (signature)); + } complaint (&symfile_complaints, - _("Could not find DWO TU referenced by TU at offset 0x%x" + _("Could not find DWO CU referenced by CU at offset 0x%x" " [in module %s]"), - this_tu->per_cu.offset.sect_off, objfile->name); + this_unit->offset.sect_off, objfile->name); return NULL; } +/* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU. + See lookup_dwo_cutu_unit for details. */ + +static struct dwo_unit * +lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu, + const char *dwo_name, const char *comp_dir, + ULONGEST signature) +{ + return lookup_dwo_cutu (this_cu, dwo_name, comp_dir, signature, 0); +} + +/* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU. + See lookup_dwo_cutu_unit for details. */ + +static struct dwo_unit * +lookup_dwo_type_unit (struct signatured_type *this_tu, + const char *dwo_name, const char *comp_dir) +{ + return lookup_dwo_cutu (&this_tu->per_cu, dwo_name, comp_dir, this_tu->signature, 1); +} + /* Free all resources associated with DWO_FILE. Close the DWO file and munmap the sections. All memory should be on the objfile obstack. */ @@ -8485,8 +9172,8 @@ free_dwo_file (struct dwo_file *dwo_file, struct objfile *objfile) int ix; struct dwarf2_section_info *section; - gdb_assert (dwo_file->dwo_bfd != objfile->obfd); - gdb_bfd_unref (dwo_file->dwo_bfd); + gdb_assert (dwo_file->dbfd != objfile->obfd); + gdb_bfd_unref (dwo_file->dbfd); VEC_free (dwarf2_section_info_def, dwo_file->sections.types); } -- 2.7.4