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