addr2line.c revision 60484
1191783Srmacklem/* addr2line.c -- convert addresses to line number and function name 2191783Srmacklem Copyright 1997, 98, 99, 2000 Free Software Foundation, Inc. 3191783Srmacklem Contributed by Ulrich Lauther <Ulrich.Lauther@zfe.siemens.de> 4191783Srmacklem 5191783Srmacklem This file is part of GNU Binutils. 6191783Srmacklem 7191783Srmacklem This program is free software; you can redistribute it and/or modify 8191783Srmacklem it under the terms of the GNU General Public License as published by 9191783Srmacklem the Free Software Foundation; either version 2, or (at your option) 10191783Srmacklem any later version. 11191783Srmacklem 12191783Srmacklem This program is distributed in the hope that it will be useful, 13191783Srmacklem but WITHOUT ANY WARRANTY; without even the implied warranty of 14191783Srmacklem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15191783Srmacklem GNU General Public License for more details. 16191783Srmacklem 17191783Srmacklem You should have received a copy of the GNU General Public License 18191783Srmacklem along with this program; if not, write to the Free Software 19191783Srmacklem Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20191783Srmacklem 21191783Srmacklem/* Derived from objdump.c and nm.c by Ulrich.Lauther@zfe.siemens.de 22191783Srmacklem 23191783Srmacklem Usage: 24191783Srmacklem addr2line [options] addr addr ... 25191783Srmacklem or 26191783Srmacklem addr2line [options] 27191783Srmacklem 28191783Srmacklem both forms write results to stdout, the second form reads addresses 29191783Srmacklem to be converted from stdin. */ 30191783Srmacklem 31191783Srmacklem#include <ctype.h> 32191783Srmacklem#include <string.h> 33191783Srmacklem 34191783Srmacklem#include "bfd.h" 35191783Srmacklem#include "getopt.h" 36191783Srmacklem#include "libiberty.h" 37191783Srmacklem#include "demangle.h" 38191783Srmacklem#include "bucomm.h" 39191783Srmacklem 40191783Srmacklemextern char *program_version; 41191783Srmacklem 42191783Srmacklemstatic boolean with_functions; /* -f, show function names. */ 43191783Srmacklemstatic boolean do_demangle; /* -C, demangle names. */ 44191783Srmacklemstatic boolean base_names; /* -s, strip directory names. */ 45306663Srmacklem 46244042Srmacklemstatic int naddr; /* Number of addresses to process. */ 47191783Srmacklemstatic char **addr; /* Hex addresses to process. */ 48191783Srmacklem 49191783Srmacklemstatic asymbol **syms; /* Symbol table. */ 50244042Srmacklem 51191783Srmacklemstatic struct option long_options[] = 52191783Srmacklem{ 53191783Srmacklem {"basenames", no_argument, NULL, 's'}, 54191783Srmacklem {"demangle", no_argument, NULL, 'C'}, 55191783Srmacklem {"exe", required_argument, NULL, 'e'}, 56191783Srmacklem {"functions", no_argument, NULL, 'f'}, 57191783Srmacklem {"target", required_argument, NULL, 'b'}, 58191783Srmacklem {"help", no_argument, NULL, 'H'}, 59191783Srmacklem {"version", no_argument, NULL, 'V'}, 60244042Srmacklem {0, no_argument, 0, 0} 61191783Srmacklem}; 62191783Srmacklem 63191783Srmacklemstatic void usage PARAMS ((FILE *, int)); 64191783Srmacklemstatic void slurp_symtab PARAMS ((bfd *)); 65191783Srmacklemstatic void find_address_in_section PARAMS ((bfd *, asection *, PTR)); 66191783Srmacklemstatic void translate_addresses PARAMS ((bfd *)); 67191783Srmacklemstatic void process_file PARAMS ((const char *, const char *)); 68191783Srmacklem 69265466Srmacklem/* Print a usage message to STREAM and exit with STATUS. */ 70265469Srmacklem 71191783Srmacklemstatic void 72191783Srmacklemusage (stream, status) 73191783Srmacklem FILE *stream; 74191783Srmacklem int status; 75191783Srmacklem{ 76191783Srmacklem fprintf (stream, _("\ 77191783SrmacklemUsage: %s [-CfsHV] [-b bfdname] [--target=bfdname]\n\ 78191783Srmacklem [-e executable] [--exe=executable] [--demangle]\n\ 79191783Srmacklem [--basenames] [--functions] [addr addr ...]\n"), 80191783Srmacklem program_name); 81191783Srmacklem list_supported_targets (program_name, stream); 82191783Srmacklem if (status == 0) 83191783Srmacklem fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 84191783Srmacklem exit (status); 85191783Srmacklem} 86191783Srmacklem 87191783Srmacklem/* Read in the symbol table. */ 88191783Srmacklem 89191783Srmacklemstatic void 90191783Srmacklemslurp_symtab (abfd) 91191783Srmacklem bfd *abfd; 92191783Srmacklem{ 93191783Srmacklem long storage; 94191783Srmacklem long symcount; 95191783Srmacklem 96191783Srmacklem if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0) 97191783Srmacklem return; 98191783Srmacklem 99191783Srmacklem storage = bfd_get_symtab_upper_bound (abfd); 100191783Srmacklem if (storage < 0) 101191783Srmacklem bfd_fatal (bfd_get_filename (abfd)); 102244042Srmacklem 103244042Srmacklem syms = (asymbol **) xmalloc (storage); 104244042Srmacklem 105244042Srmacklem symcount = bfd_canonicalize_symtab (abfd, syms); 106244042Srmacklem if (symcount < 0) 107244042Srmacklem bfd_fatal (bfd_get_filename (abfd)); 108244042Srmacklem} 109244042Srmacklem 110244042Srmacklem/* These global variables are used to pass information between 111244042Srmacklem translate_addresses and find_address_in_section. */ 112244042Srmacklem 113244042Srmacklemstatic bfd_vma pc; 114244042Srmacklemstatic const char *filename; 115191783Srmacklemstatic const char *functionname; 116191783Srmacklemstatic unsigned int line; 117191783Srmacklemstatic boolean found; 118191783Srmacklem 119191783Srmacklem/* Look for an address in a section. This is called via 120244042Srmacklem bfd_map_over_sections. */ 121191783Srmacklem 122244042Srmacklemstatic void 123244042Srmacklemfind_address_in_section (abfd, section, data) 124191783Srmacklem bfd *abfd; 125191783Srmacklem asection *section; 126191783Srmacklem PTR data ATTRIBUTE_UNUSED; 127191783Srmacklem{ 128191783Srmacklem bfd_vma vma; 129191783Srmacklem bfd_size_type size; 130191783Srmacklem 131191783Srmacklem if (found) 132244042Srmacklem return; 133191783Srmacklem 134191783Srmacklem if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) 135191783Srmacklem return; 136191783Srmacklem 137191783Srmacklem vma = bfd_get_section_vma (abfd, section); 138191783Srmacklem if (pc < vma) 139191783Srmacklem return; 140191783Srmacklem 141191783Srmacklem size = bfd_get_section_size_before_reloc (section); 142244042Srmacklem if (pc >= vma + size) 143244042Srmacklem return; 144240720Srmacklem 145244042Srmacklem found = bfd_find_nearest_line (abfd, section, syms, pc - vma, 146244042Srmacklem &filename, &functionname, &line); 147244042Srmacklem} 148240720Srmacklem 149191783Srmacklem/* Read hexadecimal addresses from stdin, translate into 150240720Srmacklem file_name:line_number and optionally function name. */ 151191783Srmacklem 152191783Srmacklemstatic void 153191783Srmacklemtranslate_addresses (abfd) 154191783Srmacklem bfd *abfd; 155191783Srmacklem{ 156191783Srmacklem int read_stdin = (naddr == 0); 157191783Srmacklem 158243882Sglebius for (;;) 159191783Srmacklem { 160191783Srmacklem if (read_stdin) 161191783Srmacklem { 162191783Srmacklem char addr_hex[100]; 163191783Srmacklem 164191783Srmacklem if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL) 165191783Srmacklem break; 166191783Srmacklem pc = bfd_scan_vma (addr_hex, NULL, 16); 167191783Srmacklem } 168191783Srmacklem else 169191783Srmacklem { 170191783Srmacklem if (naddr <= 0) 171244042Srmacklem break; 172244042Srmacklem --naddr; 173244042Srmacklem pc = bfd_scan_vma (*addr++, NULL, 16); 174244042Srmacklem } 175244042Srmacklem 176244042Srmacklem found = false; 177244042Srmacklem bfd_map_over_sections (abfd, find_address_in_section, (PTR) NULL); 178244042Srmacklem 179244042Srmacklem if (! found) 180244042Srmacklem { 181244042Srmacklem if (with_functions) 182244042Srmacklem printf ("??\n"); 183244042Srmacklem printf ("??:0\n"); 184244042Srmacklem } 185244042Srmacklem else 186244042Srmacklem { 187244042Srmacklem if (with_functions) 188191783Srmacklem { 189191783Srmacklem if (functionname == NULL || *functionname == '\0') 190191783Srmacklem printf ("??\n"); 191191783Srmacklem else if (! do_demangle) 192191783Srmacklem printf ("%s\n", functionname); 193244042Srmacklem else 194244042Srmacklem { 195244042Srmacklem char *res; 196244042Srmacklem 197244042Srmacklem res = cplus_demangle (functionname, DMGL_ANSI | DMGL_PARAMS); 198191783Srmacklem if (res == NULL) 199191783Srmacklem printf ("%s\n", functionname); 200244042Srmacklem else 201244042Srmacklem { 202244042Srmacklem printf ("%s\n", res); 203317404Srmacklem free (res); 204317404Srmacklem } 205317404Srmacklem } 206244042Srmacklem } 207244042Srmacklem 208317404Srmacklem if (base_names && filename != NULL) 209317404Srmacklem { 210317404Srmacklem char *h; 211244042Srmacklem 212317404Srmacklem h = strrchr (filename, '/'); 213259238Srmacklem if (h != NULL) 214244042Srmacklem filename = h + 1; 215244042Srmacklem } 216191783Srmacklem 217244042Srmacklem printf ("%s:%u\n", filename ? filename : "??", line); 218191783Srmacklem } 219191783Srmacklem 220244042Srmacklem /* fflush() is essential for using this command as a server 221244042Srmacklem child process that reads addresses from a pipe and responds 222244042Srmacklem with line number information, processing one address at a 223191783Srmacklem time. */ 224191783Srmacklem fflush (stdout); 225265434Srmacklem } 226265434Srmacklem} 227265434Srmacklem 228265434Srmacklem/* Process a file. */ 229265434Srmacklem 230265434Srmacklemstatic void 231265434Srmacklemprocess_file (filename, target) 232265434Srmacklem const char *filename; 233265434Srmacklem const char *target; 234265434Srmacklem{ 235265434Srmacklem bfd *abfd; 236191783Srmacklem char **matching; 237191783Srmacklem 238244042Srmacklem abfd = bfd_openr (filename, target); 239244042Srmacklem if (abfd == NULL) 240244042Srmacklem bfd_fatal (filename); 241191783Srmacklem 242244042Srmacklem if (bfd_check_format (abfd, bfd_archive)) 243191783Srmacklem fatal (_("%s: can not get addresses from archive"), filename); 244191783Srmacklem 245191783Srmacklem if (! bfd_check_format_matches (abfd, bfd_object, &matching)) 246191783Srmacklem { 247306663Srmacklem bfd_nonfatal (bfd_get_filename (abfd)); 248306663Srmacklem if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 249191783Srmacklem { 250191783Srmacklem list_matching_formats (matching); 251191783Srmacklem free (matching); 252191783Srmacklem } 253191783Srmacklem xexit (1); 254191783Srmacklem } 255191783Srmacklem 256191783Srmacklem slurp_symtab (abfd); 257191783Srmacklem 258191783Srmacklem translate_addresses (abfd); 259191783Srmacklem 260191783Srmacklem if (syms != NULL) 261191783Srmacklem { 262191783Srmacklem free (syms); 263191783Srmacklem syms = NULL; 264191783Srmacklem } 265209120Skib 266191783Srmacklem bfd_close (abfd); 267191783Srmacklem} 268191783Srmacklem 269191783Srmacklemint 270191783Srmacklemmain (argc, argv) 271191783Srmacklem int argc; 272191783Srmacklem char **argv; 273191783Srmacklem{ 274191783Srmacklem char *filename; 275191783Srmacklem char *target; 276191783Srmacklem int c; 277191783Srmacklem 278191783Srmacklem#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 279191783Srmacklem setlocale (LC_MESSAGES, ""); 280191783Srmacklem#endif 281191783Srmacklem bindtextdomain (PACKAGE, LOCALEDIR); 282191783Srmacklem textdomain (PACKAGE); 283243882Sglebius 284191783Srmacklem program_name = *argv; 285191783Srmacklem xmalloc_set_program_name (program_name); 286191783Srmacklem 287191783Srmacklem bfd_init (); 288191783Srmacklem set_default_bfd_target (); 289191783Srmacklem 290191783Srmacklem filename = NULL; 291191783Srmacklem target = NULL; 292191783Srmacklem while ((c = getopt_long (argc, argv, "b:Ce:sfHV", long_options, (int *) 0)) 293191783Srmacklem != EOF) 294191783Srmacklem { 295191783Srmacklem switch (c) 296191783Srmacklem { 297191783Srmacklem case 0: 298191783Srmacklem break; /* we've been given a long option */ 299191783Srmacklem case 'b': 300191783Srmacklem target = optarg; 301191783Srmacklem break; 302191783Srmacklem case 'C': 303191783Srmacklem do_demangle = true; 304191783Srmacklem break; 305191783Srmacklem case 'e': 306191783Srmacklem filename = optarg; 307191783Srmacklem break; 308191783Srmacklem case 's': 309191783Srmacklem base_names = true; 310191783Srmacklem break; 311191783Srmacklem case 'f': 312191783Srmacklem with_functions = true; 313191783Srmacklem break; 314191783Srmacklem case 'V': 315191783Srmacklem print_version ("addr2line"); 316191783Srmacklem break; 317191783Srmacklem case 'H': 318191783Srmacklem usage (stdout, 0); 319191783Srmacklem break; 320191783Srmacklem default: 321191783Srmacklem usage (stderr, 1); 322191783Srmacklem break; 323191783Srmacklem } 324191783Srmacklem } 325191783Srmacklem 326191783Srmacklem if (filename == NULL) 327191783Srmacklem filename = "a.out"; 328191783Srmacklem 329191783Srmacklem addr = argv + optind; 330191783Srmacklem naddr = argc - optind; 331191783Srmacklem 332191783Srmacklem process_file (filename, target); 333191783Srmacklem 334191783Srmacklem return 0; 335191783Srmacklem} 336191783Srmacklem