From 1e21ea76b743f29b7c17952f5f19d15b53dc5afd Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 8 May 2018 15:09:47 +1000 Subject: linkers/exe-info: Add DWARF support to gather and check producer details. - Provide support to list the compilers and assemblers used to build an executable. - List the machine flags showing which flags are common and which are not. --- linkers/rtems-exeinfo.cpp | 212 +++++++++++++++++++++++++++++++++++++++++++++- linkers/wscript | 2 +- 2 files changed, 210 insertions(+), 4 deletions(-) (limited to 'linkers') diff --git a/linkers/rtems-exeinfo.cpp b/linkers/rtems-exeinfo.cpp index b0388af..ef1b653 100644 --- a/linkers/rtems-exeinfo.cpp +++ b/linkers/rtems-exeinfo.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -131,6 +132,7 @@ namespace rld struct image { files::object exe; //< The object file that is the executable. + dwarf::file debug; //< The executable's DWARF details. symbols::table symbols; //< The synbols for a map. symbols::addrtab addresses; //< The symbols keyed by address. files::sections secs; //< The sections in the executable. @@ -148,6 +150,11 @@ namespace rld */ ~image (); + /* + * Check the compiler and flags match. + */ + void output_compilation_unit (bool objects); + /* * Output the sections. */ @@ -260,6 +267,7 @@ namespace rld */ exe.open (); exe.begin (); + debug.begin (exe.elf ()); if (!exe.valid ()) throw rld::error ("Not valid: " + exe.name ().full (), @@ -284,6 +292,7 @@ namespace rld * Load the symbols and sections. */ exe.load_symbols (symbols, true); + debug.load_debug (); symbols.globals (addresses); symbols.weaks (addresses); symbols.locals (addresses); @@ -292,7 +301,186 @@ namespace rld image::~image () { - exe.close (); + } + + void + image::output_compilation_unit (bool objects) + { + dwarf::compilation_units& cus = debug.get_cus (); + + std::cout << "Compilation: " << std::endl; + + rld::strings flag_exceptions = { "-O", + "-g", + "-mtune=", + "-fno-builtin", + "-fno-inline", + "-fexceptions", + "-fnon-call-exceptions", + "-fvisibility=", + "-fno-stack-protector", + "-fbuilding-libgcc", + "-fno-implicit-templates", + "-ffunction-sections", + "-fdata-sections", + "-frandom-seed=", + "-fno-common", + "-fno-keep-inline-functions" }; + + dwarf::producer_sources producers; + + debug.get_producer_sources (producers); + + /* + * Find which flags are common to the building of all source. We are only + * interested in files that have any flags. This filters out things like + * the assembler which does not have flags. + */ + + rld::strings all_flags; + + size_t source_max = 0; + + for (auto& p : producers) + { + dwarf::source_flags_compare compare; + std::sort (p.sources.begin (), p.sources.end (), compare); + + for (auto& s : p.sources) + { + size_t len = rld::path::basename (s.source).length (); + if (len > source_max) + source_max = len; + + if (!s.flags.empty ()) + { + for (auto& f : s.flags) + { + bool add = true; + for (auto& ef : flag_exceptions) + { + if (rld::starts_with (f, ef)) + { + add = false; + break; + } + } + if (add) + { + for (auto& af : all_flags) + { + if (f == af) + { + add = false; + break; + } + } + if (add) + all_flags.push_back (f); + } + } + } + } + } + + rld::strings common_flags; + + for (auto& flag : all_flags) + { + bool found_in_all = true; + for (auto& p : producers) + { + for (auto& s : p.sources) + { + if (!s.flags.empty ()) + { + bool flag_found = false; + for (auto& f : s.flags) + { + if (flag == f) + { + flag_found = true; + break; + } + } + if (!flag_found) + { + found_in_all = false; + break; + } + } + if (!found_in_all) + break; + } + } + if (found_in_all) + common_flags.push_back (flag); + } + + std::cout << " Producers: " << producers.size () << std::endl; + + for (auto& p : producers) + { + std::cout << " | " << p.producer + << ": " << p.sources.size () << " objects" << std::endl; + } + + std::cout << " Common flags: " << common_flags.size () << std::endl + << " |"; + + for (auto& f : common_flags) + std::cout << ' ' << f; + std::cout << std::endl; + + if (objects) + { + std::cout << " Object files: " << cus.size () << std::endl; + + rld::strings filter_flags = common_flags; + filter_flags.insert (filter_flags.end (), + flag_exceptions.begin (), + flag_exceptions.end()); + + for (auto& p : producers) + { + std::cout << ' ' << p.producer + << ": " << p.sources.size () << " objects" << std::endl; + for (auto& s : p.sources) + { + std::cout << " | " + << std::setw (source_max + 1) << std::left + << rld::path::basename (s.source); + if (!s.flags.empty ()) + { + bool first = true; + for (auto& f : s.flags) + { + bool present = false; + for (auto& ff : filter_flags) + { + if (rld::starts_with(f, ff)) + { + present = true; + break; + } + } + if (!present) + { + if (first) + { + std::cout << ':'; + first = false; + } + std::cout << ' ' << f; + } + } + } + std::cout << std::endl; + } + } + } + + std::cout << std::endl; } void @@ -442,7 +630,8 @@ usage (int exit_code) << " -a : all output excluding the map (also --all)" << std::endl << " -S : show all section (also --sections)" << std::endl << " -I : show init section tables (also --init)" << std::endl - << " -F : show fini section tables (also --fini)" << std::endl; + << " -F : show fini section tables (also --fini)" << std::endl + << " -O : show object files (also --objects)" << std::endl; ::exit (exit_code); } @@ -480,6 +669,13 @@ setup_signals (void) #endif } +void +unhandled_exception (void) +{ + std::cerr << "error: exception handling error, please report" << std::endl; + exit (1); +} + int main (int argc, char* argv[]) { @@ -487,6 +683,8 @@ main (int argc, char* argv[]) setup_signals (); + std::set_terminate(unhandled_exception); + try { std::string exe_name; @@ -495,6 +693,7 @@ main (int argc, char* argv[]) bool sections = false; bool init = false; bool fini = false; + bool objects = false; rld::set_cmdline (argc, argv); @@ -537,6 +736,10 @@ main (int argc, char* argv[]) sections = true; break; + case 'O': + objects = true; + break; + case '?': usage (3); break; @@ -566,6 +769,7 @@ main (int argc, char* argv[]) sections = true; init = true; fini = true; + objects = true; } /* @@ -589,11 +793,13 @@ main (int argc, char* argv[]) */ rld::exeinfo::image exe (exe_name); - std::cout << "exe: " << exe.exe.name ().full () << std::endl; + std::cout << "exe: " << exe.exe.name ().full () << std::endl + << std::endl; /* * Generate the output. */ + exe.output_compilation_unit (objects); if (sections) exe.output_sections (); if (init) diff --git a/linkers/wscript b/linkers/wscript index ecb0335..10fe2a0 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -70,7 +70,7 @@ def build(bld): # # The list of modules. # - modules = ['rld', 'elf', 'iberty'] + modules = ['rld', 'dwarf', 'elf', 'iberty'] # # The list of defines -- cgit v1.2.3