X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fdwp.cc;h=c312b7dbed52fe0d838aad4f11bcb1e53540a7da;hb=b437bfe0f4cf06559ca4c508a2869383196ddc6b;hp=c6453bfdef1962f468b5ecf1746d744d11f15012;hpb=908794a91538a6a758b60847f33411efea0cb2fe;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/dwp.cc b/gold/dwp.cc index c6453bfdef..c312b7dbed 100644 --- a/gold/dwp.cc +++ b/gold/dwp.cc @@ -1,6 +1,6 @@ // dwp.cc -- DWARF packaging utility -// Copyright 2012 Free Software Foundation, Inc. +// Copyright (C) 2012-2019 Free Software Foundation, Inc. // Written by Cary Coutant . // This file is part of dwp, the DWARF packaging utility. @@ -60,7 +60,15 @@ template class Sized_relobj_dwo; // List of .dwo files to process. -typedef std::vector File_list; +struct Dwo_file_entry +{ + Dwo_file_entry(uint64_t id, std::string name) + : dwo_id(id), dwo_name(name) + { } + uint64_t dwo_id; + std::string dwo_name; +}; +typedef std::vector File_list; // Type to hold the offset and length of an input section // within an output section. @@ -115,6 +123,12 @@ class Dwo_file void read(Dwp_output_file* output_file); + // Verify a .dwp file given a list of .dwo files referenced by the + // corresponding executable file. Returns true if no problems + // were found. + bool + verify(const File_list& files); + private: // Types for mapping input string offsets to output string offsets. typedef std::pair @@ -174,6 +188,16 @@ class Dwo_file sized_read_unit_index(unsigned int, unsigned int *, Dwp_output_file*, bool is_tu_index); + // Verify the .debug_cu_index section of a .dwp file, comparing it + // against the list of .dwo files referenced by the corresponding + // executable file. + bool + verify_dwo_list(unsigned int, const File_list& files); + + template + bool + sized_verify_dwo_list(unsigned int, const File_list& files); + // Merge the input string table section into the output file. void add_strings(Dwp_output_file*, unsigned int); @@ -248,7 +272,7 @@ class Sized_relobj_dwo : public Sized_relobj // Get the name of a section. std::string - do_section_name(unsigned int shndx) + do_section_name(unsigned int shndx) const { return this->elf_file_.section_name(shndx); } // Get the size of a section. @@ -260,14 +284,6 @@ class Sized_relobj_dwo : public Sized_relobj const unsigned char* do_section_contents(unsigned int, section_size_type*, bool); - // Return a view of the uncompressed contents of a section. Set *PLEN - // to the size. Set *IS_NEW to true if the contents need to be deleted - // by the caller. - const unsigned char* - do_decompressed_section_contents(unsigned int shndx, - section_size_type* plen, - bool* is_new); - // The following virtual functions are abstract in the base classes, // but are not used here. @@ -757,9 +773,36 @@ template void Sized_relobj_dwo::setup() { + const int shdr_size = elfcpp::Elf_sizes::shdr_size; + const off_t shoff = this->elf_file_.shoff(); const unsigned int shnum = this->elf_file_.shnum(); + this->set_shnum(shnum); this->section_offsets().resize(shnum); + + // Read the section headers. + const unsigned char* const pshdrs = this->get_view(shoff, shnum * shdr_size, + true, false); + + // Read the section names. + const unsigned char* pshdrnames = + pshdrs + this->elf_file_.shstrndx() * shdr_size; + typename elfcpp::Shdr shdrnames(pshdrnames); + if (shdrnames.get_sh_type() != elfcpp::SHT_STRTAB) + this->error(_("section name section has wrong type: %u"), + static_cast(shdrnames.get_sh_type())); + section_size_type section_names_size = + convert_to_section_size_type(shdrnames.get_sh_size()); + const unsigned char* namesu = this->get_view(shdrnames.get_sh_offset(), + section_names_size, false, + false); + const char* names = reinterpret_cast(namesu); + + Compressed_section_map* compressed_sections = + build_compressed_section_map( + pshdrs, this->shnum(), names, section_names_size, this, true); + if (compressed_sections != NULL && !compressed_sections->empty()) + this->set_compressed_sections(compressed_sections); } // Return a view of the contents of a section. @@ -781,43 +824,6 @@ Sized_relobj_dwo::do_section_contents( return this->get_view(loc.file_offset, *plen, true, cache); } -// Return a view of the uncompressed contents of a section. Set *PLEN -// to the size. Set *IS_NEW to true if the contents need to be deleted -// by the caller. - -template -const unsigned char* -Sized_relobj_dwo::do_decompressed_section_contents( - unsigned int shndx, - section_size_type* plen, - bool* is_new) -{ - section_size_type buffer_size; - const unsigned char* buffer = this->do_section_contents(shndx, &buffer_size, - false); - - std::string sect_name = this->do_section_name(shndx); - if (!is_prefix_of(".zdebug_", sect_name.c_str())) - { - *plen = buffer_size; - *is_new = false; - return buffer; - } - - section_size_type uncompressed_size = get_uncompressed_size(buffer, - buffer_size); - unsigned char* uncompressed_data = new unsigned char[uncompressed_size]; - if (!decompress_input_section(buffer, - buffer_size, - uncompressed_data, - uncompressed_size)) - this->error(_("could not decompress section %s"), - this->section_name(shndx).c_str()); - *plen = uncompressed_size; - *is_new = true; - return uncompressed_data; -} - // Class Dwo_file. Dwo_file::~Dwo_file() @@ -946,10 +952,13 @@ Dwo_file::read(Dwp_output_file* output_file) this->read_unit_index(debug_cu_index, debug_shndx, output_file, false); if (debug_tu_index > 0) { - if (debug_types.size() != 1) - gold_fatal(_("%s: .dwp file must have exactly one " + if (debug_types.size() > 1) + gold_fatal(_("%s: .dwp file must have no more than one " ".debug_types.dwo section"), this->name_); - debug_shndx[elfcpp::DW_SECT_TYPES] = debug_types[0]; + if (debug_types.size() == 1) + debug_shndx[elfcpp::DW_SECT_TYPES] = debug_types[0]; + else + debug_shndx[elfcpp::DW_SECT_TYPES] = 0; this->read_unit_index(debug_tu_index, debug_shndx, output_file, true); } return; @@ -969,6 +978,48 @@ Dwo_file::read(Dwp_output_file* output_file) } } +// Verify a .dwp file given a list of .dwo files referenced by the +// corresponding executable file. Returns true if no problems +// were found. + +bool +Dwo_file::verify(const File_list& files) +{ + this->obj_ = this->make_object(NULL); + + unsigned int shnum = this->shnum(); + this->is_compressed_.resize(shnum); + this->sect_offsets_.resize(shnum); + + unsigned int debug_cu_index = 0; + + // Scan the section table and collect debug sections. + // (Section index 0 is a dummy section; skip it.) + for (unsigned int i = 1; i < shnum; i++) + { + if (this->section_type(i) != elfcpp::SHT_PROGBITS) + continue; + std::string sect_name = this->section_name(i); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + { + this->is_compressed_[i] = true; + suffix += 8; + } + else + continue; + if (strcmp(suffix, "cu_index") == 0) + debug_cu_index = i; + } + + if (debug_cu_index == 0) + gold_fatal(_("%s: no .debug_cu_index section found"), this->name_); + + return this->verify_dwo_list(debug_cu_index, files); +} + // Create a Sized_relobj_dwo of the given size and endianness, // and record the target info. @@ -1088,7 +1139,7 @@ Dwo_file::sized_read_unit_index(unsigned int shndx, : elfcpp::DW_SECT_INFO); unsigned int info_shndx = debug_shndx[info_sect]; - gold_assert(shndx > 0 && info_shndx > 0); + gold_assert(shndx > 0); section_size_type index_len; bool index_is_new; @@ -1114,6 +1165,8 @@ Dwo_file::sized_read_unit_index(unsigned int shndx, if (ncols == 0 || nused == 0) return; + gold_assert(info_shndx > 0); + unsigned int nslots = elfcpp::Swap_unaligned<32, big_endian>::readval(contents + 3 * sizeof(uint32_t)); @@ -1211,6 +1264,102 @@ Dwo_file::sized_read_unit_index(unsigned int shndx, delete[] info_contents; } +// Verify the .debug_cu_index section of a .dwp file, comparing it +// against the list of .dwo files referenced by the corresponding +// executable file. + +bool +Dwo_file::verify_dwo_list(unsigned int shndx, const File_list& files) +{ + if (this->obj_->is_big_endian()) + return this->sized_verify_dwo_list(shndx, files); + else + return this->sized_verify_dwo_list(shndx, files); +} + +template +bool +Dwo_file::sized_verify_dwo_list(unsigned int shndx, const File_list& files) +{ + gold_assert(shndx > 0); + + section_size_type index_len; + bool index_is_new; + const unsigned char* contents = + this->section_contents(shndx, &index_len, &index_is_new); + + unsigned int version = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents); + + // We don't support version 1 anymore because it was experimental + // and because in normal use, dwp is not expected to read .dwp files + // produced by an earlier version of the tool. + if (version != 2) + gold_fatal(_("%s: section %s has unsupported version number %d"), + this->name_, this->section_name(shndx).c_str(), version); + + unsigned int ncols = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + sizeof(uint32_t)); + unsigned int nused = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 2 * sizeof(uint32_t)); + if (ncols == 0 || nused == 0) + return true; + + unsigned int nslots = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 3 * sizeof(uint32_t)); + + const unsigned char* phash = contents + 4 * sizeof(uint32_t); + const unsigned char* pindex = phash + nslots * sizeof(uint64_t); + const unsigned char* pcolhdrs = pindex + nslots * sizeof(uint32_t); + const unsigned char* poffsets = pcolhdrs + ncols * sizeof(uint32_t); + const unsigned char* psizes = poffsets + nused * ncols * sizeof(uint32_t); + const unsigned char* pend = psizes + nused * ncols * sizeof(uint32_t); + + if (pend > contents + index_len) + gold_fatal(_("%s: section %s is corrupt"), this->name_, + this->section_name(shndx).c_str()); + + int nmissing = 0; + for (File_list::const_iterator f = files.begin(); f != files.end(); ++f) + { + uint64_t dwo_id = f->dwo_id; + unsigned int slot = static_cast(dwo_id) & (nslots - 1); + const unsigned char* ph = phash + slot * sizeof(uint64_t); + const unsigned char* pi = pindex + slot * sizeof(uint32_t); + uint64_t probe = elfcpp::Swap_unaligned<64, big_endian>::readval(ph); + uint32_t row_index = elfcpp::Swap_unaligned<32, big_endian>::readval(pi); + if (row_index != 0 && probe != dwo_id) + { + unsigned int h2 = ((static_cast(dwo_id >> 32) + & (nslots - 1)) | 1); + do + { + slot = (slot + h2) & (nslots - 1); + ph = phash + slot * sizeof(uint64_t); + pi = pindex + slot * sizeof(uint32_t); + probe = elfcpp::Swap_unaligned<64, big_endian>::readval(ph); + row_index = elfcpp::Swap_unaligned<32, big_endian>::readval(pi); + } while (row_index != 0 && probe != dwo_id); + } + if (row_index == 0) + { + printf(_("missing .dwo file: %016llx %s\n"), + static_cast(dwo_id), f->dwo_name.c_str()); + ++nmissing; + } + } + + gold_info(_("Found %d missing .dwo files"), nmissing); + + if (index_is_new) + delete[] contents; + + return nmissing == 0; +} + // Merge the input string table section into the output file. void @@ -2063,7 +2212,10 @@ Dwo_name_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die* die) { const char* dwo_name = die->string_attribute(elfcpp::DW_AT_GNU_dwo_name); if (dwo_name != NULL) - this->files_->push_back(dwo_name); + { + uint64_t dwo_id = die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id); + this->files_->push_back(Dwo_file_entry(dwo_id, dwo_name)); + } } // Class Unit_reader. @@ -2138,12 +2290,17 @@ using namespace gold; // Options. +enum Dwp_options { + VERIFY_ONLY = 0x101, +}; + struct option dwp_options[] = { { "exec", required_argument, NULL, 'e' }, { "help", no_argument, NULL, 'h' }, { "output", required_argument, NULL, 'o' }, { "verbose", no_argument, NULL, 'v' }, + { "verify-only", no_argument, NULL, VERIFY_ONLY }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; @@ -2156,9 +2313,11 @@ usage(FILE* fd, int exit_status) fprintf(fd, _("Usage: %s [options] [file...]\n"), program_name); fprintf(fd, _(" -h, --help Print this help message\n")); fprintf(fd, _(" -e EXE, --exec EXE Get list of dwo files from EXE" - " (defaults output to EXE.dwp)\n")); + " (defaults output to EXE.dwp)\n")); fprintf(fd, _(" -o FILE, --output FILE Set output dwp file name\n")); fprintf(fd, _(" -v, --verbose Verbose output\n")); + fprintf(fd, _(" --verify-only Verify output file against" + " exec file\n")); fprintf(fd, _(" -V, --version Print version number\n")); // REPORT_BUGS_TO is defined in bfd/bfdver.h. @@ -2175,7 +2334,7 @@ print_version() { // This output is intended to follow the GNU standards. printf("GNU dwp %s\n", BFD_VERSION_STRING); - printf(_("Copyright 2012 Free Software Foundation, Inc.\n")); + printf(_("Copyright (C) 2019 Free Software Foundation, Inc.\n")); printf(_("\ This program is free software; you may redistribute it under the terms of\n\ the GNU General Public License version 3 or (at your option) any later version.\n\ @@ -2218,6 +2377,7 @@ main(int argc, char** argv) std::string output_filename; const char* exe_filename = NULL; bool verbose = false; + bool verify_only = false; int c; while ((c = getopt_long(argc, argv, "e:ho:vV", dwp_options, NULL)) != -1) { @@ -2234,6 +2394,9 @@ main(int argc, char** argv) case 'v': verbose = true; break; + case VERIFY_ONLY: + verify_only = true; + break; case 'V': print_version(); case '?': @@ -2250,8 +2413,6 @@ main(int argc, char** argv) output_filename.append(".dwp"); } - Dwp_output_file output_file(output_filename.c_str()); - // Get list of .dwo files from the executable. if (exe_filename != NULL) { @@ -2261,20 +2422,29 @@ main(int argc, char** argv) // Add any additional files listed on command line. for (int i = optind; i < argc; ++i) - files.push_back(argv[i]); + files.push_back(Dwo_file_entry(0, argv[i])); if (exe_filename == NULL && files.empty()) gold_fatal(_("no input files and no executable specified")); + if (verify_only) + { + // Get list of DWO files in the DWP file and compare with + // references found in the EXE file. + Dwo_file dwp_file(output_filename.c_str()); + bool ok = dwp_file.verify(files); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; + } + // Process each file, adding its contents to the output file. + Dwp_output_file output_file(output_filename.c_str()); for (File_list::const_iterator f = files.begin(); f != files.end(); ++f) { if (verbose) - fprintf(stderr, "%s\n", f->c_str()); - Dwo_file dwo_file(f->c_str()); + fprintf(stderr, "%s\n", f->dwo_name.c_str()); + Dwo_file dwo_file(f->dwo_name.c_str()); dwo_file.read(&output_file); } - output_file.finalize(); return EXIT_SUCCESS;