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