addr2line.c revision 78828
1/* addr2line.c -- convert addresses to line number and function name 2 Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc. 3 Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.siemens.de> 4 5 This file is part of GNU Binutils. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21/* Derived from objdump.c and nm.c by Ulrich.Lauther@mchp.siemens.de 22 23 Usage: 24 addr2line [options] addr addr ... 25 or 26 addr2line [options] 27 28 both forms write results to stdout, the second form reads addresses 29 to be converted from stdin. */ 30 31#include <ctype.h> 32#include <string.h> 33 34#include "bfd.h" 35#include "getopt.h" 36#include "libiberty.h" 37#include "demangle.h" 38#include "bucomm.h" 39 40extern char *program_version; 41 42static boolean with_functions; /* -f, show function names. */ 43static boolean do_demangle; /* -C, demangle names. */ 44static boolean base_names; /* -s, strip directory names. */ 45 46static int naddr; /* Number of addresses to process. */ 47static char **addr; /* Hex addresses to process. */ 48 49static asymbol **syms; /* Symbol table. */ 50 51static struct option long_options[] = 52{ 53 {"basenames", no_argument, NULL, 's'}, 54 {"demangle", optional_argument, NULL, 'C'}, 55 {"exe", required_argument, NULL, 'e'}, 56 {"functions", no_argument, NULL, 'f'}, 57 {"target", required_argument, NULL, 'b'}, 58 {"help", no_argument, NULL, 'H'}, 59 {"version", no_argument, NULL, 'V'}, 60 {0, no_argument, 0, 0} 61}; 62 63static void usage PARAMS ((FILE *, int)); 64static void slurp_symtab PARAMS ((bfd *)); 65static void find_address_in_section PARAMS ((bfd *, asection *, PTR)); 66static void translate_addresses PARAMS ((bfd *)); 67static void process_file PARAMS ((const char *, const char *)); 68 69/* Print a usage message to STREAM and exit with STATUS. */ 70 71static void 72usage (stream, status) 73 FILE *stream; 74 int status; 75{ 76 fprintf (stream, _("\ 77Usage: %s [-CfsHV] [-b bfdname] [--target=bfdname]\n\ 78 [-e executable] [--exe=executable] [--demangle[=style]]\n\ 79 [--basenames] [--functions] [addr addr ...]\n"), 80 program_name); 81 list_supported_targets (program_name, stream); 82 if (status == 0) 83 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 84 exit (status); 85} 86 87/* Read in the symbol table. */ 88 89static void 90slurp_symtab (abfd) 91 bfd *abfd; 92{ 93 long storage; 94 long symcount; 95 96 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0) 97 return; 98 99 storage = bfd_get_symtab_upper_bound (abfd); 100 if (storage < 0) 101 bfd_fatal (bfd_get_filename (abfd)); 102 103 syms = (asymbol **) xmalloc (storage); 104 105 symcount = bfd_canonicalize_symtab (abfd, syms); 106 if (symcount < 0) 107 bfd_fatal (bfd_get_filename (abfd)); 108} 109 110/* These global variables are used to pass information between 111 translate_addresses and find_address_in_section. */ 112 113static bfd_vma pc; 114static const char *filename; 115static const char *functionname; 116static unsigned int line; 117static boolean found; 118 119/* Look for an address in a section. This is called via 120 bfd_map_over_sections. */ 121 122static void 123find_address_in_section (abfd, section, data) 124 bfd *abfd; 125 asection *section; 126 PTR data ATTRIBUTE_UNUSED; 127{ 128 bfd_vma vma; 129 bfd_size_type size; 130 131 if (found) 132 return; 133 134 if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) 135 return; 136 137 vma = bfd_get_section_vma (abfd, section); 138 if (pc < vma) 139 return; 140 141 size = bfd_get_section_size_before_reloc (section); 142 if (pc >= vma + size) 143 return; 144 145 found = bfd_find_nearest_line (abfd, section, syms, pc - vma, 146 &filename, &functionname, &line); 147} 148 149/* Read hexadecimal addresses from stdin, translate into 150 file_name:line_number and optionally function name. */ 151 152static void 153translate_addresses (abfd) 154 bfd *abfd; 155{ 156 int read_stdin = (naddr == 0); 157 158 for (;;) 159 { 160 if (read_stdin) 161 { 162 char addr_hex[100]; 163 164 if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL) 165 break; 166 pc = bfd_scan_vma (addr_hex, NULL, 16); 167 } 168 else 169 { 170 if (naddr <= 0) 171 break; 172 --naddr; 173 pc = bfd_scan_vma (*addr++, NULL, 16); 174 } 175 176 found = false; 177 bfd_map_over_sections (abfd, find_address_in_section, (PTR) NULL); 178 179 if (! found) 180 { 181 if (with_functions) 182 printf ("??\n"); 183 printf ("??:0\n"); 184 } 185 else 186 { 187 if (with_functions) 188 { 189 if (functionname == NULL || *functionname == '\0') 190 printf ("??\n"); 191 else if (! do_demangle) 192 printf ("%s\n", functionname); 193 else 194 { 195 char *res; 196 197 res = cplus_demangle (functionname, DMGL_ANSI | DMGL_PARAMS); 198 if (res == NULL) 199 printf ("%s\n", functionname); 200 else 201 { 202 printf ("%s\n", res); 203 free (res); 204 } 205 } 206 } 207 208 if (base_names && filename != NULL) 209 { 210 char *h; 211 212 h = strrchr (filename, '/'); 213 if (h != NULL) 214 filename = h + 1; 215 } 216 217 printf ("%s:%u\n", filename ? filename : "??", line); 218 } 219 220 /* fflush() is essential for using this command as a server 221 child process that reads addresses from a pipe and responds 222 with line number information, processing one address at a 223 time. */ 224 fflush (stdout); 225 } 226} 227 228/* Process a file. */ 229 230static void 231process_file (filename, target) 232 const char *filename; 233 const char *target; 234{ 235 bfd *abfd; 236 char **matching; 237 238 abfd = bfd_openr (filename, target); 239 if (abfd == NULL) 240 bfd_fatal (filename); 241 242 if (bfd_check_format (abfd, bfd_archive)) 243 fatal (_("%s: can not get addresses from archive"), filename); 244 245 if (! bfd_check_format_matches (abfd, bfd_object, &matching)) 246 { 247 bfd_nonfatal (bfd_get_filename (abfd)); 248 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 249 { 250 list_matching_formats (matching); 251 free (matching); 252 } 253 xexit (1); 254 } 255 256 slurp_symtab (abfd); 257 258 translate_addresses (abfd); 259 260 if (syms != NULL) 261 { 262 free (syms); 263 syms = NULL; 264 } 265 266 bfd_close (abfd); 267} 268 269int 270main (argc, argv) 271 int argc; 272 char **argv; 273{ 274 const char *filename; 275 char *target; 276 int c; 277 278#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 279 setlocale (LC_MESSAGES, ""); 280#endif 281 bindtextdomain (PACKAGE, LOCALEDIR); 282 textdomain (PACKAGE); 283 284 program_name = *argv; 285 xmalloc_set_program_name (program_name); 286 287 bfd_init (); 288 set_default_bfd_target (); 289 290 filename = NULL; 291 target = NULL; 292 while ((c = getopt_long (argc, argv, "b:Ce:sfHV", long_options, (int *) 0)) 293 != EOF) 294 { 295 switch (c) 296 { 297 case 0: 298 break; /* we've been given a long option */ 299 case 'b': 300 target = optarg; 301 break; 302 case 'C': 303 do_demangle = true; 304 if (optarg != NULL) 305 { 306 enum demangling_styles style; 307 308 style = cplus_demangle_name_to_style (optarg); 309 if (style == unknown_demangling) 310 fatal (_("unknown demangling style `%s'"), 311 optarg); 312 313 cplus_demangle_set_style (style); 314 } 315 break; 316 case 'e': 317 filename = optarg; 318 break; 319 case 's': 320 base_names = true; 321 break; 322 case 'f': 323 with_functions = true; 324 break; 325 case 'V': 326 print_version ("addr2line"); 327 break; 328 case 'H': 329 usage (stdout, 0); 330 break; 331 default: 332 usage (stderr, 1); 333 break; 334 } 335 } 336 337 if (filename == NULL) 338 filename = "a.out"; 339 340 addr = argv + optind; 341 naddr = argc - optind; 342 343 process_file (filename, target); 344 345 return 0; 346} 347