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