class Dwp_output_file;
-// An input file.
-// This class may represent either a .dwo file or a .dwp file
-// produced by an earlier run.
-
template <int size, bool big_endian>
class Sized_relobj_dwo;
+// List of .dwo files to process.
+typedef std::vector<std::string> File_list;
+
+// An input file.
+// This class may represent a .dwo file, a .dwp file
+// produced by an earlier run, or an executable file whose
+// debug section identifies a set of .dwo files to read.
+
class Dwo_file
{
public:
~Dwo_file();
+ // Read the input executable file and extract the list of .dwo files
+ // that it references.
+ void
+ read_executable(File_list* files);
+
// Read the input file and send its contents to OUTPUT_FILE.
void
read(Dwp_output_file* output_file);
// and record the target info. P is a pointer to the ELF header
// in memory.
Relobj*
- make_object(int size, bool big_endian, const unsigned char* p,
- Input_file* input_file, Dwp_output_file* output_file);
+ make_object(Dwp_output_file* output_file);
template <int size, bool big_endian>
Relobj*
unsigned int last_tu_slot_;
};
+// A specialization of Dwarf_info_reader, for reading dwo_names from
+// DWARF CUs.
+
+class Dwo_name_info_reader : public Dwarf_info_reader
+{
+ public:
+ Dwo_name_info_reader(Relobj* object, unsigned int shndx)
+ : Dwarf_info_reader(false, object, NULL, 0, shndx, 0, 0),
+ files_(NULL)
+ { }
+
+ ~Dwo_name_info_reader()
+ { }
+
+ // Get the dwo_names from the DWARF compilation unit DIEs.
+ void
+ get_dwo_names(File_list* files)
+ {
+ this->files_ = files;
+ this->parse();
+ }
+
+ protected:
+ // Visit a compilation unit.
+ virtual void
+ visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*);
+
+ private:
+ // The list of files to populate.
+ File_list* files_;
+};
+
// A specialization of Dwarf_info_reader, for reading dwo_ids and
// type signatures from DWARF CUs and TUs.
public:
Dwo_id_info_reader(bool is_type_unit,
Relobj* object,
- const unsigned char* symbols,
- off_t symbols_size,
- unsigned int shndx,
- unsigned int reloc_shndx,
- unsigned int reloc_type)
- : Dwarf_info_reader(is_type_unit, object, symbols, symbols_size, shndx,
- reloc_shndx, reloc_type),
+ unsigned int shndx)
+ : Dwarf_info_reader(is_type_unit, object, NULL, 0, shndx, 0, 0),
dwo_id_found_(false), dwo_id_(0), type_sig_found_(false), type_sig_(0)
{ }
Dwarf_die*);
private:
- // Visit a top-level DIE.
- void
- visit_top_die(Dwarf_die* die);
-
// TRUE if we found a dwo_id.
bool dwo_id_found_;
// The dwo_id.
Dwo_file::~Dwo_file()
{
- if (this->input_file_ != NULL)
- delete this->input_file_;
if (this->obj_ != NULL)
delete this->obj_;
+ if (this->input_file_ != NULL)
+ delete this->input_file_;
+}
+
+// Read the input executable file and extract the list of .dwo files
+// that it references.
+
+void
+Dwo_file::read_executable(File_list* files)
+{
+ this->obj_ = this->make_object(NULL);
+
+ unsigned int shnum = this->shnum();
+ this->is_compressed_.resize(shnum);
+ this->shndx_map_.resize(shnum);
+
+ unsigned int debug_info = 0;
+ unsigned int debug_abbrev = 0;
+
+ // Scan the section table and collect the debug sections we need.
+ // (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, "info") == 0)
+ debug_info = i;
+ else if (strcmp(suffix, "abbrev") == 0)
+ debug_abbrev = i;
+ }
+
+ if (debug_info > 0)
+ {
+ Dwo_name_info_reader dwarf_reader(this->obj_, debug_info);
+ dwarf_reader.set_abbrev_shndx(debug_abbrev);
+ dwarf_reader.get_dwo_names(files);
+ }
}
// Read the input file and send its contents to OUTPUT_FILE.
void
Dwo_file::read(Dwp_output_file* output_file)
{
- // Open the input file.
- this->input_file_ = new Input_file(this->name_);
- Dirsearch dirpath;
- int index;
- if (!this->input_file_->open(dirpath, NULL, &index))
- gold_fatal(_("%s: can't open"), this->name_);
-
- // Check that it's an ELF file.
- off_t filesize = this->input_file_->file().filesize();
- int hdrsize = elfcpp::Elf_recognizer::max_header_size;
- if (filesize < hdrsize)
- hdrsize = filesize;
- const unsigned char* p =
- this->input_file_->file().get_view(0, 0, hdrsize, true, false);
- if (!elfcpp::Elf_recognizer::is_elf_file(p, hdrsize))
- gold_fatal(_("%s: not an ELF object file"), this->name_);
-
- // Get the size, endianness, machine, etc. info from the header,
- // make an appropriately-sized Relobj, and pass the target info
- // to the output object.
- int size;
- bool big_endian;
- std::string error;
- if (!elfcpp::Elf_recognizer::is_valid_header(p, hdrsize, &size,
- &big_endian, &error))
- gold_fatal(_("%s: %s"), this->name_, error.c_str());
-
- this->obj_ = this->make_object(size, big_endian, p, this->input_file_,
- output_file);
+ this->obj_ = this->make_object(output_file);
unsigned int shnum = this->shnum();
this->is_compressed_.resize(shnum);
{
// Extract the dwo_id from .debug_info.dwo section.
uint64_t dwo_id;
- Dwo_id_info_reader dwarf_reader(false, this->obj_, NULL, 0, debug_info,
- 0, 0);
+ Dwo_id_info_reader dwarf_reader(false, this->obj_, debug_info);
dwarf_reader.set_abbrev_shndx(debug_abbrev);
if (!dwarf_reader.get_dwo_id(&dwo_id))
gold_fatal(_("%s: .debug_info.dwo section does not have DW_AT_GNU_dwo_id "
// Extract the type signature from .debug_types.dwo section.
uint64_t type_sig;
gold_assert(*tp > 0);
- Dwo_id_info_reader dwarf_reader(true, this->obj_, NULL, 0, *tp, 0, 0);
+ Dwo_id_info_reader dwarf_reader(true, this->obj_, *tp);
dwarf_reader.set_abbrev_shndx(debug_abbrev);
if (!dwarf_reader.get_type_sig(&type_sig))
gold_fatal(_("%s: .debug_types.dwo section does not have type signature"),
}
// Create a Sized_relobj_dwo of the given size and endianness,
-// and record the target info. P is a pointer to the ELF header
-// in memory.
+// and record the target info.
Relobj*
-Dwo_file::make_object(int size, bool big_endian, const unsigned char* p,
- Input_file* input_file, Dwp_output_file* output_file)
+Dwo_file::make_object(Dwp_output_file* output_file)
{
+ // Open the input file.
+ Input_file* input_file = new Input_file(this->name_);
+ this->input_file_ = input_file;
+ Dirsearch dirpath;
+ int index;
+ if (!input_file->open(dirpath, NULL, &index))
+ gold_fatal(_("%s: can't open"), this->name_);
+
+ // Check that it's an ELF file.
+ off_t filesize = input_file->file().filesize();
+ int hdrsize = elfcpp::Elf_recognizer::max_header_size;
+ if (filesize < hdrsize)
+ hdrsize = filesize;
+ const unsigned char* elf_header =
+ input_file->file().get_view(0, 0, hdrsize, true, false);
+ if (!elfcpp::Elf_recognizer::is_elf_file(elf_header, hdrsize))
+ gold_fatal(_("%s: not an ELF object file"), this->name_);
+
+ // Get the size, endianness, machine, etc. info from the header,
+ // make an appropriately-sized Relobj, and pass the target info
+ // to the output object.
+ int size;
+ bool big_endian;
+ std::string error;
+ if (!elfcpp::Elf_recognizer::is_valid_header(elf_header, hdrsize, &size,
+ &big_endian, &error))
+ gold_fatal(_("%s: %s"), this->name_, error.c_str());
+
if (size == 32)
{
if (big_endian)
#ifdef HAVE_TARGET_32_BIG
- return this->sized_make_object<32, true>(p, input_file, output_file);
+ return this->sized_make_object<32, true>(elf_header, input_file,
+ output_file);
#else
gold_unreachable();
#endif
else
#ifdef HAVE_TARGET_32_LITTLE
- return this->sized_make_object<32, false>(p, input_file, output_file);
+ return this->sized_make_object<32, false>(elf_header, input_file,
+ output_file);
#else
gold_unreachable();
#endif
{
if (big_endian)
#ifdef HAVE_TARGET_64_BIG
- return this->sized_make_object<64, true>(p, input_file, output_file);
+ return this->sized_make_object<64, true>(elf_header, input_file,
+ output_file);
#else
gold_unreachable();
#endif
else
#ifdef HAVE_TARGET_64_LITTLE
- return this->sized_make_object<64, false>(p, input_file, output_file);
+ return this->sized_make_object<64, false>(elf_header, input_file,
+ output_file);
#else
gold_unreachable();
#endif
Sized_relobj_dwo<size, big_endian>* obj =
new Sized_relobj_dwo<size, big_endian>(this->name_, input_file, ehdr);
obj->setup();
- output_file->record_target_info(
- this->name_, ehdr.get_e_machine(), size, big_endian,
- ehdr.get_e_ident()[elfcpp::EI_OSABI],
- ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+ if (output_file != NULL)
+ output_file->record_target_info(
+ this->name_, ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
return obj;
}
gold_fatal(_("%s: error writing section header table"), this->name_);
}
+// Class Dwo_name_info_reader.
+
+// Visit a compilation unit.
+
+void
+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);
+}
+
// Class Dwo_id_info_reader.
// Visit a compilation unit.
// Visit a type unit.
void
-Dwo_id_info_reader::visit_type_unit(off_t, off_t, uint64_t signature, Dwarf_die*)
+Dwo_id_info_reader::visit_type_unit(off_t, off_t, uint64_t signature,
+ Dwarf_die*)
{
this->type_sig_ = signature;
this->type_sig_found_ = true;
struct option dwp_options[] =
{
+ { "exec", required_argument, NULL, 'e' },
{ "help", no_argument, NULL, 'h' },
{ "output", required_argument, NULL, 'o' },
{ "verbose", no_argument, NULL, 'v' },
static void
usage(FILE* fd, int exit_status)
{
- fprintf(fd, _("Usage: %s [options] file...\n"), program_name);
+ fprintf(fd, _("Usage: %s [options] [file...]\n"), program_name);
fprintf(fd, _(" -h, --help Print this help message\n"));
- fprintf(fd, _(" -o FILE, --output FILE Set output dwp file name"
- " (required)\n"));
+ fprintf(fd, _(" -e EXE, --exec EXE Get list of dwo files from EXE"
+ " (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, _(" -V, --version Print version number\n"));
expandargv(&argc, &argv);
// Collect file names and options.
- typedef std::vector<char*> File_list;
File_list files;
- const char* output_filename = NULL;
+ std::string output_filename;
+ const char* exe_filename = NULL;
bool verbose = false;
int c;
- while ((c = getopt_long(argc, argv, "ho:vV", dwp_options, NULL)) != -1)
+ while ((c = getopt_long(argc, argv, "e:ho:vV", dwp_options, NULL)) != -1)
{
switch (c)
{
case 'h':
usage(stdout, EXIT_SUCCESS);
+ case 'e':
+ exe_filename = optarg;
+ break;
case 'o':
- output_filename = optarg;
+ output_filename.assign(optarg);
break;
case 'v':
verbose = true;
usage(stderr, EXIT_FAILURE);
}
}
+
+ if (output_filename.empty())
+ {
+ if (exe_filename == NULL)
+ gold_fatal(_("no output file specified"));
+ output_filename.assign(exe_filename);
+ 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)
+ {
+ Dwo_file exe_file(exe_filename);
+ exe_file.read_executable(&files);
+ }
+
+ // Add any additional files listed on command line.
for (int i = optind; i < argc; ++i)
files.push_back(argv[i]);
- if (files.empty())
- gold_fatal(_("no input files"));
- if (output_filename == NULL)
- gold_fatal(_("no output file specified"));
+ if (exe_filename == NULL && files.empty())
+ gold_fatal(_("no input files and no executable specified"));
- Dwp_output_file output_file(output_filename);
-
// Process each file, adding its contents to the output file.
for (File_list::const_iterator f = files.begin(); f != files.end(); ++f)
{
if (verbose)
- fprintf(stderr, "%s\n", *f);
- Dwo_file dwo_file(*f);
+ fprintf(stderr, "%s\n", f->c_str());
+ Dwo_file dwo_file(f->c_str());
dwo_file.read(&output_file);
}