From 1318c11e5df8ccc86383e4ce255e68f3279a94d8 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 24 May 2018 18:05:44 +1200 Subject: linkers: Add an address to line tool. This tool provides a way to check the DWARF toolkit support for finding lines from addresses. --- linkers/rtems-addr2line.cpp | 289 ++++++++++++++++++++++++++++++++++++++++++++ linkers/wscript | 15 ++- 2 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 linkers/rtems-addr2line.cpp (limited to 'linkers') diff --git a/linkers/rtems-addr2line.cpp b/linkers/rtems-addr2line.cpp new file mode 100644 index 0000000..2e79c62 --- /dev/null +++ b/linkers/rtems-addr2line.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2018, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS Address to Line is a version of the classic addr2line + * utility to test the DWARF info support in the RTEMS Toolkit. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Symbols options. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "executable", required_argument, NULL, 'e' }, + { "addresses", no_argument, NULL, 'a' }, + { "pretty-print", no_argument, NULL, 'p' }, + { "basenames", no_argument, NULL, 's' }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int exit_code) +{ + std::cout << "rtems-addr2line [options] addresses" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -e : executable (also --executablewarn)" << std::endl + << " -a : show addresses (also --addresses)" << std::endl + << " -p : human readable format (also --pretty-print)" << std::endl + << " -s : Strip directory paths (also --basenames)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +void +unhandled_exception (void) +{ + std::cerr << "error: exception handling error, please report" << std::endl; + exit (13); +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + std::set_terminate(unhandled_exception); + + try + { + std::string exe_name = "a.out"; + bool show_addresses = false; + bool pretty_print = false; + bool show_basenames = false; + + rld::set_cmdline (argc, argv); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvVe:aps", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-addr2line (RTEMS Address To Line) " << rld::version () + << ", RTEMS revision " << rld::rtems::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'e': + exe_name = optarg; + break; + + case 'a': + show_addresses = true; + break; + + case 'p': + pretty_print = true; + break; + + case 's': + show_basenames = true; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + /* + * Set the program name. + */ + rld::set_progname (argv[0]); + + argc -= optind; + argv += optind; + + if (rld::verbose ()) + std::cout << "RTEMS Address To Line " << rld::version () << std::endl; + + /* + * If there are no object files there is nothing to link. + */ + if (argc == 0) + throw rld::error ("no addresses provided", "options"); + + if (rld::verbose ()) + std::cout << "exe: " << exe_name << std::endl; + + /* + * Load the executable's debug info. + */ + rld::files::object exe (exe_name); + rld::dwarf::file debug; + + try + { + /* + * Load the executable's ELF file debug info. + */ + exe.open (); + exe.begin (); + debug.begin (exe.elf ()); + debug.load_debug (); + + for (int arg = 0; arg < argc; ++arg) + { + rld::dwarf::dwarf_address location; + + if (rld::verbose ()) + std::cout << "address: " << argv[arg] << std::endl; + + /* + * Use the C routine as C++ does not have a way to automatically handle + * different bases on the input. + */ + location = ::strtoul (argv[arg], 0, 0); + + std::string path; + int line; + + debug.get_source (location, path, line); + + if (show_addresses) + { + std::cout << std::hex << std::setfill ('0') + << "0x" << location + << std::dec << std::setfill (' '); + + if (pretty_print) + std::cout << ": "; + else + std::cout << std::endl; + } + + if (show_basenames) + std::cout << rld::path::basename (path); + else + std::cout << path; + + std::cout << ':' << line << std::endl; + } + + debug.end (); + exe.end (); + exe.close (); + } + catch (...) + { + debug.end (); + exe.end (); + exe.close (); + throw; + } + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + rld::output_std_exception (e, std::cerr); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/wscript b/linkers/wscript index 10fe2a0..23d3f9c 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -58,6 +58,7 @@ def build(bld): rtemstoolkit + '/elftoolchain/libelf', rtemstoolkit + '/elftoolchain/libdwarf', rtemstoolkit + '/elftoolchain/common', + rtemstoolkit + '/elftoolchain/libelftc', rtemstoolkit + '/libiberty'] if bld.env.DEST_OS == 'win32': conf['includes'] += [rtemstoolkit + '/win32'] @@ -70,7 +71,7 @@ def build(bld): # # The list of modules. # - modules = ['rld', 'dwarf', 'elf', 'iberty'] + modules = ['rld', 'elftc', 'dwarf', 'elf', 'iberty'] # # The list of defines @@ -165,5 +166,17 @@ def build(bld): linkflags = conf['linkflags'], use = modules) + # + # Build the address to line tool. + # + bld.program(target = 'rtems-addr2line', + source = ['rtems-addr2line.cpp'], + defines = defines, + includes = ['.'] + conf['includes'], + cflags = conf['cflags'] + conf['warningflags'], + cxxflags = conf['cxxflags'] + conf['warningflags'], + linkflags = conf['linkflags'], + use = modules) + def tags(ctx): ctx.exec_command('etags $(find . -name \*.[sSch])', shell = True) -- cgit v1.2.3