1 /* Locate source files and line information for given addresses 2 Copyright (C) 2005-2010, 2012 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2005. 5 6 Red Hat elfutils is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 2 of the License. 9 10 Red Hat elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with Red Hat elfutils; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 19 Red Hat elfutils is an included package of the Open Invention Network. 20 An included package of the Open Invention Network is a package for which 21 Open Invention Network licensees cross-license their patents. No patent 22 license is granted, either expressly or impliedly, by designation as an 23 included package. Should you wish to participate in the Open Invention 24 Network licensing program, please visit www.openinventionnetwork.com 25 <http://www.openinventionnetwork.com>. */ 26 27 #ifdef HAVE_CONFIG_H 28 # include <config.h> 29 #endif 30 31 #include <argp.h> 32 #include <assert.h> 33 #include <errno.h> 34 #include <error.h> 35 #include <fcntl.h> 36 #include <inttypes.h> 37 #include <libdwfl.h> 38 #include <dwarf.h> 39 #include <libintl.h> 40 #include <locale.h> 41 #include <mcheck.h> 42 #include <stdbool.h> 43 #include <stdio.h> 44 #include <stdio_ext.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include <system.h> 50 51 52 /* Name and version of program. */ 53 static void print_version (FILE *stream, struct argp_state *state); 54 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 55 56 /* Bug report address. */ 57 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 58 59 60 /* Values for the parameters which have no short form. */ 61 #define OPT_DEMANGLER 0x100 62 63 /* Definitions of arguments for argp functions. */ 64 static const struct argp_option options[] = 65 { 66 { NULL, 0, NULL, 0, N_("Output selection options:"), 2 }, 67 { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, 68 { "absolute", 'A', NULL, 0, 69 N_("Show absolute file names using compilation directory"), 0 }, 70 { "functions", 'f', NULL, 0, N_("Also show function names"), 0 }, 71 { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 }, 72 { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 }, 73 { "section", 'j', "NAME", 0, 74 N_("Treat addresses as offsets relative to NAME section."), 0 }, 75 76 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 77 /* Unsupported options. */ 78 { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 }, 79 { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 }, 80 { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 }, 81 { NULL, 0, NULL, 0, NULL, 0 } 82 }; 83 84 /* Short description of program. */ 85 static const char doc[] = N_("\ 86 Locate source files and line information for ADDRs (in a.out by default)."); 87 88 /* Strings for arguments in help texts. */ 89 static const char args_doc[] = N_("[ADDR...]"); 90 91 /* Prototype for option handler. */ 92 static error_t parse_opt (int key, char *arg, struct argp_state *state); 93 94 static struct argp_child argp_children[2]; /* [0] is set in main. */ 95 96 /* Data structure to communicate with argp functions. */ 97 static const struct argp argp = 98 { 99 options, parse_opt, args_doc, doc, argp_children, NULL, NULL 100 }; 101 102 103 /* Handle ADDR. */ 104 static int handle_address (const char *addr, Dwfl *dwfl); 105 106 107 /* True if only base names of files should be shown. */ 108 static bool only_basenames; 109 110 /* True if absolute file names based on DW_AT_comp_dir should be shown. */ 111 static bool use_comp_dir; 112 113 /* True if line flags should be shown. */ 114 static bool show_flags; 115 116 /* True if function names should be shown. */ 117 static bool show_functions; 118 119 /* True if ELF symbol or section info should be shown. */ 120 static bool show_symbols; 121 122 /* If non-null, take address parameters as relative to named section. */ 123 static const char *just_section; 124 125 126 int 127 main (int argc, char *argv[]) 128 { 129 int remaining; 130 int result = 0; 131 132 /* Make memory leak detection possible. */ 133 mtrace (); 134 135 /* We use no threads here which can interfere with handling a stream. */ 136 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 137 138 /* Set locale. */ 139 (void) setlocale (LC_ALL, ""); 140 141 /* Make sure the message catalog can be found. */ 142 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 143 144 /* Initialize the message catalog. */ 145 (void) textdomain (PACKAGE_TARNAME); 146 147 /* Parse and process arguments. This includes opening the modules. */ 148 argp_children[0].argp = dwfl_standard_argp (); 149 argp_children[0].group = 1; 150 Dwfl *dwfl = NULL; 151 (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); 152 assert (dwfl != NULL); 153 154 /* Now handle the addresses. In case none are given on the command 155 line, read from stdin. */ 156 if (remaining == argc) 157 { 158 /* We use no threads here which can interfere with handling a stream. */ 159 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 160 161 char *buf = NULL; 162 size_t len = 0; 163 while (!feof_unlocked (stdin)) 164 { 165 if (getline (&buf, &len, stdin) < 0) 166 break; 167 168 result = handle_address (buf, dwfl); 169 } 170 171 free (buf); 172 } 173 else 174 { 175 do 176 result = handle_address (argv[remaining], dwfl); 177 while (++remaining < argc); 178 } 179 180 return result; 181 } 182 183 184 /* Print the version information. */ 185 static void 186 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) 187 { 188 fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); 189 fprintf (stream, gettext ("\ 190 Copyright (C) %s Red Hat, Inc.\n\ 191 This is free software; see the source for copying conditions. There is NO\n\ 192 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ 193 "), "2012"); 194 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); 195 } 196 197 198 /* Handle program arguments. */ 199 static error_t 200 parse_opt (int key, char *arg, struct argp_state *state) 201 { 202 switch (key) 203 { 204 case ARGP_KEY_INIT: 205 state->child_inputs[0] = state->input; 206 break; 207 208 case 'b': 209 case 'C': 210 case OPT_DEMANGLER: 211 /* Ignored for compatibility. */ 212 break; 213 214 case 's': 215 only_basenames = true; 216 break; 217 218 case 'A': 219 use_comp_dir = true; 220 break; 221 222 case 'f': 223 show_functions = true; 224 break; 225 226 case 'F': 227 show_flags = true; 228 break; 229 230 case 'S': 231 show_symbols = true; 232 break; 233 234 case 'j': 235 just_section = arg; 236 break; 237 238 default: 239 return ARGP_ERR_UNKNOWN; 240 } 241 return 0; 242 } 243 244 245 static bool 246 print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) 247 { 248 Dwarf_Addr bias = 0; 249 Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias); 250 251 Dwarf_Die *scopes; 252 int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes); 253 if (nscopes <= 0) 254 return false; 255 256 for (int i = 0; i < nscopes; ++i) 257 switch (dwarf_tag (&scopes[i])) 258 { 259 case DW_TAG_subprogram: 260 { 261 const char *name = dwarf_diename (&scopes[i]); 262 if (name == NULL) 263 return false; 264 puts (name); 265 return true; 266 } 267 268 case DW_TAG_inlined_subroutine: 269 { 270 const char *name = dwarf_diename (&scopes[i]); 271 if (name == NULL) 272 return false; 273 printf ("%s inlined", name); 274 275 Dwarf_Files *files; 276 if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) 277 { 278 Dwarf_Attribute attr_mem; 279 Dwarf_Word val; 280 if (dwarf_formudata (dwarf_attr (&scopes[i], 281 DW_AT_call_file, 282 &attr_mem), &val) == 0) 283 { 284 const char *file = dwarf_filesrc (files, val, NULL, NULL); 285 unsigned int lineno = 0; 286 unsigned int colno = 0; 287 if (dwarf_formudata (dwarf_attr (&scopes[i], 288 DW_AT_call_line, 289 &attr_mem), &val) == 0) 290 lineno = val; 291 if (dwarf_formudata (dwarf_attr (&scopes[i], 292 DW_AT_call_column, 293 &attr_mem), &val) == 0) 294 colno = val; 295 296 const char *comp_dir = ""; 297 const char *comp_dir_sep = ""; 298 299 if (file == NULL) 300 file = "???"; 301 else if (only_basenames) 302 file = basename (file); 303 else if (use_comp_dir && file[0] != '/') 304 { 305 const char *const *dirs; 306 size_t ndirs; 307 if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 308 && dirs[0] != NULL) 309 { 310 comp_dir = dirs[0]; 311 comp_dir_sep = "/"; 312 } 313 } 314 315 if (lineno == 0) 316 printf (" from %s%s%s", 317 comp_dir, comp_dir_sep, file); 318 else if (colno == 0) 319 printf (" at %s%s%s:%u", 320 comp_dir, comp_dir_sep, file, lineno); 321 else 322 printf (" at %s%s%s:%u:%u", 323 comp_dir, comp_dir_sep, file, lineno, colno); 324 } 325 } 326 printf (" in "); 327 continue; 328 } 329 } 330 331 return false; 332 } 333 334 static void 335 print_addrsym (Dwfl_Module *mod, GElf_Addr addr) 336 { 337 GElf_Sym s; 338 GElf_Word shndx; 339 const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx); 340 if (name == NULL) 341 { 342 /* No symbol name. Get a section name instead. */ 343 int i = dwfl_module_relocate_address (mod, &addr); 344 if (i >= 0) 345 name = dwfl_module_relocation_info (mod, i, NULL); 346 if (name == NULL) 347 puts ("??"); 348 else 349 printf ("(%s)+%#" PRIx64 "\n", name, addr); 350 } 351 else if (addr == s.st_value) 352 puts (name); 353 else 354 printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value); 355 } 356 357 static int 358 see_one_module (Dwfl_Module *mod, 359 void **userdata __attribute__ ((unused)), 360 const char *name __attribute__ ((unused)), 361 Dwarf_Addr start __attribute__ ((unused)), 362 void *arg) 363 { 364 Dwfl_Module **result = arg; 365 if (*result != NULL) 366 return DWARF_CB_ABORT; 367 *result = mod; 368 return DWARF_CB_OK; 369 } 370 371 static int 372 find_symbol (Dwfl_Module *mod, 373 void **userdata __attribute__ ((unused)), 374 const char *name __attribute__ ((unused)), 375 Dwarf_Addr start __attribute__ ((unused)), 376 void *arg) 377 { 378 const char *looking_for = ((void **) arg)[0]; 379 GElf_Sym *symbol = ((void **) arg)[1]; 380 381 int n = dwfl_module_getsymtab (mod); 382 for (int i = 1; i < n; ++i) 383 { 384 const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL); 385 if (symbol_name == NULL || symbol_name[0] == '\0') 386 continue; 387 switch (GELF_ST_TYPE (symbol->st_info)) 388 { 389 case STT_SECTION: 390 case STT_FILE: 391 case STT_TLS: 392 break; 393 default: 394 if (!strcmp (symbol_name, looking_for)) 395 { 396 ((void **) arg)[0] = NULL; 397 return DWARF_CB_ABORT; 398 } 399 } 400 } 401 402 return DWARF_CB_OK; 403 } 404 405 static bool 406 adjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl) 407 { 408 /* It was (section)+offset. This makes sense if there is 409 only one module to look in for a section. */ 410 Dwfl_Module *mod = NULL; 411 if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0 412 || mod == NULL) 413 error (EXIT_FAILURE, 0, gettext ("Section syntax requires" 414 " exactly one module")); 415 416 int nscn = dwfl_module_relocations (mod); 417 for (int i = 0; i < nscn; ++i) 418 { 419 GElf_Word shndx; 420 const char *scn = dwfl_module_relocation_info (mod, i, &shndx); 421 if (unlikely (scn == NULL)) 422 break; 423 if (!strcmp (scn, name)) 424 { 425 /* Found the section. */ 426 GElf_Shdr shdr_mem; 427 GElf_Addr shdr_bias; 428 GElf_Shdr *shdr = gelf_getshdr 429 (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx), 430 &shdr_mem); 431 if (unlikely (shdr == NULL)) 432 break; 433 434 if (*addr >= shdr->sh_size) 435 error (0, 0, 436 gettext ("offset %#" PRIxMAX " lies outside" 437 " section '%s'"), 438 *addr, scn); 439 440 *addr += shdr->sh_addr + shdr_bias; 441 return true; 442 } 443 } 444 445 return false; 446 } 447 448 static int 449 handle_address (const char *string, Dwfl *dwfl) 450 { 451 char *endp; 452 uintmax_t addr = strtoumax (string, &endp, 0); 453 if (endp == string) 454 { 455 bool parsed = false; 456 int i, j; 457 char *name = NULL; 458 if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2 459 && string[i] == '\0') 460 parsed = adjust_to_section (name, &addr, dwfl); 461 switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j)) 462 { 463 default: 464 break; 465 case 1: 466 addr = 0; 467 j = i; 468 case 2: 469 if (string[j] != '\0') 470 break; 471 472 /* It was symbol[+offset]. */ 473 GElf_Sym sym; 474 void *arg[2] = { name, &sym }; 475 (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0); 476 if (arg[0] != NULL) 477 error (0, 0, gettext ("cannot find symbol '%s'"), name); 478 else 479 { 480 if (sym.st_size != 0 && addr >= sym.st_size) 481 error (0, 0, 482 gettext ("offset %#" PRIxMAX " lies outside" 483 " contents of '%s'"), 484 addr, name); 485 addr += sym.st_value; 486 parsed = true; 487 } 488 break; 489 } 490 491 free (name); 492 if (!parsed) 493 return 1; 494 } 495 else if (just_section != NULL 496 && !adjust_to_section (just_section, &addr, dwfl)) 497 return 1; 498 499 Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); 500 501 if (show_functions) 502 { 503 /* First determine the function name. Use the DWARF information if 504 possible. */ 505 if (! print_dwarf_function (mod, addr) && !show_symbols) 506 puts (dwfl_module_addrname (mod, addr) ?: "??"); 507 } 508 509 if (show_symbols) 510 print_addrsym (mod, addr); 511 512 Dwfl_Line *line = dwfl_module_getsrc (mod, addr); 513 514 const char *src; 515 int lineno, linecol; 516 if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol, 517 NULL, NULL)) != NULL) 518 { 519 const char *comp_dir = ""; 520 const char *comp_dir_sep = ""; 521 522 if (only_basenames) 523 src = basename (src); 524 else if (use_comp_dir && src[0] != '/') 525 { 526 comp_dir = dwfl_line_comp_dir (line); 527 if (comp_dir != NULL) 528 comp_dir_sep = "/"; 529 } 530 531 if (linecol != 0) 532 printf ("%s%s%s:%d:%d", 533 comp_dir, comp_dir_sep, src, lineno, linecol); 534 else 535 printf ("%s%s%s:%d", 536 comp_dir, comp_dir_sep, src, lineno); 537 538 if (show_flags) 539 { 540 Dwarf_Addr bias; 541 Dwarf_Line *info = dwfl_dwarf_line (line, &bias); 542 assert (info != NULL); 543 544 inline void show (int (*get) (Dwarf_Line *, bool *), 545 const char *note) 546 { 547 bool flag; 548 if ((*get) (info, &flag) == 0 && flag) 549 fputs (note, stdout); 550 } 551 inline void show_int (int (*get) (Dwarf_Line *, unsigned int *), 552 const char *name) 553 { 554 unsigned int val; 555 if ((*get) (info, &val) == 0 && val != 0) 556 printf (" (%s %u)", name, val); 557 } 558 559 show (&dwarf_linebeginstatement, " (is_stmt)"); 560 show (&dwarf_lineblock, " (basic_block)"); 561 show (&dwarf_lineprologueend, " (prologue_end)"); 562 show (&dwarf_lineepiloguebegin, " (epilogue_begin)"); 563 show_int (&dwarf_lineisa, "isa"); 564 show_int (&dwarf_linediscriminator, "discriminator"); 565 } 566 putchar ('\n'); 567 } 568 else 569 puts ("??:0"); 570 571 return 0; 572 } 573 574 575 #include "debugpred.h" 576