summaryrefslogtreecommitdiff
path: root/linkers
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2018-05-08 15:09:47 +1000
committerChris Johns <chrisj@rtems.org>2018-06-18 12:26:16 +1000
commit1e21ea76b743f29b7c17952f5f19d15b53dc5afd (patch)
treec4017861d64edec8d67c8ea8b22e470573bb184e /linkers
parentb73f905e3aa0e9ac16eb19f956ff3297d92fe48f (diff)
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.
Diffstat (limited to 'linkers')
-rw-r--r--linkers/rtems-exeinfo.cpp212
-rw-r--r--linkers/wscript2
2 files changed, 210 insertions, 4 deletions
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 <rld.h>
#include <rld-buffer.h>
+#include <rld-dwarf.h>
#include <rld-files.h>
#include <rld-process.h>
#include <rld-rtems.h>
@@ -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.
@@ -149,6 +151,11 @@ namespace rld
~image ();
/*
+ * Check the compiler and flags match.
+ */
+ void output_compilation_unit (bool objects);
+
+ /*
* Output the sections.
*/
void output_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