Branch data Line data Source code
1 : : /* Locate source files and line information for given addresses
2 : : Copyright (C) 2005-2010, 2012, 2013, 2015 Red Hat, Inc.
3 : : Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
5 : : Written by Ulrich Drepper <drepper@redhat.com>, 2005.
6 : :
7 : : This file is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3 of the License, or
10 : : (at your option) any later version.
11 : :
12 : : elfutils is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : GNU General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 : :
20 : : #ifdef HAVE_CONFIG_H
21 : : # include <config.h>
22 : : #endif
23 : :
24 : : #include <argp.h>
25 : : #include <assert.h>
26 : : #include <errno.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 <stdbool.h>
34 : : #include <stdio.h>
35 : : #include <stdio_ext.h>
36 : : #include <stdlib.h>
37 : : #include <string.h>
38 : : #include <unistd.h>
39 : :
40 : : #include <system.h>
41 : : #include <printversion.h>
42 : :
43 : :
44 : : /* Name and version of program. */
45 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
46 : :
47 : : /* Bug report address. */
48 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
49 : :
50 : :
51 : : /* Values for the parameters which have no short form. */
52 : : #define OPT_DEMANGLER 0x100
53 : : #define OPT_PRETTY 0x101 /* 'p' is already used to select the process. */
54 : : #define OPT_RELATIVE 0x102 /* 'r' is something else in binutils addr2line. */
55 : :
56 : : /* Definitions of arguments for argp functions. */
57 : : static const struct argp_option options[] =
58 : : {
59 : : { NULL, 0, NULL, 0, N_("Input format options:"), 2 },
60 : : { "section", 'j', "NAME", 0,
61 : : N_("Treat addresses as offsets relative to NAME section."), 0 },
62 : :
63 : : { NULL, 0, NULL, 0, N_("Output format options:"), 3 },
64 : : { "addresses", 'a', NULL, 0, N_("Print address before each entry"), 0 },
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 (default)"), 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 : : { "symbols-sections", 'x', NULL, 0, N_("Also show symbol and the section names"), 0 },
71 : : { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 },
72 : : { "inlines", 'i', NULL, 0,
73 : : N_("Show all source locations that caused inline expansion of subroutines at the address."),
74 : : 0 },
75 : : { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL,
76 : : N_("Show demangled symbols (ARG is always ignored)"), 0 },
77 : : { "pretty-print", OPT_PRETTY, NULL, 0,
78 : : N_("Print all information on one line, and indent inlines"), 0 },
79 : : { "relative", OPT_RELATIVE, NULL, 0,
80 : : N_("Show relative file names without compilation directory"), 0 },
81 : :
82 : : { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
83 : : /* Unsupported options. */
84 : : { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
85 : : { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
86 : : { NULL, 0, NULL, 0, NULL, 0 }
87 : : };
88 : :
89 : : /* Short description of program. */
90 : : static const char doc[] = N_("\
91 : : Locate source files and line information for ADDRs (in a.out by default).");
92 : :
93 : : /* Strings for arguments in help texts. */
94 : : static const char args_doc[] = N_("[ADDR...]");
95 : :
96 : : /* Prototype for option handler. */
97 : : static error_t parse_opt (int key, char *arg, struct argp_state *state);
98 : :
99 : : static struct argp_child argp_children[2]; /* [0] is set in main. */
100 : :
101 : : /* Data structure to communicate with argp functions. */
102 : : static const struct argp argp =
103 : : {
104 : : options, parse_opt, args_doc, doc, argp_children, NULL, NULL
105 : : };
106 : :
107 : :
108 : : /* Handle ADDR. */
109 : : static int handle_address (const char *addr, Dwfl *dwfl);
110 : :
111 : : /* True when we should print the address for each entry. */
112 : : static bool print_addresses;
113 : :
114 : : /* True if only base names of files should be shown. */
115 : : static bool only_basenames;
116 : :
117 : : /* True if absolute file names based on DW_AT_comp_dir should be shown. */
118 : : static bool use_comp_dir = true;
119 : :
120 : : /* True if line flags should be shown. */
121 : : static bool show_flags;
122 : :
123 : : /* True if function names should be shown. */
124 : : static bool show_functions;
125 : :
126 : : /* True if ELF symbol or section info should be shown. */
127 : : static bool show_symbols;
128 : :
129 : : /* True if section associated with a symbol address should be shown. */
130 : : static bool show_symbol_sections;
131 : :
132 : : /* If non-null, take address parameters as relative to named section. */
133 : : static const char *just_section;
134 : :
135 : : /* True if all inlined subroutines of the current address should be shown. */
136 : : static bool show_inlines;
137 : :
138 : : /* True if all names need to be demangled. */
139 : : static bool demangle;
140 : :
141 : : /* True if all information should be printed on one line. */
142 : : static bool pretty;
143 : :
144 : : #ifdef USE_DEMANGLE
145 : : static size_t demangle_buffer_len = 0;
146 : : static char *demangle_buffer = NULL;
147 : : #endif
148 : :
149 : : int
150 : 52 : main (int argc, char *argv[])
151 : : {
152 : 52 : int remaining;
153 : 52 : int result = 0;
154 : :
155 : : /* We use no threads here which can interfere with handling a stream. */
156 : 52 : (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
157 : :
158 : : /* Set locale. */
159 : 52 : (void) setlocale (LC_ALL, "");
160 : :
161 : : /* Make sure the message catalog can be found. */
162 : 52 : (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
163 : :
164 : : /* Initialize the message catalog. */
165 : 52 : (void) textdomain (PACKAGE_TARNAME);
166 : :
167 : : /* Parse and process arguments. This includes opening the modules. */
168 : 52 : argp_children[0].argp = dwfl_standard_argp ();
169 : 52 : argp_children[0].group = 1;
170 : 52 : Dwfl *dwfl = NULL;
171 : 52 : (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
172 [ - + ]: 52 : assert (dwfl != NULL);
173 : :
174 : : /* Now handle the addresses. In case none are given on the command
175 : : line, read from stdin. */
176 [ + + ]: 52 : if (remaining == argc)
177 : : {
178 : : /* We use no threads here which can interfere with handling a stream. */
179 : 4 : (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
180 : :
181 : 4 : char *buf = NULL;
182 : 4 : size_t len = 0;
183 : 4 : ssize_t chars;
184 [ + + ]: 22 : while (!feof_unlocked (stdin))
185 : : {
186 [ + + ]: 20 : if ((chars = getline (&buf, &len, stdin)) < 0)
187 : : break;
188 : :
189 [ + + ]: 18 : if (buf[chars - 1] == '\n')
190 : 16 : buf[chars - 1] = '\0';
191 : :
192 : 18 : result = handle_address (buf, dwfl);
193 : 18 : fflush (stdout);
194 : : }
195 : :
196 : 4 : free (buf);
197 : : }
198 : : else
199 : : {
200 : 193 : do
201 : 193 : result = handle_address (argv[remaining], dwfl);
202 [ + + ]: 193 : while (++remaining < argc);
203 : : }
204 : :
205 : 52 : dwfl_end (dwfl);
206 : :
207 : : #ifdef USE_DEMANGLE
208 : 52 : free (demangle_buffer);
209 : : #endif
210 : :
211 : 52 : return result;
212 : : }
213 : :
214 : :
215 : : /* Handle program arguments. */
216 : : static error_t
217 : 328 : parse_opt (int key, char *arg, struct argp_state *state)
218 : : {
219 [ + + + - : 328 : switch (key)
- - + - +
+ - + +
+ ]
220 : : {
221 : 52 : case ARGP_KEY_INIT:
222 : 52 : state->child_inputs[0] = state->input;
223 : 52 : break;
224 : :
225 : 6 : case 'a':
226 : 6 : print_addresses = true;
227 : 6 : break;
228 : :
229 : 1 : case 'b':
230 : : case 'C':
231 : : case OPT_DEMANGLER:
232 : 1 : demangle = true;
233 : 1 : break;
234 : :
235 : 0 : case 's':
236 : 0 : only_basenames = true;
237 : 0 : break;
238 : :
239 : 0 : case 'A':
240 : 0 : use_comp_dir = true;
241 : 0 : break;
242 : :
243 : 0 : case OPT_RELATIVE:
244 : 0 : use_comp_dir = false;
245 : 0 : break;
246 : :
247 : 14 : case 'f':
248 : 14 : show_functions = true;
249 : 14 : break;
250 : :
251 : 0 : case 'F':
252 : 0 : show_flags = true;
253 : 0 : break;
254 : :
255 : 22 : case 'S':
256 : 22 : show_symbols = true;
257 : 22 : break;
258 : :
259 : 2 : case 'x':
260 : 2 : show_symbols = true;
261 : 2 : show_symbol_sections = true;
262 : 2 : break;
263 : :
264 : 0 : case 'j':
265 : 0 : just_section = arg;
266 : 0 : break;
267 : :
268 : 20 : case 'i':
269 : 20 : show_inlines = true;
270 : 20 : break;
271 : :
272 : 3 : case OPT_PRETTY:
273 : 3 : pretty = true;
274 : 3 : break;
275 : :
276 : : default:
277 : : return ARGP_ERR_UNKNOWN;
278 : : }
279 : : return 0;
280 : : }
281 : :
282 : : static const char *
283 : 249 : symname (const char *name)
284 : : {
285 : : #ifdef USE_DEMANGLE
286 : : // Require GNU v3 ABI by the "_Z" prefix.
287 [ + + + + : 249 : if (demangle && name[0] == '_' && name[1] == 'Z')
+ - ]
288 : : {
289 : 11 : int status = -1;
290 : 11 : char *dsymname = __cxa_demangle (name, demangle_buffer,
291 : : &demangle_buffer_len, &status);
292 [ + - ]: 11 : if (status == 0)
293 : 11 : name = demangle_buffer = dsymname;
294 : : }
295 : : #endif
296 : 249 : return name;
297 : : }
298 : :
299 : : static const char *
300 : 137 : get_diename (Dwarf_Die *die)
301 : : {
302 : 137 : Dwarf_Attribute attr;
303 : 137 : const char *name;
304 : :
305 [ + + ]: 249 : name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name,
306 : : &attr)
307 : 112 : ?: dwarf_attr_integrate (die, DW_AT_linkage_name,
308 : : &attr));
309 : :
310 [ + + ]: 137 : if (name == NULL)
311 [ - + ]: 108 : name = dwarf_diename (die) ?: "??";
312 : :
313 : 137 : return name;
314 : : }
315 : :
316 : : static bool
317 : 101 : print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
318 : : {
319 : 101 : Dwarf_Addr bias = 0;
320 : 101 : Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
321 : :
322 : 101 : Dwarf_Die *scopes;
323 : 101 : int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
324 [ + + ]: 101 : if (nscopes <= 0)
325 : : return false;
326 : :
327 : 135 : bool res = false;
328 [ + + ]: 135 : for (int i = 0; i < nscopes; ++i)
329 [ + + + ]: 115 : switch (dwarf_tag (&scopes[i]))
330 : : {
331 : 63 : case DW_TAG_subprogram:
332 : : {
333 : 63 : const char *name = get_diename (&scopes[i]);
334 [ - + ]: 63 : if (name == NULL)
335 : 0 : goto done;
336 [ + + ]: 63 : printf ("%s%c", symname (name), pretty ? ' ' : '\n');
337 : 63 : res = true;
338 : 63 : goto done;
339 : : }
340 : :
341 : 32 : case DW_TAG_inlined_subroutine:
342 : : {
343 : 32 : const char *name = get_diename (&scopes[i]);
344 [ - + ]: 32 : if (name == NULL)
345 : 12 : goto done;
346 : :
347 : : /* When using --pretty-print we only show inlines on their
348 : : own line. Just print the first subroutine name. */
349 [ + + ]: 32 : if (pretty)
350 : : {
351 : 12 : printf ("%s ", symname (name));
352 : 12 : res = true;
353 : 12 : goto done;
354 : : }
355 : : else
356 : 20 : printf ("%s inlined", symname (name));
357 : :
358 : 20 : Dwarf_Files *files;
359 [ + - ]: 20 : if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
360 : : {
361 : 20 : Dwarf_Attribute attr_mem;
362 : 20 : Dwarf_Word val;
363 [ + - ]: 20 : if (dwarf_formudata (dwarf_attr (&scopes[i],
364 : : DW_AT_call_file,
365 : : &attr_mem), &val) == 0)
366 : : {
367 : 20 : const char *file = dwarf_filesrc (files, val, NULL, NULL);
368 : 20 : unsigned int lineno = 0;
369 : 20 : unsigned int colno = 0;
370 [ + - ]: 20 : if (dwarf_formudata (dwarf_attr (&scopes[i],
371 : : DW_AT_call_line,
372 : : &attr_mem), &val) == 0)
373 : 20 : lineno = val;
374 [ - + ]: 20 : if (dwarf_formudata (dwarf_attr (&scopes[i],
375 : : DW_AT_call_column,
376 : : &attr_mem), &val) == 0)
377 : 0 : colno = val;
378 : :
379 : 20 : const char *comp_dir = "";
380 : 20 : const char *comp_dir_sep = "";
381 : :
382 [ + - ]: 20 : if (file == NULL)
383 : : file = "???";
384 [ - + ]: 20 : else if (only_basenames)
385 : 0 : file = basename (file);
386 [ + - - + ]: 20 : else if (use_comp_dir && file[0] != '/')
387 : : {
388 : 0 : const char *const *dirs;
389 : 0 : size_t ndirs;
390 [ # # ]: 0 : if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0
391 [ # # ]: 0 : && dirs[0] != NULL)
392 : : {
393 : 0 : comp_dir = dirs[0];
394 : 0 : comp_dir_sep = "/";
395 : : }
396 : : }
397 : :
398 [ - + ]: 20 : if (lineno == 0)
399 : 0 : printf (" from %s%s%s",
400 : : comp_dir, comp_dir_sep, file);
401 [ + - ]: 20 : else if (colno == 0)
402 : 20 : printf (" at %s%s%s:%u",
403 : : comp_dir, comp_dir_sep, file, lineno);
404 : : else
405 : 20 : printf (" at %s%s%s:%u:%u",
406 : : comp_dir, comp_dir_sep, file, lineno, colno);
407 : : }
408 : : }
409 : 20 : printf (" in ");
410 : 20 : continue;
411 : : }
412 : : }
413 : :
414 : 20 : done:
415 : 95 : free (scopes);
416 : 95 : return res;
417 : : }
418 : :
419 : : static void
420 : 96 : print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
421 : : {
422 : 96 : GElf_Sym s;
423 : 96 : GElf_Off off;
424 : 96 : const char *name = dwfl_module_addrinfo (mod, addr, &off, &s,
425 : : NULL, NULL, NULL);
426 [ + + ]: 96 : if (name == NULL)
427 : : {
428 : : /* No symbol name. Get a section name instead. */
429 : 9 : int i = dwfl_module_relocate_address (mod, &addr);
430 [ + - ]: 9 : if (i >= 0)
431 : 9 : name = dwfl_module_relocation_info (mod, i, NULL);
432 [ - + ]: 9 : if (name == NULL)
433 [ # # ]: 0 : printf ("??%c", pretty ? ' ': '\n');
434 : : else
435 [ + - ]: 9 : printf ("(%s)+%#" PRIx64 "%c", name, addr, pretty ? ' ' : '\n');
436 : : }
437 : : else
438 : : {
439 : 87 : name = symname (name);
440 [ + + ]: 87 : if (off == 0)
441 : 31 : printf ("%s", name);
442 : : else
443 : 56 : printf ("%s+%#" PRIx64 "", name, off);
444 : :
445 : : // Also show section name for address.
446 [ + + ]: 87 : if (show_symbol_sections)
447 : : {
448 : 8 : Dwarf_Addr ebias;
449 : 8 : Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias);
450 [ + - ]: 8 : if (scn != NULL)
451 : : {
452 : 8 : GElf_Shdr shdr_mem;
453 : 8 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
454 [ + - ]: 8 : if (shdr != NULL)
455 : : {
456 : 8 : Elf *elf = dwfl_module_getelf (mod, &ebias);
457 : 8 : size_t shstrndx;
458 [ + - ]: 8 : if (elf_getshdrstrndx (elf, &shstrndx) >= 0)
459 : 8 : printf (" (%s)", elf_strptr (elf, shstrndx,
460 : 8 : shdr->sh_name));
461 : : }
462 : : }
463 : : }
464 [ + - ]: 87 : printf ("%c", pretty ? ' ' : '\n');
465 : : }
466 : 96 : }
467 : :
468 : : static int
469 : 0 : see_one_module (Dwfl_Module *mod,
470 : : void **userdata __attribute__ ((unused)),
471 : : const char *name __attribute__ ((unused)),
472 : : Dwarf_Addr start __attribute__ ((unused)),
473 : : void *arg)
474 : : {
475 : 0 : Dwfl_Module **result = arg;
476 [ # # ]: 0 : if (*result != NULL)
477 : : return DWARF_CB_ABORT;
478 : 0 : *result = mod;
479 : 0 : return DWARF_CB_OK;
480 : : }
481 : :
482 : : static int
483 : 29 : find_symbol (Dwfl_Module *mod,
484 : : void **userdata __attribute__ ((unused)),
485 : : const char *name __attribute__ ((unused)),
486 : : Dwarf_Addr start __attribute__ ((unused)),
487 : : void *arg)
488 : : {
489 : 29 : const char *looking_for = ((void **) arg)[0];
490 : 29 : GElf_Sym *symbol = ((void **) arg)[1];
491 : 29 : GElf_Addr *value = ((void **) arg)[2];
492 : :
493 : 29 : int n = dwfl_module_getsymtab (mod);
494 [ + + ]: 2124 : for (int i = 1; i < n; ++i)
495 : : {
496 : 2122 : const char *symbol_name = dwfl_module_getsym_info (mod, i, symbol,
497 : : value, NULL, NULL,
498 : : NULL);
499 [ + - + + ]: 2122 : if (symbol_name == NULL || symbol_name[0] == '\0')
500 : 873 : continue;
501 [ + + ]: 1249 : switch (GELF_ST_TYPE (symbol->st_info))
502 : : {
503 : : case STT_SECTION:
504 : : case STT_FILE:
505 : : case STT_TLS:
506 : : break;
507 : 1049 : default:
508 [ + + ]: 1049 : if (!strcmp (symbol_name, looking_for))
509 : : {
510 : 27 : ((void **) arg)[0] = NULL;
511 : 27 : return DWARF_CB_ABORT;
512 : : }
513 : : }
514 : : }
515 : :
516 : : return DWARF_CB_OK;
517 : : }
518 : :
519 : : static bool
520 : 0 : adjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl)
521 : : {
522 : : /* It was (section)+offset. This makes sense if there is
523 : : only one module to look in for a section. */
524 : 0 : Dwfl_Module *mod = NULL;
525 [ # # ]: 0 : if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
526 [ # # ]: 0 : || mod == NULL)
527 : 0 : error_exit (0, _("Section syntax requires exactly one module"));
528 : :
529 : 0 : int nscn = dwfl_module_relocations (mod);
530 [ # # ]: 0 : for (int i = 0; i < nscn; ++i)
531 : : {
532 : 0 : GElf_Word shndx;
533 : 0 : const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
534 [ # # ]: 0 : if (unlikely (scn == NULL))
535 : : break;
536 [ # # ]: 0 : if (!strcmp (scn, name))
537 : : {
538 : : /* Found the section. */
539 : 0 : GElf_Shdr shdr_mem;
540 : 0 : GElf_Addr shdr_bias;
541 : 0 : GElf_Shdr *shdr = gelf_getshdr
542 : : (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
543 : : &shdr_mem);
544 [ # # ]: 0 : if (unlikely (shdr == NULL))
545 : : break;
546 : :
547 [ # # ]: 0 : if (*addr >= shdr->sh_size)
548 : 0 : error (0, 0,
549 : 0 : _("offset %#" PRIxMAX " lies outside"
550 : : " section '%s'"),
551 : : *addr, scn);
552 : :
553 : 0 : *addr += shdr->sh_addr + shdr_bias;
554 : 0 : return true;
555 : : }
556 : : }
557 : :
558 : : return false;
559 : : }
560 : :
561 : : static void
562 : 185 : print_src (const char *src, int lineno, int linecol, Dwarf_Die *cu)
563 : : {
564 : 185 : const char *comp_dir = "";
565 : 185 : const char *comp_dir_sep = "";
566 : :
567 [ - + ]: 185 : if (only_basenames)
568 : 0 : src = basename (src);
569 [ + - - + ]: 185 : else if (use_comp_dir && src[0] != '/')
570 : : {
571 : 0 : Dwarf_Attribute attr;
572 : 0 : comp_dir = dwarf_formstring (dwarf_attr (cu, DW_AT_comp_dir, &attr));
573 [ # # ]: 0 : if (comp_dir != NULL)
574 : 0 : comp_dir_sep = "/";
575 : : }
576 : :
577 [ - + ]: 185 : if (linecol != 0)
578 : 0 : printf ("%s%s%s:%d:%d",
579 : : comp_dir, comp_dir_sep, src, lineno, linecol);
580 : : else
581 : 185 : printf ("%s%s%s:%d",
582 : : comp_dir, comp_dir_sep, src, lineno);
583 : 185 : }
584 : :
585 : : static int
586 : 51 : get_addr_width (Dwfl_Module *mod)
587 : : {
588 : : // Try to find the address width if possible.
589 : 51 : static int width = 0;
590 [ + + + - ]: 51 : if (width == 0 && mod != NULL)
591 : : {
592 : 6 : Dwarf_Addr bias;
593 : 6 : Elf *elf = dwfl_module_getelf (mod, &bias);
594 [ + - ]: 6 : if (elf != NULL)
595 : : {
596 : 6 : GElf_Ehdr ehdr_mem;
597 : 6 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
598 [ + - ]: 6 : if (ehdr != NULL)
599 [ + + ]: 9 : width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
600 : : }
601 : : }
602 [ - + ]: 51 : if (width == 0)
603 : 0 : width = 16;
604 : :
605 : 51 : return width;
606 : : }
607 : :
608 : : static inline void
609 : 0 : show_note (int (*get) (Dwarf_Line *, bool *),
610 : : Dwarf_Line *info,
611 : : const char *note)
612 : : {
613 : 0 : bool flag;
614 [ # # # # ]: 0 : if ((*get) (info, &flag) == 0 && flag)
615 : 0 : fputs (note, stdout);
616 : 0 : }
617 : :
618 : : static inline void
619 : 0 : show_int (int (*get) (Dwarf_Line *, unsigned int *),
620 : : Dwarf_Line *info,
621 : : const char *name)
622 : : {
623 : 0 : unsigned int val;
624 [ # # # # ]: 0 : if ((*get) (info, &val) == 0 && val != 0)
625 : 0 : printf (" (%s %u)", name, val);
626 : 0 : }
627 : :
628 : : static int
629 : 211 : handle_address (const char *string, Dwfl *dwfl)
630 : : {
631 : 211 : char *endp;
632 : 211 : uintmax_t addr = strtoumax (string, &endp, 16);
633 [ + + + + ]: 211 : if (endp == string || *endp != '\0')
634 : 27 : {
635 : 27 : bool parsed = false;
636 : 27 : int i, j;
637 : 27 : char *name = NULL;
638 [ - + ]: 27 : if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2
639 [ # # ]: 0 : && string[i] == '\0')
640 : 0 : parsed = adjust_to_section (name, &addr, dwfl);
641 [ + + - ]: 27 : switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j))
642 : : {
643 : : default:
644 : : break;
645 : 11 : case 1:
646 : 11 : addr = 0;
647 : 11 : j = i;
648 : 27 : FALLTHROUGH;
649 : 27 : case 2:
650 [ + - ]: 27 : if (string[j] != '\0')
651 : : break;
652 : :
653 : : /* It was symbol[+offset]. */
654 : 27 : GElf_Sym sym;
655 : 27 : GElf_Addr value = 0;
656 : 27 : void *arg[3] = { name, &sym, &value };
657 : 27 : (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
658 [ - + ]: 27 : if (arg[0] != NULL)
659 : 0 : error (0, 0, _("cannot find symbol '%s'"), name);
660 : : else
661 : : {
662 [ + - - + ]: 27 : if (sym.st_size != 0 && addr >= sym.st_size)
663 : 27 : error (0, 0,
664 : 0 : _("offset %#" PRIxMAX " lies outside"
665 : : " contents of '%s'"),
666 : : addr, name);
667 : 27 : addr += value;
668 : 27 : parsed = true;
669 : : }
670 : : break;
671 : : }
672 : :
673 : 27 : free (name);
674 [ - + ]: 27 : if (!parsed)
675 : 0 : return 1;
676 : : }
677 [ - + ]: 184 : else if (just_section != NULL
678 [ # # ]: 0 : && !adjust_to_section (just_section, &addr, dwfl))
679 : : return 1;
680 : :
681 : 211 : Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
682 : :
683 [ + + ]: 211 : if (print_addresses)
684 : : {
685 : 51 : int width = get_addr_width (mod);
686 [ + + ]: 51 : printf ("0x%.*" PRIx64 "%s", width, addr, pretty ? ": " : "\n");
687 : : }
688 : :
689 [ + + ]: 211 : if (show_functions)
690 : : {
691 : : /* First determine the function name. Use the DWARF information if
692 : : possible. */
693 [ + + + - ]: 101 : if (! print_dwarf_function (mod, addr) && !show_symbols)
694 : : {
695 : 26 : const char *name = dwfl_module_addrname (mod, addr);
696 [ + + ]: 26 : name = name != NULL ? symname (name) : "??";
697 [ + - ]: 26 : printf ("%s%c", name, pretty ? ' ' : '\n');
698 : : }
699 : : }
700 : :
701 [ + + ]: 211 : if (show_symbols)
702 : 96 : print_addrsym (mod, addr);
703 : :
704 [ + + + + : 211 : if ((show_functions || show_symbols) && pretty)
+ + ]
705 : 24 : printf ("at ");
706 : :
707 : 211 : Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
708 : :
709 : 211 : const char *src;
710 : 211 : int lineno, linecol;
711 : :
712 [ + + + - ]: 211 : if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
713 : : NULL, NULL)) != NULL)
714 : : {
715 : 133 : print_src (src, lineno, linecol, dwfl_linecu (line));
716 [ - + ]: 133 : if (show_flags)
717 : : {
718 : 0 : Dwarf_Addr bias;
719 : 0 : Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
720 [ # # ]: 0 : assert (info != NULL);
721 : :
722 : 0 : show_note (&dwarf_linebeginstatement, info, " (is_stmt)");
723 : 0 : show_note (&dwarf_lineblock, info, " (basic_block)");
724 : 0 : show_note (&dwarf_lineprologueend, info, " (prologue_end)");
725 : 0 : show_note (&dwarf_lineepiloguebegin, info, " (epilogue_begin)");
726 : 0 : show_int (&dwarf_lineisa, info, "isa");
727 : 0 : show_int (&dwarf_linediscriminator, info, "discriminator");
728 : : }
729 : 133 : putchar ('\n');
730 : : }
731 : : else
732 : 78 : puts ("??:0");
733 : :
734 [ + + ]: 211 : if (show_inlines)
735 : : {
736 : 73 : Dwarf_Addr bias = 0;
737 : 73 : Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
738 : :
739 : 73 : Dwarf_Die *scopes = NULL;
740 : 73 : int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
741 [ - + ]: 73 : if (nscopes < 0)
742 : 0 : return 1;
743 : :
744 [ + - ]: 73 : if (nscopes > 0)
745 : : {
746 : 73 : Dwarf_Die subroutine;
747 : 73 : Dwarf_Off dieoff = dwarf_dieoffset (&scopes[0]);
748 : 73 : dwarf_offdie (dwfl_module_getdwarf (mod, &bias),
749 : : dieoff, &subroutine);
750 : 73 : free (scopes);
751 : 73 : scopes = NULL;
752 : :
753 : 73 : nscopes = dwarf_getscopes_die (&subroutine, &scopes);
754 [ + - ]: 73 : if (nscopes > 1)
755 : : {
756 : 73 : Dwarf_Die cu;
757 : 73 : Dwarf_Files *files;
758 [ + - ]: 73 : if (dwarf_diecu (&scopes[0], &cu, NULL, NULL) != NULL
759 [ + - ]: 73 : && dwarf_getsrcfiles (cudie, &files, NULL) == 0)
760 : : {
761 [ + + ]: 202 : for (int i = 0; i < nscopes - 1; i++)
762 : : {
763 : 129 : Dwarf_Word val;
764 : 129 : Dwarf_Attribute attr;
765 : 129 : Dwarf_Die *die = &scopes[i];
766 [ + + ]: 129 : if (dwarf_tag (die) != DW_TAG_inlined_subroutine)
767 : 77 : continue;
768 : :
769 [ + + ]: 52 : if (pretty)
770 : 16 : printf (" (inlined by) ");
771 : :
772 [ + + ]: 52 : if (show_functions)
773 : : {
774 : : /* Search for the parent inline or function. It
775 : : might not be directly above this inline -- e.g.
776 : : there could be a lexical_block in between. */
777 [ + - ]: 44 : for (int j = i + 1; j < nscopes; j++)
778 : : {
779 : 44 : Dwarf_Die *parent = &scopes[j];
780 : 44 : int tag = dwarf_tag (parent);
781 : 44 : if (tag == DW_TAG_inlined_subroutine
782 [ + + ]: 44 : || tag == DW_TAG_entry_point
783 [ + + ]: 34 : || tag == DW_TAG_subprogram)
784 : : {
785 : 42 : printf ("%s%s",
786 : : symname (get_diename (parent)),
787 [ + + ]: 42 : pretty ? " at " : "\n");
788 : : break;
789 : : }
790 : : }
791 : : }
792 : :
793 : 52 : src = NULL;
794 : 52 : lineno = 0;
795 : 52 : linecol = 0;
796 [ + - ]: 52 : if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file,
797 : : &attr), &val) == 0)
798 : 52 : src = dwarf_filesrc (files, val, NULL, NULL);
799 : :
800 [ + - ]: 52 : if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
801 : : &attr), &val) == 0)
802 : 52 : lineno = val;
803 : :
804 [ - + ]: 52 : if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
805 : : &attr), &val) == 0)
806 : 0 : linecol = val;
807 : :
808 [ + - ]: 52 : if (src != NULL)
809 : : {
810 : 52 : print_src (src, lineno, linecol, &cu);
811 : 52 : putchar ('\n');
812 : : }
813 : : else
814 : 0 : puts ("??:0");
815 : : }
816 : : }
817 : : }
818 : : }
819 : 73 : free (scopes);
820 : : }
821 : :
822 : : return 0;
823 : : }
824 : :
825 : :
826 : : #include "debugpred.h"
|