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@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
main(int argc,char * argv[])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
print_version(FILE * stream,struct argp_state * state)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
parse_opt(int key,char * arg,struct argp_state * state)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
print_dwarf_function(Dwfl_Module * mod,Dwarf_Addr addr)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
print_addrsym(Dwfl_Module * mod,GElf_Addr addr)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
see_one_module(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void * arg)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
find_symbol(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void * arg)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
adjust_to_section(const char * name,uintmax_t * addr,Dwfl * dwfl)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
handle_address(const char * string,Dwfl * dwfl)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