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 : 20 : main (int argc, char *argv[])
120 : : {
121 : : int remaining;
122 : 20 : int result = 0;
123 : :
124 : : /* Make memory leak detection possible. */
125 : 20 : mtrace ();
126 : :
127 : : /* We use no threads here which can interfere with handling a stream. */
128 : 20 : (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
129 : :
130 : : /* Set locale. */
131 : 20 : (void) setlocale (LC_ALL, "");
132 : :
133 : : /* Make sure the message catalog can be found. */
134 : 20 : (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
135 : :
136 : : /* Initialize the message catalog. */
137 : 20 : (void) textdomain (PACKAGE_TARNAME);
138 : :
139 : : /* Parse and process arguments. This includes opening the modules. */
140 : 20 : argp_children[0].argp = dwfl_standard_argp ();
141 : 20 : argp_children[0].group = 1;
142 : 20 : Dwfl *dwfl = NULL;
143 : 20 : (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
144 [ - + ]: 20 : assert (dwfl != NULL);
145 : :
146 : : /* Now handle the addresses. In case none are given on the command
147 : : line, read from stdin. */
148 [ - + ]: 20 : 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 : 20 : free (buf);
164 : : }
165 : : else
166 : : {
167 : : do
168 : 89 : result = handle_address (argv[remaining], dwfl);
169 [ + + ]: 89 : while (++remaining < argc);
170 : : }
171 : :
172 : : return result;
173 : : }
174 : :
175 : :
176 : : /* Print the version information. */
177 : : static void
178 : 0 : print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
179 : : {
180 : 0 : fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
181 : 0 : fprintf (stream, gettext ("\
182 : : Copyright (C) %s Red Hat, Inc.\n\
183 : : This is free software; see the source for copying conditions. There is NO\n\
184 : : warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
185 : : "), "2012");
186 : 0 : fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
187 : 0 : }
188 : :
189 : :
190 : : /* Handle program arguments. */
191 : : static error_t
192 : 120 : parse_opt (int key, char *arg, struct argp_state *state)
193 : : {
194 [ + - - + : 120 : switch (key)
- + - -
+ ]
195 : : {
196 : : case ARGP_KEY_INIT:
197 : 20 : state->child_inputs[0] = state->input;
198 : 20 : break;
199 : :
200 : : case 'b':
201 : : case 'C':
202 : : case OPT_DEMANGLER:
203 : : /* Ignored for compatibility. */
204 : : break;
205 : :
206 : : case 's':
207 : 0 : only_basenames = true;
208 : 0 : break;
209 : :
210 : : case 'A':
211 : 0 : use_comp_dir = true;
212 : 0 : break;
213 : :
214 : : case 'f':
215 : 1 : show_functions = true;
216 : 1 : break;
217 : :
218 : : case 'F':
219 : 0 : show_flags = true;
220 : 0 : break;
221 : :
222 : : case 'S':
223 : 19 : show_symbols = true;
224 : 19 : break;
225 : :
226 : : case 'j':
227 : 0 : just_section = arg;
228 : 120 : break;
229 : :
230 : : default:
231 : : return ARGP_ERR_UNKNOWN;
232 : : }
233 : : return 0;
234 : : }
235 : :
236 : :
237 : : static bool
238 : 6 : print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
239 : : {
240 : 6 : Dwarf_Addr bias = 0;
241 : 6 : Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
242 : :
243 : : Dwarf_Die *scopes;
244 : 6 : int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
245 [ - + ]: 6 : if (nscopes <= 0)
246 : : return false;
247 : :
248 [ # # ]: 6 : for (int i = 0; i < nscopes; ++i)
249 [ # # # ]: 0 : switch (dwarf_tag (&scopes[i]))
250 : : {
251 : : case DW_TAG_subprogram:
252 : : {
253 : 0 : const char *name = dwarf_diename (&scopes[i]);
254 [ # # ]: 0 : if (name == NULL)
255 : : return false;
256 : 0 : puts (name);
257 : : return true;
258 : : }
259 : :
260 : : case DW_TAG_inlined_subroutine:
261 : : {
262 : 0 : const char *name = dwarf_diename (&scopes[i]);
263 [ # # ]: 0 : if (name == NULL)
264 : : return false;
265 : 0 : printf ("%s inlined", name);
266 : :
267 : : Dwarf_Files *files;
268 [ # # ]: 0 : if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
269 : : {
270 : : Dwarf_Attribute attr_mem;
271 : : Dwarf_Word val;
272 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr (&scopes[i],
273 : : DW_AT_call_file,
274 : : &attr_mem), &val) == 0)
275 : : {
276 : 0 : const char *file = dwarf_filesrc (files, val, NULL, NULL);
277 : 0 : unsigned int lineno = 0;
278 : 0 : unsigned int colno = 0;
279 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr (&scopes[i],
280 : : DW_AT_call_line,
281 : : &attr_mem), &val) == 0)
282 : 0 : lineno = val;
283 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr (&scopes[i],
284 : : DW_AT_call_column,
285 : : &attr_mem), &val) == 0)
286 : 0 : colno = val;
287 : :
288 : 0 : const char *comp_dir = "";
289 : 0 : const char *comp_dir_sep = "";
290 : :
291 [ # # ]: 0 : if (file == NULL)
292 : : file = "???";
293 [ # # ]: 0 : else if (only_basenames)
294 : 0 : file = basename (file);
295 [ # # ][ # # ]: 0 : else if (use_comp_dir && file[0] != '/')
296 : : {
297 : : const char *const *dirs;
298 : : size_t ndirs;
299 [ # # ]: 0 : if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0
300 [ # # ]: 0 : && dirs[0] != NULL)
301 : : {
302 : 0 : comp_dir = dirs[0];
303 : 0 : comp_dir_sep = "/";
304 : : }
305 : : }
306 : :
307 [ # # ]: 0 : if (lineno == 0)
308 : 0 : printf (" from %s%s%s",
309 : : comp_dir, comp_dir_sep, file);
310 [ # # ]: 0 : else if (colno == 0)
311 : 0 : printf (" at %s%s%s:%u",
312 : : comp_dir, comp_dir_sep, file, lineno);
313 : : else
314 : 0 : printf (" at %s%s%s:%u:%u",
315 : : comp_dir, comp_dir_sep, file, lineno, colno);
316 : : }
317 : : }
318 : 0 : printf (" in ");
319 : 0 : continue;
320 : : }
321 : : }
322 : :
323 : : return false;
324 : : }
325 : :
326 : : static void
327 : 83 : print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
328 : : {
329 : : GElf_Sym s;
330 : : GElf_Word shndx;
331 : 83 : const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
332 [ + + ]: 83 : if (name == NULL)
333 : : {
334 : : /* No symbol name. Get a section name instead. */
335 : 7 : int i = dwfl_module_relocate_address (mod, &addr);
336 [ + - ]: 7 : if (i >= 0)
337 : 7 : name = dwfl_module_relocation_info (mod, i, NULL);
338 [ - + ]: 7 : if (name == NULL)
339 : 0 : puts ("??");
340 : : else
341 : 7 : printf ("(%s)+%#" PRIx64 "\n", name, addr);
342 : : }
343 [ + + ]: 76 : else if (addr == s.st_value)
344 : 25 : puts (name);
345 : : else
346 : 51 : printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value);
347 : 83 : }
348 : :
349 : : static int
350 : 0 : see_one_module (Dwfl_Module *mod,
351 : : void **userdata __attribute__ ((unused)),
352 : : const char *name __attribute__ ((unused)),
353 : : Dwarf_Addr start __attribute__ ((unused)),
354 : : void *arg)
355 : : {
356 : 0 : Dwfl_Module **result = arg;
357 [ # # ]: 0 : if (*result != NULL)
358 : : return DWARF_CB_ABORT;
359 : 0 : *result = mod;
360 : 0 : return DWARF_CB_OK;
361 : : }
362 : :
363 : : static int
364 : 0 : find_symbol (Dwfl_Module *mod,
365 : : void **userdata __attribute__ ((unused)),
366 : : const char *name __attribute__ ((unused)),
367 : : Dwarf_Addr start __attribute__ ((unused)),
368 : : void *arg)
369 : : {
370 : 0 : const char *looking_for = ((void **) arg)[0];
371 : 0 : GElf_Sym *symbol = ((void **) arg)[1];
372 : :
373 : 0 : int n = dwfl_module_getsymtab (mod);
374 [ # # ]: 0 : for (int i = 1; i < n; ++i)
375 : : {
376 : 0 : const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL);
377 [ # # ][ # # ]: 0 : if (symbol_name == NULL || symbol_name[0] == '\0')
378 : 0 : continue;
379 [ # # ]: 0 : switch (GELF_ST_TYPE (symbol->st_info))
380 : : {
381 : : case STT_SECTION:
382 : : case STT_FILE:
383 : : case STT_TLS:
384 : : break;
385 : : default:
386 [ # # ]: 0 : if (!strcmp (symbol_name, looking_for))
387 : : {
388 : 0 : ((void **) arg)[0] = NULL;
389 : 0 : return DWARF_CB_ABORT;
390 : : }
391 : : }
392 : : }
393 : :
394 : : return DWARF_CB_OK;
395 : : }
396 : :
397 : : static bool
398 : 0 : adjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl)
399 : : {
400 : : /* It was (section)+offset. This makes sense if there is
401 : : only one module to look in for a section. */
402 : 0 : Dwfl_Module *mod = NULL;
403 [ # # ]: 0 : if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
404 [ # # ]: 0 : || mod == NULL)
405 : 0 : error (EXIT_FAILURE, 0, gettext ("Section syntax requires"
406 : : " exactly one module"));
407 : :
408 : 0 : int nscn = dwfl_module_relocations (mod);
409 [ # # ]: 0 : for (int i = 0; i < nscn; ++i)
410 : : {
411 : : GElf_Word shndx;
412 : 0 : const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
413 [ # # ]: 0 : if (unlikely (scn == NULL))
414 : : break;
415 [ # # ]: 0 : if (!strcmp (scn, name))
416 : : {
417 : : /* Found the section. */
418 : : GElf_Shdr shdr_mem;
419 : : GElf_Addr shdr_bias;
420 : 0 : GElf_Shdr *shdr = gelf_getshdr
421 : 0 : (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
422 : : &shdr_mem);
423 [ # # ]: 0 : if (unlikely (shdr == NULL))
424 : : break;
425 : :
426 [ # # ]: 0 : if (*addr >= shdr->sh_size)
427 : : error (0, 0,
428 : 0 : gettext ("offset %#" PRIxMAX " lies outside"
429 : : " section '%s'"),
430 : : *addr, scn);
431 : :
432 : 0 : *addr += shdr->sh_addr + shdr_bias;
433 : : return true;
434 : : }
435 : : }
436 : :
437 : : return false;
438 : : }
439 : :
440 : : static int
441 : 89 : handle_address (const char *string, Dwfl *dwfl)
442 : : {
443 : : char *endp;
444 : 89 : uintmax_t addr = strtoumax (string, &endp, 0);
445 [ - + ]: 89 : if (endp == string)
446 : : {
447 : 0 : bool parsed = false;
448 : : int i, j;
449 : 0 : char *name = NULL;
450 [ # # ]: 0 : if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2
451 [ # # ]: 0 : && string[i] == '\0')
452 : 0 : parsed = adjust_to_section (name, &addr, dwfl);
453 [ # # # ]: 0 : switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j))
454 : : {
455 : : default:
456 : : break;
457 : : case 1:
458 : 0 : addr = 0;
459 : 0 : j = i;
460 : : case 2:
461 [ # # ]: 0 : if (string[j] != '\0')
462 : : break;
463 : :
464 : : /* It was symbol[+offset]. */
465 : : GElf_Sym sym;
466 : 0 : void *arg[2] = { name, &sym };
467 : 0 : (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
468 [ # # ]: 0 : if (arg[0] != NULL)
469 : 0 : error (0, 0, gettext ("cannot find symbol '%s'"), name);
470 : : else
471 : : {
472 [ # # ][ # # ]: 0 : if (sym.st_size != 0 && addr >= sym.st_size)
473 : 0 : error (0, 0,
474 : 0 : gettext ("offset %#" PRIxMAX " lies outside"
475 : : " contents of '%s'"),
476 : : addr, name);
477 : 0 : addr += sym.st_value;
478 : 0 : parsed = true;
479 : : }
480 : : break;
481 : : }
482 : :
483 : 0 : free (name);
484 [ # # ]: 0 : if (!parsed)
485 : : return 1;
486 : : }
487 [ - + ]: 89 : else if (just_section != NULL
488 [ # # ]: 0 : && !adjust_to_section (just_section, &addr, dwfl))
489 : : return 1;
490 : :
491 : 89 : Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
492 : :
493 [ + + ]: 89 : if (show_functions)
494 : : {
495 : : /* First determine the function name. Use the DWARF information if
496 : : possible. */
497 [ + - ][ + - ]: 6 : if (! print_dwarf_function (mod, addr) && !show_symbols)
498 [ + + ]: 6 : puts (dwfl_module_addrname (mod, addr) ?: "??");
499 : : }
500 : :
501 [ + + ]: 89 : if (show_symbols)
502 : 83 : print_addrsym (mod, addr);
503 : :
504 : 89 : Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
505 : :
506 : : const char *src;
507 : : int lineno, linecol;
508 [ + + ][ + - ]: 89 : if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
509 : : NULL, NULL)) != NULL)
510 : : {
511 : 24 : const char *comp_dir = "";
512 : 24 : const char *comp_dir_sep = "";
513 : :
514 [ - + ]: 24 : if (only_basenames)
515 : 0 : src = basename (src);
516 [ - + ][ # # ]: 24 : else if (use_comp_dir && src[0] != '/')
517 : : {
518 : 0 : comp_dir = dwfl_line_comp_dir (line);
519 [ # # ]: 0 : if (comp_dir != NULL)
520 : 0 : comp_dir_sep = "/";
521 : : }
522 : :
523 [ - + ]: 24 : if (linecol != 0)
524 : 0 : printf ("%s%s%s:%d:%d",
525 : : comp_dir, comp_dir_sep, src, lineno, linecol);
526 : : else
527 : 24 : printf ("%s%s%s:%d",
528 : : comp_dir, comp_dir_sep, src, lineno);
529 : :
530 [ - + ]: 24 : if (show_flags)
531 : : {
532 : : Dwarf_Addr bias;
533 : 0 : Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
534 [ # # ]: 0 : assert (info != NULL);
535 : :
536 : 0 : inline void show (int (*get) (Dwarf_Line *, bool *),
537 : : const char *note)
538 : : {
539 : : bool flag;
540 [ # # ][ # # ]: 0 : if ((*get) (info, &flag) == 0 && flag)
541 : 0 : fputs (note, stdout);
542 : 0 : }
543 : 0 : inline void show_int (int (*get) (Dwarf_Line *, unsigned int *),
544 : : const char *name)
545 : : {
546 : : unsigned int val;
547 [ # # ][ # # ]: 0 : if ((*get) (info, &val) == 0 && val != 0)
548 : 0 : printf (" (%s %u)", name, val);
549 : 0 : }
550 : :
551 : 0 : show (&dwarf_linebeginstatement, " (is_stmt)");
552 : 0 : show (&dwarf_lineblock, " (basic_block)");
553 : 0 : show (&dwarf_lineprologueend, " (prologue_end)");
554 : 0 : show (&dwarf_lineepiloguebegin, " (epilogue_begin)");
555 : 0 : show_int (&dwarf_lineisa, "isa");
556 : 0 : show_int (&dwarf_linediscriminator, "discriminator");
557 : : }
558 : : putchar ('\n');
559 : : }
560 : : else
561 : 89 : puts ("??:0");
562 : :
563 : : return 0;
564 : : }
565 : :
566 : :
567 : 0 : #include "debugpred.h"
|