1 /* Locate source files and line information for given addresses 2 Copyright (C) 2005, 2006, 2007, 2008 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 50 /* Name and version of program. */ 51 static void print_version (FILE *stream, struct argp_state *state); 52 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; 53 54 /* Bug report address. */ 55 const char *argp_program_bug_address = PACKAGE_BUGREPORT; 56 57 58 /* Values for the parameters which have no short form. */ 59 #define OPT_DEMANGLER 0x100 60 61 /* Definitions of arguments for argp functions. */ 62 static const struct argp_option options[] = 63 { 64 { NULL, 0, NULL, 0, N_("Output selection options:"), 2 }, 65 { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, 66 { "absolute", 'A', NULL, 0, 67 N_("Show absolute file names using compilation directory"), 0 }, 68 { "functions", 'f', NULL, 0, N_("Also show function names"), 0 }, 69 { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 }, 70 71 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 72 /* Unsupported options. */ 73 { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 }, 74 { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 }, 75 { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 }, 76 { NULL, 0, NULL, 0, NULL, 0 } 77 }; 78 79 /* Short description of program. */ 80 static const char doc[] = N_("\ 81 Locate source files and line information for ADDRs (in a.out by default)."); 82 83 /* Strings for arguments in help texts. */ 84 static const char args_doc[] = N_("[ADDR...]"); 85 86 /* Prototype for option handler. */ 87 static error_t parse_opt (int key, char *arg, struct argp_state *state); 88 89 static struct argp_child argp_children[2]; /* [0] is set in main. */ 90 91 /* Data structure to communicate with argp functions. */ 92 static const struct argp argp = 93 { 94 options, parse_opt, args_doc, doc, argp_children, NULL, NULL 95 }; 96 97 98 /* Handle ADDR. */ 99 static int handle_address (const char *addr, Dwfl *dwfl); 100 101 102 /* True if only base names of files should be shown. */ 103 static bool only_basenames; 104 105 /* True if absolute file names based on DW_AT_comp_dir should be shown. */ 106 static bool use_comp_dir; 107 108 /* True if function names should be shown. */ 109 static bool show_functions; 110 111 /* True if ELF symbol or section info should be shown. */ 112 static bool show_symbols; 113 114 115 int 116 main (int argc, char *argv[]) 117 { 118 int remaining; 119 int result = 0; 120 121 /* Make memory leak detection possible. */ 122 mtrace (); 123 124 /* We use no threads here which can interfere with handling a stream. */ 125 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 126 127 /* Set locale. */ 128 (void) setlocale (LC_ALL, ""); 129 130 /* Make sure the message catalog can be found. */ 131 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 132 133 /* Initialize the message catalog. */ 134 (void) textdomain (PACKAGE_TARNAME); 135 136 /* Parse and process arguments. This includes opening the modules. */ 137 argp_children[0].argp = dwfl_standard_argp (); 138 argp_children[0].group = 1; 139 Dwfl *dwfl = NULL; 140 (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); 141 assert (dwfl != NULL); 142 143 /* Now handle the addresses. In case none are given on the command 144 line, read from stdin. */ 145 if (remaining == argc) 146 { 147 /* We use no threads here which can interfere with handling a stream. */ 148 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 149 150 char *buf = NULL; 151 size_t len = 0; 152 while (!feof_unlocked (stdin)) 153 { 154 if (getline (&buf, &len, stdin) < 0) 155 break; 156 157 result = handle_address (buf, dwfl); 158 } 159 160 free (buf); 161 } 162 else 163 { 164 do 165 result = handle_address (argv[remaining], dwfl); 166 while (++remaining < argc); 167 } 168 169 return result; 170 } 171 172 173 /* Print the version information. */ 174 static void 175 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) 176 { 177 fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); 178 fprintf (stream, gettext ("\ 179 Copyright (C) %s Red Hat, Inc.\n\ 180 This is free software; see the source for copying conditions. There is NO\n\ 181 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ 182 "), "2008"); 183 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); 184 } 185 186 187 /* Handle program arguments. */ 188 static error_t 189 parse_opt (int key, char *arg __attribute__ ((unused)), 190 struct argp_state *state) 191 { 192 switch (key) 193 { 194 case ARGP_KEY_INIT: 195 state->child_inputs[0] = state->input; 196 break; 197 198 case 'b': 199 case 'C': 200 case OPT_DEMANGLER: 201 /* Ignored for compatibility. */ 202 break; 203 204 case 's': 205 only_basenames = true; 206 break; 207 208 case 'A': 209 use_comp_dir = true; 210 break; 211 212 case 'f': 213 show_functions = true; 214 break; 215 216 case 'S': 217 show_symbols = true; 218 break; 219 220 default: 221 return ARGP_ERR_UNKNOWN; 222 } 223 return 0; 224 } 225 226 227 static bool 228 print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) 229 { 230 Dwarf_Addr bias = 0; 231 Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias); 232 233 Dwarf_Die *scopes; 234 int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes); 235 if (nscopes <= 0) 236 return false; 237 238 for (int i = 0; i < nscopes; ++i) 239 switch (dwarf_tag (&scopes[i])) 240 { 241 case DW_TAG_subprogram: 242 { 243 const char *name = dwarf_diename (&scopes[i]); 244 if (name == NULL) 245 return false; 246 puts (name); 247 return true; 248 } 249 250 case DW_TAG_inlined_subroutine: 251 { 252 const char *name = dwarf_diename (&scopes[i]); 253 if (name == NULL) 254 return false; 255 printf ("%s inlined", name); 256 257 Dwarf_Files *files; 258 if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) 259 { 260 Dwarf_Attribute attr_mem; 261 Dwarf_Word val; 262 if (dwarf_formudata (dwarf_attr (&scopes[i], 263 DW_AT_call_file, 264 &attr_mem), &val) == 0) 265 { 266 const char *file = dwarf_filesrc (files, val, NULL, NULL); 267 unsigned int lineno = 0; 268 unsigned int colno = 0; 269 if (dwarf_formudata (dwarf_attr (&scopes[i], 270 DW_AT_call_line, 271 &attr_mem), &val) == 0) 272 lineno = val; 273 if (dwarf_formudata (dwarf_attr (&scopes[i], 274 DW_AT_call_column, 275 &attr_mem), &val) == 0) 276 colno = val; 277 if (lineno == 0) 278 { 279 if (file != NULL) 280 printf (" from %s", file); 281 } 282 else if (colno == 0) 283 printf (" at %s:%u", file, lineno); 284 else 285 printf (" at %s:%u:%u", file, lineno, colno); 286 } 287 } 288 printf (" in "); 289 continue; 290 } 291 } 292 293 return false; 294 } 295 296 static void 297 print_addrsym (Dwfl_Module *mod, GElf_Addr addr) 298 { 299 GElf_Sym s; 300 GElf_Word shndx; 301 const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx); 302 if (name == NULL) 303 { 304 /* No symbol name. Get a section name instead. */ 305 int i = dwfl_module_relocate_address (mod, &addr); 306 if (i >= 0) 307 name = dwfl_module_relocation_info (mod, i, NULL); 308 if (name == NULL) 309 puts ("??"); 310 else 311 printf ("(%s)+%#" PRIx64 "\n", name, addr); 312 } 313 else if (addr == s.st_value) 314 puts (name); 315 else 316 printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value); 317 } 318 319 static int 320 see_one_module (Dwfl_Module *mod, 321 void **userdata __attribute__ ((unused)), 322 const char *name __attribute__ ((unused)), 323 Dwarf_Addr start __attribute__ ((unused)), 324 void *arg) 325 { 326 Dwfl_Module **result = arg; 327 if (*result != NULL) 328 return DWARF_CB_ABORT; 329 *result = mod; 330 return DWARF_CB_OK; 331 } 332 333 static int 334 find_symbol (Dwfl_Module *mod, 335 void **userdata __attribute__ ((unused)), 336 const char *name __attribute__ ((unused)), 337 Dwarf_Addr start __attribute__ ((unused)), 338 void *arg) 339 { 340 const char *looking_for = ((void **) arg)[0]; 341 GElf_Sym *symbol = ((void **) arg)[1]; 342 343 int n = dwfl_module_getsymtab (mod); 344 for (int i = 1; i < n; ++i) 345 { 346 const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL); 347 if (symbol_name == NULL) 348 continue; 349 switch (GELF_ST_TYPE (symbol->st_info)) 350 { 351 case STT_SECTION: 352 case STT_FILE: 353 case STT_TLS: 354 break; 355 default: 356 if (!strcmp (symbol_name, looking_for)) 357 { 358 ((void **) arg)[0] = NULL; 359 return DWARF_CB_ABORT; 360 } 361 } 362 } 363 364 return DWARF_CB_OK; 365 } 366 367 static int 368 handle_address (const char *string, Dwfl *dwfl) 369 { 370 char *endp; 371 uintmax_t addr = strtoumax (string, &endp, 0); 372 if (endp == string) 373 { 374 bool parsed = false; 375 int n; 376 char *name = NULL; 377 if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &n) == 2 378 && string[n] == '\0') 379 { 380 /* It was (section)+offset. This makes sense if there is 381 only one module to look in for a section. */ 382 Dwfl_Module *mod = NULL; 383 if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0 384 || mod == NULL) 385 error (EXIT_FAILURE, 0, gettext ("Section syntax requires" 386 " exactly one module")); 387 388 int nscn = dwfl_module_relocations (mod); 389 for (int i = 0; i < nscn; ++i) 390 { 391 GElf_Word shndx; 392 const char *scn = dwfl_module_relocation_info (mod, i, &shndx); 393 if (unlikely (scn == NULL)) 394 break; 395 if (!strcmp (scn, name)) 396 { 397 /* Found the section. */ 398 GElf_Shdr shdr_mem; 399 GElf_Addr shdr_bias; 400 GElf_Shdr *shdr = gelf_getshdr 401 (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx), 402 &shdr_mem); 403 if (unlikely (shdr == NULL)) 404 break; 405 406 if (addr >= shdr->sh_size) 407 error (0, 0, 408 gettext ("offset %#" PRIxMAX " lies outside" 409 " section '%s'"), 410 addr, scn); 411 412 addr += shdr->sh_addr + shdr_bias; 413 parsed = true; 414 break; 415 } 416 } 417 } 418 else if (sscanf (string, "%m[^-+]%" PRIiMAX "%n", &name, &addr, &n) == 2 419 && string[n] == '\0') 420 { 421 /* It was symbol+offset. */ 422 GElf_Sym sym; 423 void *arg[2] = { name, &sym }; 424 (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0); 425 if (arg[0] != NULL) 426 error (0, 0, gettext ("cannot find symbol '%s'"), name); 427 else 428 { 429 if (sym.st_size != 0 && addr >= sym.st_size) 430 error (0, 0, 431 gettext ("offset %#" PRIxMAX " lies outside" 432 " contents of '%s'"), 433 addr, name); 434 addr += sym.st_value; 435 parsed = true; 436 } 437 } 438 439 free (name); 440 if (!parsed) 441 return 1; 442 } 443 444 Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); 445 446 if (show_functions) 447 { 448 /* First determine the function name. Use the DWARF information if 449 possible. */ 450 if (! print_dwarf_function (mod, addr) && !show_symbols) 451 puts (dwfl_module_addrname (mod, addr) ?: "??"); 452 } 453 454 if (show_symbols) 455 print_addrsym (mod, addr); 456 457 Dwfl_Line *line = dwfl_module_getsrc (mod, addr); 458 459 const char *src; 460 int lineno, linecol; 461 if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol, 462 NULL, NULL)) != NULL) 463 { 464 const char *comp_dir = ""; 465 const char *comp_dir_sep = ""; 466 467 if (only_basenames) 468 src = basename (src); 469 else if (use_comp_dir && src[0] != '/') 470 { 471 comp_dir = dwfl_line_comp_dir (line); 472 if (comp_dir != NULL) 473 comp_dir_sep = "/"; 474 } 475 476 if (linecol != 0) 477 printf ("%s%s%s:%d:%d\n", 478 comp_dir, comp_dir_sep, src, lineno, linecol); 479 else 480 printf ("%s%s%s:%d\n", 481 comp_dir, comp_dir_sep, src, lineno); 482 } 483 else 484 puts ("??:0"); 485 486 return 0; 487 } 488 489 490 #include "debugpred.h" 491