133965Sjdp/* addr2line.c -- convert addresses to line number and function name 2218822Sdim Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007 3130561Sobrien Free Software Foundation, Inc. 477298Sobrien Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.siemens.de> 533965Sjdp 633965Sjdp This file is part of GNU Binutils. 733965Sjdp 833965Sjdp This program is free software; you can redistribute it and/or modify 933965Sjdp it under the terms of the GNU General Public License as published by 1033965Sjdp the Free Software Foundation; either version 2, or (at your option) 1133965Sjdp any later version. 1233965Sjdp 1333965Sjdp This program is distributed in the hope that it will be useful, 1433965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1533965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1633965Sjdp GNU General Public License for more details. 1733965Sjdp 1833965Sjdp You should have received a copy of the GNU General Public License 1933965Sjdp along with this program; if not, write to the Free Software 20218822Sdim Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 2277298Sobrien/* Derived from objdump.c and nm.c by Ulrich.Lauther@mchp.siemens.de 2333965Sjdp 24104834Sobrien Usage: 2533965Sjdp addr2line [options] addr addr ... 2633965Sjdp or 27104834Sobrien addr2line [options] 2833965Sjdp 2933965Sjdp both forms write results to stdout, the second form reads addresses 3033965Sjdp to be converted from stdin. */ 3133965Sjdp 32218822Sdim#include "sysdep.h" 3333965Sjdp#include "bfd.h" 3433965Sjdp#include "getopt.h" 3533965Sjdp#include "libiberty.h" 3633965Sjdp#include "demangle.h" 3733965Sjdp#include "bucomm.h" 3833965Sjdp 39218822Sdimstatic bfd_boolean unwind_inlines; /* -i, unwind inlined functions. */ 40130561Sobrienstatic bfd_boolean with_functions; /* -f, show function names. */ 41130561Sobrienstatic bfd_boolean do_demangle; /* -C, demangle names. */ 42130561Sobrienstatic bfd_boolean base_names; /* -s, strip directory names. */ 4333965Sjdp 4433965Sjdpstatic int naddr; /* Number of addresses to process. */ 4533965Sjdpstatic char **addr; /* Hex addresses to process. */ 4633965Sjdp 4733965Sjdpstatic asymbol **syms; /* Symbol table. */ 4833965Sjdp 4933965Sjdpstatic struct option long_options[] = 5033965Sjdp{ 5133965Sjdp {"basenames", no_argument, NULL, 's'}, 5277298Sobrien {"demangle", optional_argument, NULL, 'C'}, 5333965Sjdp {"exe", required_argument, NULL, 'e'}, 5433965Sjdp {"functions", no_argument, NULL, 'f'}, 55218822Sdim {"inlines", no_argument, NULL, 'i'}, 56218822Sdim {"section", required_argument, NULL, 'j'}, 5733965Sjdp {"target", required_argument, NULL, 'b'}, 5833965Sjdp {"help", no_argument, NULL, 'H'}, 5933965Sjdp {"version", no_argument, NULL, 'V'}, 6033965Sjdp {0, no_argument, 0, 0} 6133965Sjdp}; 6233965Sjdp 63130561Sobrienstatic void usage (FILE *, int); 64130561Sobrienstatic void slurp_symtab (bfd *); 65130561Sobrienstatic void find_address_in_section (bfd *, asection *, void *); 66218822Sdimstatic void find_offset_in_section (bfd *, asection *); 67218822Sdimstatic void translate_addresses (bfd *, asection *); 6833965Sjdp 6933965Sjdp/* Print a usage message to STREAM and exit with STATUS. */ 7033965Sjdp 7133965Sjdpstatic void 72130561Sobrienusage (FILE *stream, int status) 7333965Sjdp{ 7489857Sobrien fprintf (stream, _("Usage: %s [option(s)] [addr(s)]\n"), program_name); 7589857Sobrien fprintf (stream, _(" Convert addresses into line number/file name pairs.\n")); 7689857Sobrien fprintf (stream, _(" If no addresses are specified on the command line, they will be read from stdin\n")); 7789857Sobrien fprintf (stream, _(" The options are:\n\ 78218822Sdim @<file> Read options from <file>\n\ 7989857Sobrien -b --target=<bfdname> Set the binary file format\n\ 8089857Sobrien -e --exe=<executable> Set the input file name (default is a.out)\n\ 81218822Sdim -i --inlines Unwind inlined functions\n\ 82218822Sdim -j --section=<name> Read section-relative offsets instead of addresses\n\ 8389857Sobrien -s --basenames Strip directory names\n\ 8489857Sobrien -f --functions Show function names\n\ 8589857Sobrien -C --demangle[=style] Demangle function names\n\ 8689857Sobrien -h --help Display this information\n\ 8789857Sobrien -v --version Display the program's version\n\ 8889857Sobrien\n")); 8989857Sobrien 9033965Sjdp list_supported_targets (program_name, stream); 91218822Sdim if (REPORT_BUGS_TO[0] && status == 0) 9260484Sobrien fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 9333965Sjdp exit (status); 9433965Sjdp} 9533965Sjdp 9633965Sjdp/* Read in the symbol table. */ 9733965Sjdp 9833965Sjdpstatic void 99130561Sobrienslurp_symtab (bfd *abfd) 10033965Sjdp{ 10133965Sjdp long symcount; 102130561Sobrien unsigned int size; 10333965Sjdp 10433965Sjdp if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0) 10533965Sjdp return; 10633965Sjdp 107130561Sobrien symcount = bfd_read_minisymbols (abfd, FALSE, (void *) &syms, &size); 108130561Sobrien if (symcount == 0) 109130561Sobrien symcount = bfd_read_minisymbols (abfd, TRUE /* dynamic */, (void *) &syms, &size); 11033965Sjdp 11133965Sjdp if (symcount < 0) 11233965Sjdp bfd_fatal (bfd_get_filename (abfd)); 11333965Sjdp} 11433965Sjdp 11533965Sjdp/* These global variables are used to pass information between 11633965Sjdp translate_addresses and find_address_in_section. */ 11733965Sjdp 11833965Sjdpstatic bfd_vma pc; 11933965Sjdpstatic const char *filename; 12033965Sjdpstatic const char *functionname; 12133965Sjdpstatic unsigned int line; 122130561Sobrienstatic bfd_boolean found; 12333965Sjdp 12433965Sjdp/* Look for an address in a section. This is called via 12533965Sjdp bfd_map_over_sections. */ 12633965Sjdp 12733965Sjdpstatic void 128130561Sobrienfind_address_in_section (bfd *abfd, asection *section, 129130561Sobrien void *data ATTRIBUTE_UNUSED) 13033965Sjdp{ 13133965Sjdp bfd_vma vma; 13260484Sobrien bfd_size_type size; 13333965Sjdp 13433965Sjdp if (found) 13533965Sjdp return; 13633965Sjdp 13733965Sjdp if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) 13833965Sjdp return; 13933965Sjdp 14033965Sjdp vma = bfd_get_section_vma (abfd, section); 14133965Sjdp if (pc < vma) 14233965Sjdp return; 14333965Sjdp 144218822Sdim size = bfd_get_section_size (section); 14560484Sobrien if (pc >= vma + size) 14660484Sobrien return; 14760484Sobrien 14833965Sjdp found = bfd_find_nearest_line (abfd, section, syms, pc - vma, 14933965Sjdp &filename, &functionname, &line); 15033965Sjdp} 15133965Sjdp 152218822Sdim/* Look for an offset in a section. This is directly called. */ 153218822Sdim 154218822Sdimstatic void 155218822Sdimfind_offset_in_section (bfd *abfd, asection *section) 156218822Sdim{ 157218822Sdim bfd_size_type size; 158218822Sdim 159218822Sdim if (found) 160218822Sdim return; 161218822Sdim 162218822Sdim if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) 163218822Sdim return; 164218822Sdim 165218822Sdim size = bfd_get_section_size (section); 166218822Sdim if (pc >= size) 167218822Sdim return; 168218822Sdim 169218822Sdim found = bfd_find_nearest_line (abfd, section, syms, pc, 170218822Sdim &filename, &functionname, &line); 171218822Sdim} 172218822Sdim 17333965Sjdp/* Read hexadecimal addresses from stdin, translate into 17433965Sjdp file_name:line_number and optionally function name. */ 17533965Sjdp 17633965Sjdpstatic void 177218822Sdimtranslate_addresses (bfd *abfd, asection *section) 17833965Sjdp{ 17933965Sjdp int read_stdin = (naddr == 0); 18033965Sjdp 18133965Sjdp for (;;) 18233965Sjdp { 18333965Sjdp if (read_stdin) 18433965Sjdp { 18533965Sjdp char addr_hex[100]; 18633965Sjdp 18733965Sjdp if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL) 18833965Sjdp break; 18938889Sjdp pc = bfd_scan_vma (addr_hex, NULL, 16); 19033965Sjdp } 19133965Sjdp else 19233965Sjdp { 19333965Sjdp if (naddr <= 0) 19433965Sjdp break; 19533965Sjdp --naddr; 19638889Sjdp pc = bfd_scan_vma (*addr++, NULL, 16); 19733965Sjdp } 19833965Sjdp 199130561Sobrien found = FALSE; 200218822Sdim if (section) 201218822Sdim find_offset_in_section (abfd, section); 202218822Sdim else 203218822Sdim bfd_map_over_sections (abfd, find_address_in_section, NULL); 20433965Sjdp 20533965Sjdp if (! found) 20633965Sjdp { 20733965Sjdp if (with_functions) 20833965Sjdp printf ("??\n"); 20933965Sjdp printf ("??:0\n"); 21033965Sjdp } 21133965Sjdp else 21233965Sjdp { 213218822Sdim do { 214218822Sdim if (with_functions) 215218822Sdim { 216218822Sdim const char *name; 217218822Sdim char *alloc = NULL; 218104834Sobrien 219218822Sdim name = functionname; 220218822Sdim if (name == NULL || *name == '\0') 221218822Sdim name = "??"; 222218822Sdim else if (do_demangle) 223218822Sdim { 224218822Sdim alloc = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS); 225218822Sdim if (alloc != NULL) 226218822Sdim name = alloc; 227218822Sdim } 22833965Sjdp 229218822Sdim printf ("%s\n", name); 230104834Sobrien 231218822Sdim if (alloc != NULL) 232218822Sdim free (alloc); 233218822Sdim } 23433965Sjdp 235218822Sdim if (base_names && filename != NULL) 236218822Sdim { 237218822Sdim char *h; 23833965Sjdp 239218822Sdim h = strrchr (filename, '/'); 240218822Sdim if (h != NULL) 241218822Sdim filename = h + 1; 242218822Sdim } 24333965Sjdp 244218822Sdim printf ("%s:%u\n", filename ? filename : "??", line); 245218822Sdim if (!unwind_inlines) 246218822Sdim found = FALSE; 247218822Sdim else 248218822Sdim found = bfd_find_inliner_info (abfd, &filename, &functionname, &line); 249218822Sdim } while (found); 250218822Sdim 25133965Sjdp } 25233965Sjdp 25333965Sjdp /* fflush() is essential for using this command as a server 25433965Sjdp child process that reads addresses from a pipe and responds 25533965Sjdp with line number information, processing one address at a 25633965Sjdp time. */ 25733965Sjdp fflush (stdout); 25833965Sjdp } 25933965Sjdp} 26033965Sjdp 261218822Sdim/* Process a file. Returns an exit value for main(). */ 26233965Sjdp 263218822Sdimstatic int 264218822Sdimprocess_file (const char *file_name, const char *section_name, 265218822Sdim const char *target) 26633965Sjdp{ 26733965Sjdp bfd *abfd; 268218822Sdim asection *section; 26933965Sjdp char **matching; 27033965Sjdp 271130561Sobrien if (get_file_size (file_name) < 1) 272218822Sdim return 1; 273130561Sobrien 274104834Sobrien abfd = bfd_openr (file_name, target); 27533965Sjdp if (abfd == NULL) 276104834Sobrien bfd_fatal (file_name); 27733965Sjdp 27833965Sjdp if (bfd_check_format (abfd, bfd_archive)) 279218822Sdim fatal (_("%s: cannot get addresses from archive"), file_name); 28033965Sjdp 28133965Sjdp if (! bfd_check_format_matches (abfd, bfd_object, &matching)) 28233965Sjdp { 28333965Sjdp bfd_nonfatal (bfd_get_filename (abfd)); 28433965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 28533965Sjdp { 28633965Sjdp list_matching_formats (matching); 28733965Sjdp free (matching); 28833965Sjdp } 28933965Sjdp xexit (1); 29033965Sjdp } 29133965Sjdp 292218822Sdim if (section_name != NULL) 293218822Sdim { 294218822Sdim section = bfd_get_section_by_name (abfd, section_name); 295218822Sdim if (section == NULL) 296218822Sdim fatal (_("%s: cannot find section %s"), file_name, section_name); 297218822Sdim } 298218822Sdim else 299218822Sdim section = NULL; 300218822Sdim 30133965Sjdp slurp_symtab (abfd); 30233965Sjdp 303218822Sdim translate_addresses (abfd, section); 30433965Sjdp 30533965Sjdp if (syms != NULL) 30633965Sjdp { 30733965Sjdp free (syms); 30833965Sjdp syms = NULL; 30933965Sjdp } 31033965Sjdp 31133965Sjdp bfd_close (abfd); 312218822Sdim 313218822Sdim return 0; 31433965Sjdp} 31533965Sjdp 31633965Sjdpint 317130561Sobrienmain (int argc, char **argv) 31833965Sjdp{ 319104834Sobrien const char *file_name; 320218822Sdim const char *section_name; 32133965Sjdp char *target; 32233965Sjdp int c; 32333965Sjdp 32460484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 32560484Sobrien setlocale (LC_MESSAGES, ""); 32660484Sobrien#endif 32789857Sobrien#if defined (HAVE_SETLOCALE) 32889857Sobrien setlocale (LC_CTYPE, ""); 32989857Sobrien#endif 33060484Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 33160484Sobrien textdomain (PACKAGE); 33260484Sobrien 33333965Sjdp program_name = *argv; 33433965Sjdp xmalloc_set_program_name (program_name); 33533965Sjdp 336218822Sdim expandargv (&argc, &argv); 337218822Sdim 33833965Sjdp bfd_init (); 33933965Sjdp set_default_bfd_target (); 34033965Sjdp 341104834Sobrien file_name = NULL; 342218822Sdim section_name = NULL; 34333965Sjdp target = NULL; 344218822Sdim while ((c = getopt_long (argc, argv, "b:Ce:sfHhij:Vv", long_options, (int *) 0)) 34533965Sjdp != EOF) 34633965Sjdp { 34733965Sjdp switch (c) 34833965Sjdp { 34933965Sjdp case 0: 35089857Sobrien break; /* We've been given a long option. */ 35133965Sjdp case 'b': 35233965Sjdp target = optarg; 35333965Sjdp break; 35433965Sjdp case 'C': 355130561Sobrien do_demangle = TRUE; 35677298Sobrien if (optarg != NULL) 35777298Sobrien { 35877298Sobrien enum demangling_styles style; 359104834Sobrien 36077298Sobrien style = cplus_demangle_name_to_style (optarg); 361104834Sobrien if (style == unknown_demangling) 36277298Sobrien fatal (_("unknown demangling style `%s'"), 36377298Sobrien optarg); 364104834Sobrien 36577298Sobrien cplus_demangle_set_style (style); 366104834Sobrien } 36733965Sjdp break; 36833965Sjdp case 'e': 369104834Sobrien file_name = optarg; 37033965Sjdp break; 37133965Sjdp case 's': 372130561Sobrien base_names = TRUE; 37333965Sjdp break; 37433965Sjdp case 'f': 375130561Sobrien with_functions = TRUE; 37633965Sjdp break; 37789857Sobrien case 'v': 37833965Sjdp case 'V': 37933965Sjdp print_version ("addr2line"); 38033965Sjdp break; 38189857Sobrien case 'h': 38233965Sjdp case 'H': 38333965Sjdp usage (stdout, 0); 38433965Sjdp break; 385218822Sdim case 'i': 386218822Sdim unwind_inlines = TRUE; 387218822Sdim break; 388218822Sdim case 'j': 389218822Sdim section_name = optarg; 390218822Sdim break; 39133965Sjdp default: 39233965Sjdp usage (stderr, 1); 39333965Sjdp break; 39433965Sjdp } 39533965Sjdp } 39633965Sjdp 397104834Sobrien if (file_name == NULL) 398104834Sobrien file_name = "a.out"; 39933965Sjdp 40033965Sjdp addr = argv + optind; 40133965Sjdp naddr = argc - optind; 40233965Sjdp 403218822Sdim return process_file (file_name, section_name, target); 40433965Sjdp} 405