Branch data Line data Source code
1 : : /* Print information from ELF file in human-readable form.
2 : : Copyright (C) 1999-2012 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 1999.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU General Public License as published by
8 : : the Free Software Foundation; either version 3 of the License, or
9 : : (at your option) any later version.
10 : :
11 : : elfutils is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : GNU General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 : :
19 : : #ifdef HAVE_CONFIG_H
20 : : # include <config.h>
21 : : #endif
22 : :
23 : : #include <argp.h>
24 : : #include <assert.h>
25 : : #include <ctype.h>
26 : : #include <dwarf.h>
27 : : #include <errno.h>
28 : : #include <error.h>
29 : : #include <fcntl.h>
30 : : #include <gelf.h>
31 : : #include <inttypes.h>
32 : : #include <langinfo.h>
33 : : #include <libdw.h>
34 : : #include <libdwfl.h>
35 : : #include <libintl.h>
36 : : #include <locale.h>
37 : : #include <stdarg.h>
38 : : #include <stdbool.h>
39 : : #include <stdlib.h>
40 : : #include <string.h>
41 : : #include <time.h>
42 : : #include <unistd.h>
43 : : #include <sys/param.h>
44 : : #include <sys/stat.h>
45 : :
46 : : #include <system.h>
47 : : #include "../libelf/libelfP.h"
48 : : #include "../libelf/common.h"
49 : : #include "../libebl/libeblP.h"
50 : : #include "../libdw/libdwP.h"
51 : : #include "../libdwfl/libdwflP.h"
52 : : #include "../libdw/memory-access.h"
53 : :
54 : : #include "../libdw/known-dwarf.h"
55 : :
56 : :
57 : : /* Name and version of program. */
58 : : static void print_version (FILE *stream, struct argp_state *state);
59 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
60 : :
61 : : /* Bug report address. */
62 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
63 : :
64 : : /* Definitions of arguments for argp functions. */
65 : : static const struct argp_option options[] =
66 : : {
67 : : { NULL, 0, NULL, 0, N_("ELF output selection:"), 0 },
68 : : { "all", 'a', NULL, 0,
69 : : N_("All these plus -p .strtab -p .dynstr -p .comment"), 0 },
70 : : { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 },
71 : : { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 },
72 : : { "histogram", 'I', NULL, 0,
73 : : N_("Display histogram of bucket list lengths"), 0 },
74 : : { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
75 : : { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
76 : : { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
77 : : { "section-headers", 'S', NULL, 0, N_("Display the sections' headers"), 0 },
78 : : { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
79 : : { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
80 : : { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
81 : : { "notes", 'n', NULL, 0, N_("Display the ELF notes"), 0 },
82 : : { "arch-specific", 'A', NULL, 0,
83 : : N_("Display architecture specific information, if any"), 0 },
84 : : { "exception", 'e', NULL, 0,
85 : : N_("Display sections for exception handling"), 0 },
86 : :
87 : : { NULL, 0, NULL, 0, N_("Additional output selection:"), 0 },
88 : : { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
89 : : N_("Display DWARF section content. SECTION can be one of abbrev, "
90 : : "aranges, frame, gdb_index, info, loc, line, ranges, pubnames, str, "
91 : : "macinfo, macro or exception"), 0 },
92 : : { "hex-dump", 'x', "SECTION", 0,
93 : : N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
94 : : { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL,
95 : : N_("Print string contents of sections"), 0 },
96 : : { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
97 : : { "archive-index", 'c', NULL, 0,
98 : : N_("Display the symbol index of an archive"), 0 },
99 : :
100 : : { NULL, 0, NULL, 0, N_("Output control:"), 0 },
101 : : { "numeric-addresses", 'N', NULL, 0,
102 : : N_("Do not find symbol names for addresses in DWARF data"), 0 },
103 : : { "wide", 'W', NULL, 0,
104 : : N_("Ignored for compatibility (lines always wide)"), 0 },
105 : : { NULL, 0, NULL, 0, NULL, 0 }
106 : : };
107 : :
108 : : /* Short description of program. */
109 : : static const char doc[] = N_("\
110 : : Print information from ELF file in human-readable form.");
111 : :
112 : : /* Strings for arguments in help texts. */
113 : : static const char args_doc[] = N_("FILE...");
114 : :
115 : : /* Prototype for option handler. */
116 : : static error_t parse_opt (int key, char *arg, struct argp_state *state);
117 : :
118 : : /* Data structure to communicate with argp functions. */
119 : : static struct argp argp =
120 : : {
121 : : options, parse_opt, args_doc, doc, NULL, NULL, NULL
122 : : };
123 : :
124 : :
125 : : /* Flags set by the option controlling the output. */
126 : :
127 : : /* True if dynamic segment should be printed. */
128 : : static bool print_dynamic_table;
129 : :
130 : : /* True if the file header should be printed. */
131 : : static bool print_file_header;
132 : :
133 : : /* True if the program headers should be printed. */
134 : : static bool print_program_header;
135 : :
136 : : /* True if relocations should be printed. */
137 : : static bool print_relocations;
138 : :
139 : : /* True if the section headers should be printed. */
140 : : static bool print_section_header;
141 : :
142 : : /* True if the symbol table should be printed. */
143 : : static bool print_symbol_table;
144 : :
145 : : /* True if the version information should be printed. */
146 : : static bool print_version_info;
147 : :
148 : : /* True if section groups should be printed. */
149 : : static bool print_section_groups;
150 : :
151 : : /* True if bucket list length histogram should be printed. */
152 : : static bool print_histogram;
153 : :
154 : : /* True if the architecture specific data should be printed. */
155 : : static bool print_arch;
156 : :
157 : : /* True if note section content should be printed. */
158 : : static bool print_notes;
159 : :
160 : : /* True if SHF_STRINGS section content should be printed. */
161 : : static bool print_string_sections;
162 : :
163 : : /* True if archive index should be printed. */
164 : : static bool print_archive_index;
165 : :
166 : : /* True if any of the control options except print_archive_index is set. */
167 : : static bool any_control_option;
168 : :
169 : : /* True if we should print addresses from DWARF in symbolic form. */
170 : : static bool print_address_names = true;
171 : :
172 : : /* Select printing of debugging sections. */
173 : : static enum section_e
174 : : {
175 : : section_abbrev = 1, /* .debug_abbrev */
176 : : section_aranges = 2, /* .debug_aranges */
177 : : section_frame = 4, /* .debug_frame or .eh_frame & al. */
178 : : section_info = 8, /* .debug_info, .debug_types */
179 : : section_types = section_info,
180 : : section_line = 16, /* .debug_line */
181 : : section_loc = 32, /* .debug_loc */
182 : : section_pubnames = 64, /* .debug_pubnames */
183 : : section_str = 128, /* .debug_str */
184 : : section_macinfo = 256, /* .debug_macinfo */
185 : : section_ranges = 512, /* .debug_ranges */
186 : : section_exception = 1024, /* .eh_frame & al. */
187 : : section_gdb_index = 2048, /* .gdb_index */
188 : : section_macro = 4096, /* .debug_macro */
189 : : section_all = (section_abbrev | section_aranges | section_frame
190 : : | section_info | section_line | section_loc
191 : : | section_pubnames | section_str | section_macinfo
192 : : | section_ranges | section_exception | section_gdb_index
193 : : | section_macro)
194 : : } print_debug_sections, implicit_debug_sections;
195 : :
196 : : /* Select hex dumping of sections. */
197 : : static struct section_argument *dump_data_sections;
198 : : static struct section_argument **dump_data_sections_tail = &dump_data_sections;
199 : :
200 : : /* Select string dumping of sections. */
201 : : static struct section_argument *string_sections;
202 : : static struct section_argument **string_sections_tail = &string_sections;
203 : :
204 : : struct section_argument
205 : : {
206 : : struct section_argument *next;
207 : : const char *arg;
208 : : bool implicit;
209 : : };
210 : :
211 : : /* Numbers of sections and program headers in the file. */
212 : : static size_t shnum;
213 : : static size_t phnum;
214 : :
215 : :
216 : : /* Declarations of local functions. */
217 : : static void process_file (int fd, const char *fname, bool only_one);
218 : : static void process_elf_file (Dwfl_Module *dwflmod, int fd);
219 : : static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
220 : : static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
221 : : static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
222 : : static void print_scngrp (Ebl *ebl);
223 : : static void print_dynamic (Ebl *ebl);
224 : : static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
225 : : static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
226 : : GElf_Shdr *shdr);
227 : : static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
228 : : GElf_Shdr *shdr);
229 : : static void print_symtab (Ebl *ebl, int type);
230 : : static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
231 : : static void print_verinfo (Ebl *ebl);
232 : : static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
233 : : static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
234 : : static void handle_versym (Ebl *ebl, Elf_Scn *scn,
235 : : GElf_Shdr *shdr);
236 : : static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
237 : : static void handle_hash (Ebl *ebl);
238 : : static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
239 : : static void print_liblist (Ebl *ebl);
240 : : static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr);
241 : : static void dump_data (Ebl *ebl);
242 : : static void dump_strings (Ebl *ebl);
243 : : static void print_strings (Ebl *ebl);
244 : : static void dump_archive_index (Elf *, const char *);
245 : :
246 : :
247 : : int
248 : 73 : main (int argc, char *argv[])
249 : : {
250 : : /* Set locale. */
251 : 73 : setlocale (LC_ALL, "");
252 : :
253 : : /* Initialize the message catalog. */
254 : 73 : textdomain (PACKAGE_TARNAME);
255 : :
256 : : /* Parse and process arguments. */
257 : : int remaining;
258 : 73 : argp_parse (&argp, argc, argv, 0, &remaining, NULL);
259 : :
260 : : /* Before we start tell the ELF library which version we are using. */
261 : 73 : elf_version (EV_CURRENT);
262 : :
263 : : /* Now process all the files given at the command line. */
264 : 73 : bool only_one = remaining + 1 == argc;
265 : : do
266 : : {
267 : : /* Open the file. */
268 : 74 : int fd = open (argv[remaining], O_RDONLY);
269 [ - + ]: 74 : if (fd == -1)
270 : : {
271 : 0 : error (0, errno, gettext ("cannot open input file"));
272 : 0 : continue;
273 : : }
274 : :
275 : 74 : process_file (fd, argv[remaining], only_one);
276 : :
277 : 74 : close (fd);
278 : : }
279 [ + + ]: 74 : while (++remaining < argc);
280 : :
281 : 73 : return error_message_count != 0;
282 : : }
283 : :
284 : :
285 : : /* Handle program arguments. */
286 : : static error_t
287 : 462 : parse_opt (int key, char *arg,
288 : : struct argp_state *state __attribute__ ((unused)))
289 : : {
290 : 109 : void add_dump_section (const char *name, bool implicit)
291 : : {
292 : 109 : struct section_argument *a = xmalloc (sizeof *a);
293 : 109 : a->arg = name;
294 : 109 : a->next = NULL;
295 : 109 : a->implicit = implicit;
296 : 109 : struct section_argument ***tailp
297 [ + + ]: 109 : = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
298 : 109 : **tailp = a;
299 : 109 : *tailp = &a->next;
300 : 109 : }
301 : :
302 [ + - + - : 462 : switch (key)
- - - - +
+ + - - +
+ - + - -
+ - + ]
303 : : {
304 : : case 'a':
305 : 36 : print_file_header = true;
306 : 36 : print_program_header = true;
307 : 36 : print_relocations = true;
308 : 36 : print_section_header = true;
309 : 36 : print_symbol_table = true;
310 : 36 : print_version_info = true;
311 : 36 : print_dynamic_table = true;
312 : 36 : print_section_groups = true;
313 : 36 : print_histogram = true;
314 : 36 : print_arch = true;
315 : 36 : print_notes = true;
316 : 36 : implicit_debug_sections |= section_exception;
317 : 36 : add_dump_section (".strtab", true);
318 : 36 : add_dump_section (".dynstr", true);
319 : 36 : add_dump_section (".comment", true);
320 : 36 : any_control_option = true;
321 : 36 : break;
322 : : case 'A':
323 : 0 : print_arch = true;
324 : 0 : any_control_option = true;
325 : 0 : break;
326 : : case 'd':
327 : 2 : print_dynamic_table = true;
328 : 2 : any_control_option = true;
329 : 2 : break;
330 : : case 'e':
331 : 0 : print_debug_sections |= section_exception;
332 : 0 : any_control_option = true;
333 : 0 : break;
334 : : case 'g':
335 : 0 : print_section_groups = true;
336 : 0 : any_control_option = true;
337 : 0 : break;
338 : : case 'h':
339 : 0 : print_file_header = true;
340 : 0 : any_control_option = true;
341 : 0 : break;
342 : : case 'I':
343 : 0 : print_histogram = true;
344 : 0 : any_control_option = true;
345 : 0 : break;
346 : : case 'l':
347 : 0 : print_program_header = true;
348 : 0 : any_control_option = true;
349 : 0 : break;
350 : : case 'n':
351 : 3 : print_notes = true;
352 : 3 : any_control_option = true;
353 : 3 : break;
354 : : case 'r':
355 : 1 : print_relocations = true;
356 : 1 : any_control_option = true;
357 : 1 : break;
358 : : case 'S':
359 : 8 : print_section_header = true;
360 : 8 : any_control_option = true;
361 : 8 : break;
362 : : case 's':
363 : 0 : print_symbol_table = true;
364 : 0 : any_control_option = true;
365 : 0 : break;
366 : : case 'V':
367 : 0 : print_version_info = true;
368 : 0 : any_control_option = true;
369 : 0 : break;
370 : : case 'c':
371 : 2 : print_archive_index = true;
372 : 2 : break;
373 : : case 'w':
374 [ + + ]: 44 : if (arg == NULL)
375 : 37 : print_debug_sections = section_all;
376 [ - + ]: 7 : else if (strcmp (arg, "abbrev") == 0)
377 : 0 : print_debug_sections |= section_abbrev;
378 [ - + ]: 7 : else if (strcmp (arg, "aranges") == 0)
379 : 0 : print_debug_sections |= section_aranges;
380 [ - + ]: 7 : else if (strcmp (arg, "ranges") == 0)
381 : : {
382 : 0 : print_debug_sections |= section_ranges;
383 : 0 : implicit_debug_sections |= section_info;
384 : : }
385 [ + - ][ - + ]: 7 : else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0)
386 : 0 : print_debug_sections |= section_frame;
387 [ + + ]: 7 : else if (strcmp (arg, "info") == 0)
388 : 4 : print_debug_sections |= section_info;
389 [ - + ][ # # ]: 3 : else if (strcmp (arg, "loc") == 0)
[ # # ][ - + ]
390 : : {
391 : 0 : print_debug_sections |= section_loc;
392 : 0 : implicit_debug_sections |= section_info;
393 : : }
394 [ - + ]: 3 : else if (strcmp (arg, "line") == 0)
395 : 0 : print_debug_sections |= section_line;
396 [ - + ]: 3 : else if (strcmp (arg, "pubnames") == 0)
397 : 0 : print_debug_sections |= section_pubnames;
398 [ - + ][ # # ]: 3 : else if (strcmp (arg, "str") == 0)
[ # # ][ - + ]
399 : 0 : print_debug_sections |= section_str;
400 [ - + ]: 3 : else if (strcmp (arg, "macinfo") == 0)
401 : 0 : print_debug_sections |= section_macinfo;
402 [ + + ]: 3 : else if (strcmp (arg, "macro") == 0)
403 : 1 : print_debug_sections |= section_macro;
404 [ - + ]: 2 : else if (strcmp (arg, "exception") == 0)
405 : 0 : print_debug_sections |= section_exception;
406 [ + - ]: 2 : else if (strcmp (arg, "gdb_index") == 0)
407 : 2 : print_debug_sections |= section_gdb_index;
408 : : else
409 : : {
410 : 0 : fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"),
411 : : arg);
412 : 0 : argp_help (&argp, stderr, ARGP_HELP_SEE,
413 : : program_invocation_short_name);
414 : 0 : exit (1);
415 : : }
416 : 44 : any_control_option = true;
417 : 44 : break;
418 : : case 'p':
419 : 0 : any_control_option = true;
420 [ # # ]: 0 : if (arg == NULL)
421 : : {
422 : 0 : print_string_sections = true;
423 : 0 : break;
424 : : }
425 : : /* Fall through. */
426 : : case 'x':
427 : 1 : add_dump_section (arg, false);
428 : 1 : any_control_option = true;
429 : 1 : break;
430 : : case 'N':
431 : 0 : print_address_names = false;
432 : 0 : break;
433 : : case ARGP_KEY_NO_ARGS:
434 : 0 : fputs (gettext ("Missing file name.\n"), stderr);
435 : 0 : goto do_argp_help;
436 : : case ARGP_KEY_FINI:
437 [ + + ][ - + ]: 73 : if (! any_control_option && ! print_archive_index)
438 : : {
439 : 0 : fputs (gettext ("No operation specified.\n"), stderr);
440 : : do_argp_help:
441 : 0 : argp_help (&argp, stderr, ARGP_HELP_SEE,
442 : : program_invocation_short_name);
443 : 462 : exit (EXIT_FAILURE);
444 : : }
445 : : break;
446 : : case 'W': /* Ignored. */
447 : : break;
448 : : default:
449 : : return ARGP_ERR_UNKNOWN;
450 : : }
451 : : return 0;
452 : : }
453 : :
454 : :
455 : : /* Print the version information. */
456 : : static void
457 : 0 : print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
458 : : {
459 : 0 : fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
460 : 0 : fprintf (stream, gettext ("\
461 : : Copyright (C) %s Red Hat, Inc.\n\
462 : : This is free software; see the source for copying conditions. There is NO\n\
463 : : warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
464 : : "), "2012");
465 : 0 : fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
466 : 0 : }
467 : :
468 : :
469 : : /* Check if the file is an archive, and if so dump its index. */
470 : : static void
471 : 2 : check_archive_index (int fd, const char *fname, bool only_one)
472 : : {
473 : : /* Create an `Elf' descriptor. */
474 : 2 : Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
475 [ - + ]: 2 : if (elf == NULL)
476 : 0 : error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
477 : : elf_errmsg (-1));
478 : : else
479 : : {
480 [ + - ]: 2 : if (elf_kind (elf) == ELF_K_AR)
481 : : {
482 [ - + ]: 2 : if (!only_one)
483 : 0 : printf ("\n%s:\n\n", fname);
484 : 2 : dump_archive_index (elf, fname);
485 : : }
486 : : else
487 : : error (0, 0,
488 : 0 : gettext ("'%s' is not an archive, cannot print archive index"),
489 : : fname);
490 : :
491 : : /* Now we can close the descriptor. */
492 [ - + ]: 2 : if (elf_end (elf) != 0)
493 : 0 : error (0, 0, gettext ("error while closing Elf descriptor: %s"),
494 : : elf_errmsg (-1));
495 : : }
496 : 2 : }
497 : :
498 : : /* Trivial callback used for checking if we opened an archive. */
499 : : static int
500 : 70 : count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
501 : : void **userdata __attribute__ ((unused)),
502 : : const char *name __attribute__ ((unused)),
503 : : Dwarf_Addr base __attribute__ ((unused)),
504 : : void *arg)
505 : : {
506 [ + - ]: 70 : if (*(bool *) arg)
507 : : return DWARF_CB_ABORT;
508 : 70 : *(bool *) arg = true;
509 : 70 : return DWARF_CB_OK;
510 : : }
511 : :
512 : : struct process_dwflmod_args
513 : : {
514 : : int fd;
515 : : bool only_one;
516 : : };
517 : :
518 : : static int
519 : 72 : process_dwflmod (Dwfl_Module *dwflmod,
520 : : void **userdata __attribute__ ((unused)),
521 : : const char *name __attribute__ ((unused)),
522 : : Dwarf_Addr base __attribute__ ((unused)),
523 : : void *arg)
524 : : {
525 : 72 : const struct process_dwflmod_args *a = arg;
526 : :
527 : : /* Print the file name. */
528 [ + + ]: 72 : if (!a->only_one)
529 : : {
530 : : const char *fname;
531 : 2 : dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
532 : :
533 : 2 : printf ("\n%s:\n\n", fname);
534 : : }
535 : :
536 : 72 : process_elf_file (dwflmod, a->fd);
537 : :
538 : 72 : return DWARF_CB_OK;
539 : : }
540 : :
541 : : /* Stub libdwfl callback, only the ELF handle already open is ever used. */
542 : : static int
543 : 12 : find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
544 : : void **userdata __attribute__ ((unused)),
545 : : const char *modname __attribute__ ((unused)),
546 : : Dwarf_Addr base __attribute__ ((unused)),
547 : : const char *file_name __attribute__ ((unused)),
548 : : const char *debuglink_file __attribute__ ((unused)),
549 : : GElf_Word debuglink_crc __attribute__ ((unused)),
550 : : char **debuginfo_file_name __attribute__ ((unused)))
551 : : {
552 : 12 : return -1;
553 : : }
554 : :
555 : : /* Process one input file. */
556 : : static void
557 : 74 : process_file (int fd, const char *fname, bool only_one)
558 : : {
559 [ + + ]: 74 : if (print_archive_index)
560 : 2 : check_archive_index (fd, fname, only_one);
561 : :
562 [ + + ]: 74 : if (!any_control_option)
563 : 74 : return;
564 : :
565 : : /* Duplicate an fd for dwfl_report_offline to swallow. */
566 : 72 : int dwfl_fd = dup (fd);
567 [ - + ]: 72 : if (unlikely (dwfl_fd < 0))
568 : 0 : error (EXIT_FAILURE, errno, "dup");
569 : :
570 : : /* Use libdwfl in a trivial way to open the libdw handle for us.
571 : : This takes care of applying relocations to DWARF data in ET_REL files. */
572 : : static const Dwfl_Callbacks callbacks =
573 : : {
574 : : .section_address = dwfl_offline_section_address,
575 : : .find_debuginfo = find_no_debuginfo
576 : : };
577 : 72 : Dwfl *dwfl = dwfl_begin (&callbacks);
578 [ + - ]: 72 : if (likely (dwfl != NULL))
579 : : /* Let 0 be the logical address of the file (or first in archive). */
580 : 72 : dwfl->offline_next_address = 0;
581 [ - + ]: 72 : if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
582 : : {
583 : : struct stat64 st;
584 [ # # ]: 0 : if (fstat64 (dwfl_fd, &st) != 0)
585 : 0 : error (0, errno, gettext ("cannot stat input file"));
586 [ # # ]: 0 : else if (unlikely (st.st_size == 0))
587 : 0 : error (0, 0, gettext ("input file is empty"));
588 : : else
589 : 0 : error (0, 0, gettext ("failed reading '%s': %s"),
590 : : fname, dwfl_errmsg (-1));
591 : 0 : close (dwfl_fd); /* Consumed on success, not on failure. */
592 : : }
593 : : else
594 : : {
595 : 72 : dwfl_report_end (dwfl, NULL, NULL);
596 : :
597 [ + + ]: 72 : if (only_one)
598 : : {
599 : : /* Clear ONLY_ONE if we have multiple modules, from an archive. */
600 : 70 : bool seen = false;
601 : 70 : only_one = dwfl_getmodules (dwfl, &count_dwflmod, &seen, 0) == 0;
602 : : }
603 : :
604 : : /* Process the one or more modules gleaned from this file. */
605 : 72 : struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
606 : 72 : dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
607 : : }
608 : 72 : dwfl_end (dwfl);
609 : : }
610 : :
611 : :
612 : : /* Process one ELF file. */
613 : : static void
614 : 72 : process_elf_file (Dwfl_Module *dwflmod, int fd)
615 : : {
616 : : GElf_Addr dwflbias;
617 : 72 : Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
618 : :
619 : : GElf_Ehdr ehdr_mem;
620 : 72 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
621 : :
622 [ - + ]: 72 : if (ehdr == NULL)
623 : : {
624 : : elf_error:
625 : 0 : error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
626 : : return;
627 : : }
628 : :
629 : 72 : Ebl *ebl = ebl_openbackend (elf);
630 [ - + ]: 72 : if (unlikely (ebl == NULL))
631 : : {
632 : : ebl_error:
633 : 0 : error (0, errno, gettext ("cannot create EBL handle"));
634 : : return;
635 : : }
636 : :
637 : : /* Determine the number of sections. */
638 [ - + ]: 72 : if (unlikely (elf_getshdrnum (ebl->elf, &shnum) < 0))
639 : 0 : error (EXIT_FAILURE, 0,
640 : 0 : gettext ("cannot determine number of sections: %s"),
641 : : elf_errmsg (-1));
642 : :
643 : : /* Determine the number of phdrs. */
644 [ - + ]: 72 : if (unlikely (elf_getphdrnum (ebl->elf, &phnum) < 0))
645 : 0 : error (EXIT_FAILURE, 0,
646 : 0 : gettext ("cannot determine number of program headers: %s"),
647 : : elf_errmsg (-1));
648 : :
649 : : /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
650 : : and may have applied relocation to some sections.
651 : : So we need to get a fresh Elf handle on the file to display those. */
652 : 72 : bool print_unrelocated = (print_section_header
653 [ + + ]: 28 : || print_relocations
654 [ + + ]: 27 : || dump_data_sections != NULL
655 [ + + ][ + + ]: 98 : || print_notes);
656 : :
657 : 72 : Elf *pure_elf = NULL;
658 : 72 : Ebl *pure_ebl = ebl;
659 [ + + ][ + + ]: 72 : if (ehdr->e_type == ET_REL && print_unrelocated)
660 : : {
661 : : /* Read the file afresh. */
662 : 14 : off64_t aroff = elf_getaroff (elf);
663 : 14 : pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
664 [ - + ]: 14 : if (aroff > 0)
665 : : {
666 : : /* Archive member. */
667 : 0 : (void) elf_rand (pure_elf, aroff);
668 : 0 : Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
669 : 0 : elf_end (pure_elf);
670 : 0 : pure_elf = armem;
671 : : }
672 [ - + ]: 14 : if (pure_elf == NULL)
673 : : goto elf_error;
674 : 14 : pure_ebl = ebl_openbackend (pure_elf);
675 [ - + ]: 14 : if (pure_ebl == NULL)
676 : : goto ebl_error;
677 : : }
678 : :
679 [ + + ]: 72 : if (print_file_header)
680 : 36 : print_ehdr (ebl, ehdr);
681 [ + + ]: 72 : if (print_section_header)
682 : 44 : print_shdr (pure_ebl, ehdr);
683 [ + + ]: 72 : if (print_program_header)
684 : 36 : print_phdr (ebl, ehdr);
685 [ + + ]: 72 : if (print_section_groups)
686 : 36 : print_scngrp (ebl);
687 [ + + ]: 72 : if (print_dynamic_table)
688 : 38 : print_dynamic (ebl);
689 [ + + ]: 72 : if (print_relocations)
690 : 37 : print_relocs (pure_ebl, ehdr);
691 [ + + ]: 72 : if (print_histogram)
692 : 36 : handle_hash (ebl);
693 [ + + ]: 72 : if (print_symbol_table)
694 : 36 : print_symtab (ebl, SHT_DYNSYM);
695 [ + + ]: 72 : if (print_version_info)
696 : 36 : print_verinfo (ebl);
697 [ + + ]: 72 : if (print_symbol_table)
698 : 36 : print_symtab (ebl, SHT_SYMTAB);
699 [ + + ]: 72 : if (print_arch)
700 : 36 : print_liblist (ebl);
701 [ + + ]: 72 : if (print_arch)
702 : 36 : print_attributes (ebl, ehdr);
703 [ + + ]: 72 : if (dump_data_sections != NULL)
704 : 1 : dump_data (pure_ebl);
705 [ + + ]: 72 : if (string_sections != NULL)
706 : 36 : dump_strings (ebl);
707 [ + + ]: 72 : if ((print_debug_sections | implicit_debug_sections) != 0)
708 : 57 : print_debug (dwflmod, ebl, ehdr);
709 [ + + ]: 72 : if (print_notes)
710 : 39 : handle_notes (pure_ebl, ehdr);
711 [ - + ]: 72 : if (print_string_sections)
712 : 0 : print_strings (ebl);
713 : :
714 : 72 : ebl_closebackend (ebl);
715 : :
716 [ + + ]: 72 : if (pure_ebl != ebl)
717 : : {
718 : 14 : ebl_closebackend (pure_ebl);
719 : 72 : elf_end (pure_elf);
720 : : }
721 : : }
722 : :
723 : :
724 : : /* Print file type. */
725 : : static void
726 : 36 : print_file_type (unsigned short int e_type)
727 : : {
728 [ + - ]: 36 : if (likely (e_type <= ET_CORE))
729 : : {
730 : : static const char *const knowntypes[] =
731 : : {
732 : : N_("NONE (None)"),
733 : : N_("REL (Relocatable file)"),
734 : : N_("EXEC (Executable file)"),
735 : : N_("DYN (Shared object file)"),
736 : : N_("CORE (Core file)")
737 : : };
738 : 36 : puts (gettext (knowntypes[e_type]));
739 : : }
740 [ # # ]: 0 : else if (e_type >= ET_LOOS && e_type <= ET_HIOS)
741 : 0 : printf (gettext ("OS Specific: (%x)\n"), e_type);
742 [ # # ]: 0 : else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */)
743 : 0 : printf (gettext ("Processor Specific: (%x)\n"), e_type);
744 : : else
745 : 0 : puts ("???");
746 : 36 : }
747 : :
748 : :
749 : : /* Print ELF header. */
750 : : static void
751 : 36 : print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
752 : : {
753 : 36 : fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout);
754 [ + + ]: 612 : for (size_t cnt = 0; cnt < EI_NIDENT; ++cnt)
755 : 576 : printf (" %02hhx", ehdr->e_ident[cnt]);
756 : :
757 [ + + ]: 70 : printf (gettext ("\n Class: %s\n"),
758 : 36 : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32"
759 : : : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64"
760 [ - + ]: 34 : : "\?\?\?");
761 : :
762 [ + + ]: 40 : printf (gettext (" Data: %s\n"),
763 : 36 : ehdr->e_ident[EI_DATA] == ELFDATA2LSB
764 : : ? "2's complement, little endian"
765 : : : ehdr->e_ident[EI_DATA] == ELFDATA2MSB
766 [ - + ]: 4 : ? "2's complement, big endian" : "\?\?\?");
767 : :
768 [ + - ]: 36 : printf (gettext (" Ident Version: %hhd %s\n"),
769 : 36 : ehdr->e_ident[EI_VERSION],
770 : 36 : ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)")
771 : : : "(\?\?\?)");
772 : :
773 : : char buf[512];
774 : 36 : printf (gettext (" OS/ABI: %s\n"),
775 : 36 : ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
776 : :
777 : 36 : printf (gettext (" ABI Version: %hhd\n"),
778 : 36 : ehdr->e_ident[EI_ABIVERSION]);
779 : :
780 : 36 : fputs_unlocked (gettext (" Type: "), stdout);
781 : 36 : print_file_type (ehdr->e_type);
782 : :
783 : 36 : printf (gettext (" Machine: %s\n"), ebl->name);
784 : :
785 [ + - ]: 36 : printf (gettext (" Version: %d %s\n"),
786 : : ehdr->e_version,
787 : 36 : ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)");
788 : :
789 : 36 : printf (gettext (" Entry point address: %#" PRIx64 "\n"),
790 : : ehdr->e_entry);
791 : :
792 : 36 : printf (gettext (" Start of program headers: %" PRId64 " %s\n"),
793 : : ehdr->e_phoff, gettext ("(bytes into file)"));
794 : :
795 : 36 : printf (gettext (" Start of section headers: %" PRId64 " %s\n"),
796 : : ehdr->e_shoff, gettext ("(bytes into file)"));
797 : :
798 : 36 : printf (gettext (" Flags: %s\n"),
799 : : ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
800 : :
801 : 36 : printf (gettext (" Size of this header: %" PRId16 " %s\n"),
802 : 36 : ehdr->e_ehsize, gettext ("(bytes)"));
803 : :
804 : 36 : printf (gettext (" Size of program header entries: %" PRId16 " %s\n"),
805 : 36 : ehdr->e_phentsize, gettext ("(bytes)"));
806 : :
807 : 36 : printf (gettext (" Number of program headers entries: %" PRId16),
808 : 36 : ehdr->e_phnum);
809 [ - + ]: 36 : if (ehdr->e_phnum == PN_XNUM)
810 : : {
811 : : GElf_Shdr shdr_mem;
812 : 0 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
813 [ # # ]: 0 : if (shdr != NULL)
814 : 0 : printf (gettext (" (%" PRIu32 " in [0].sh_info)"),
815 : : (uint32_t) shdr->sh_info);
816 : : else
817 : 0 : fputs_unlocked (gettext (" ([0] not available)"), stdout);
818 : : }
819 : 36 : fputc_unlocked ('\n', stdout);
820 : :
821 : 36 : printf (gettext (" Size of section header entries: %" PRId16 " %s\n"),
822 : 36 : ehdr->e_shentsize, gettext ("(bytes)"));
823 : :
824 : 36 : printf (gettext (" Number of section headers entries: %" PRId16),
825 : 36 : ehdr->e_shnum);
826 [ - + ]: 36 : if (ehdr->e_shnum == 0)
827 : : {
828 : : GElf_Shdr shdr_mem;
829 : 0 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
830 [ # # ]: 0 : if (shdr != NULL)
831 : 0 : printf (gettext (" (%" PRIu32 " in [0].sh_size)"),
832 : 0 : (uint32_t) shdr->sh_size);
833 : : else
834 : 0 : fputs_unlocked (gettext (" ([0] not available)"), stdout);
835 : : }
836 : 36 : fputc_unlocked ('\n', stdout);
837 : :
838 [ - + ]: 36 : if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
839 : : {
840 : : GElf_Shdr shdr_mem;
841 : 0 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
842 [ # # ]: 0 : if (shdr != NULL)
843 : : /* We managed to get the zeroth section. */
844 : 0 : snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"),
845 : : (uint32_t) shdr->sh_link);
846 : : else
847 : : {
848 : 0 : strncpy (buf, gettext (" ([0] not available)"), sizeof (buf));
849 : 0 : buf[sizeof (buf) - 1] = '\0';
850 : : }
851 : :
852 : 0 : printf (gettext (" Section header string table index: XINDEX%s\n\n"),
853 : : buf);
854 : : }
855 : : else
856 : 36 : printf (gettext (" Section header string table index: %" PRId16 "\n\n"),
857 : : ehdr->e_shstrndx);
858 : 36 : }
859 : :
860 : :
861 : : static const char *
862 : : get_visibility_type (int value)
863 : : {
864 : : switch (value)
865 : : {
866 : : case STV_DEFAULT:
867 : : return "DEFAULT";
868 : : case STV_INTERNAL:
869 : : return "INTERNAL";
870 : : case STV_HIDDEN:
871 : : return "HIDDEN";
872 : : case STV_PROTECTED:
873 : : return "PROTECTED";
874 : : default:
875 : : return "???";
876 : : }
877 : : }
878 : :
879 : :
880 : : /* Print the section headers. */
881 : : static void
882 : 44 : print_shdr (Ebl *ebl, GElf_Ehdr *ehdr)
883 : : {
884 : : size_t cnt;
885 : : size_t shstrndx;
886 : :
887 [ + + ]: 44 : if (! print_file_header)
888 : 8 : printf (gettext ("\
889 : : There are %d section headers, starting at offset %#" PRIx64 ":\n\
890 : : \n"),
891 : 8 : ehdr->e_shnum, ehdr->e_shoff);
892 : :
893 : : /* Get the section header string table index. */
894 [ - + ]: 44 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
895 : : error (EXIT_FAILURE, 0,
896 : 0 : gettext ("cannot get section header string table index"));
897 : :
898 : 44 : puts (gettext ("Section Headers:"));
899 : :
900 [ + + ]: 44 : if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
901 : 44 : puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
902 : : else
903 : 37 : puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
904 : :
905 [ + + ]: 1365 : for (cnt = 0; cnt < shnum; ++cnt)
906 : : {
907 : 1321 : Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
908 : :
909 [ - + ]: 1321 : if (unlikely (scn == NULL))
910 : 0 : error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
911 : : elf_errmsg (-1));
912 : :
913 : : /* Get the section header. */
914 : : GElf_Shdr shdr_mem;
915 : 1321 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
916 [ - + ]: 1321 : if (unlikely (shdr == NULL))
917 : 0 : error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
918 : : elf_errmsg (-1));
919 : :
920 : : char flagbuf[20];
921 : 1321 : char *cp = flagbuf;
922 [ + + ]: 1321 : if (shdr->sh_flags & SHF_WRITE)
923 : 316 : *cp++ = 'W';
924 [ + + ]: 1321 : if (shdr->sh_flags & SHF_ALLOC)
925 : 881 : *cp++ = 'A';
926 [ + + ]: 1321 : if (shdr->sh_flags & SHF_EXECINSTR)
927 : 140 : *cp++ = 'X';
928 [ + + ]: 1321 : if (shdr->sh_flags & SHF_MERGE)
929 : 74 : *cp++ = 'M';
930 [ + + ]: 1321 : if (shdr->sh_flags & SHF_STRINGS)
931 : 74 : *cp++ = 'S';
932 [ - + ]: 1321 : if (shdr->sh_flags & SHF_INFO_LINK)
933 : 0 : *cp++ = 'I';
934 [ - + ]: 1321 : if (shdr->sh_flags & SHF_LINK_ORDER)
935 : 0 : *cp++ = 'L';
936 [ - + ]: 1321 : if (shdr->sh_flags & SHF_OS_NONCONFORMING)
937 : 0 : *cp++ = 'N';
938 [ - + ]: 1321 : if (shdr->sh_flags & SHF_GROUP)
939 : 0 : *cp++ = 'G';
940 [ + + ]: 1321 : if (shdr->sh_flags & SHF_TLS)
941 : 15 : *cp++ = 'T';
942 [ - + ]: 1321 : if (shdr->sh_flags & SHF_ORDERED)
943 : 0 : *cp++ = 'O';
944 [ - + ]: 1321 : if (shdr->sh_flags & SHF_EXCLUDE)
945 : 0 : *cp++ = 'E';
946 : 1321 : *cp = '\0';
947 : :
948 : : char buf[128];
949 [ + + ][ + + ]: 2642 : printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64
[ + + ][ + - ]
950 : : " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32
951 : : " %2" PRId64 "\n",
952 : : cnt,
953 : 1321 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name)
954 : : ?: "<corrupt>",
955 : 1321 : ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)),
956 : : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr,
957 : : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset,
958 : 1321 : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size,
959 : : shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info,
960 : : shdr->sh_addralign);
961 : : }
962 : :
963 : 44 : fputc_unlocked ('\n', stdout);
964 : 44 : }
965 : :
966 : :
967 : : /* Print the program header. */
968 : : static void
969 : 36 : print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
970 : : {
971 [ + + ]: 36 : if (ehdr->e_phnum == 0)
972 : : /* No program header, this is OK in relocatable objects. */
973 : : return;
974 : :
975 : 26 : puts (gettext ("Program Headers:"));
976 [ - + ]: 26 : if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
977 : 26 : puts (gettext ("\
978 : : Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
979 : : else
980 : 26 : puts (gettext ("\
981 : : Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
982 : :
983 : : /* Process all program headers. */
984 : : bool has_relro = false;
985 : : GElf_Addr relro_from = 0;
986 : : GElf_Addr relro_to = 0;
987 [ + + ]: 222 : for (size_t cnt = 0; cnt < phnum; ++cnt)
988 : : {
989 : : char buf[128];
990 : : GElf_Phdr mem;
991 : 196 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
992 : :
993 : : /* If for some reason the header cannot be returned show this. */
994 [ - + ]: 196 : if (unlikely (phdr == NULL))
995 : : {
996 : 0 : puts (" ???");
997 : 0 : continue;
998 : : }
999 : :
1000 [ + + ][ + + ]: 196 : printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64
[ - + ][ + - ]
[ + - ]
1001 : : " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n",
1002 : 196 : ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)),
1003 : : phdr->p_offset,
1004 : : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr,
1005 : 196 : ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr,
1006 : : phdr->p_filesz,
1007 : : phdr->p_memsz,
1008 : 196 : phdr->p_flags & PF_R ? 'R' : ' ',
1009 : 196 : phdr->p_flags & PF_W ? 'W' : ' ',
1010 : 196 : phdr->p_flags & PF_X ? 'E' : ' ',
1011 : : phdr->p_align);
1012 : :
1013 [ + + ]: 196 : if (phdr->p_type == PT_INTERP)
1014 : : {
1015 : : /* We can show the user the name of the interpreter. */
1016 : : size_t maxsize;
1017 : 12 : char *filedata = elf_rawfile (ebl->elf, &maxsize);
1018 : :
1019 [ + - ][ + - ]: 12 : if (filedata != NULL && phdr->p_offset < maxsize)
1020 : 12 : printf (gettext ("\t[Requesting program interpreter: %s]\n"),
1021 : : filedata + phdr->p_offset);
1022 : : }
1023 [ + + ]: 184 : else if (phdr->p_type == PT_GNU_RELRO)
1024 : : {
1025 : 1 : has_relro = true;
1026 : 1 : relro_from = phdr->p_vaddr;
1027 : 196 : relro_to = relro_from + phdr->p_memsz;
1028 : : }
1029 : : }
1030 : :
1031 [ + - ]: 26 : if (ehdr->e_shnum == 0)
1032 : : /* No sections in the file. Punt. */
1033 : : return;
1034 : :
1035 : : /* Get the section header string table index. */
1036 : : size_t shstrndx;
1037 [ - + ]: 26 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1038 : : error (EXIT_FAILURE, 0,
1039 : 0 : gettext ("cannot get section header string table index"));
1040 : :
1041 : 26 : puts (gettext ("\n Section to Segment mapping:\n Segment Sections..."));
1042 : :
1043 [ + + ]: 232 : for (size_t cnt = 0; cnt < phnum; ++cnt)
1044 : : {
1045 : : /* Print the segment number. */
1046 : 196 : printf (" %2.2zu ", cnt);
1047 : :
1048 : : GElf_Phdr phdr_mem;
1049 : 196 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
1050 : : /* This must not happen. */
1051 [ + - ]: 196 : if (unlikely (phdr == NULL))
1052 : 0 : error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
1053 : : elf_errmsg (-1));
1054 : :
1055 : : /* Iterate over the sections. */
1056 : : bool in_relro = false;
1057 : : bool in_ro = false;
1058 [ + + ]: 7286 : for (size_t inner = 1; inner < shnum; ++inner)
1059 : : {
1060 : 7090 : Elf_Scn *scn = elf_getscn (ebl->elf, inner);
1061 : : /* This should not happen. */
1062 [ - + ]: 7090 : if (unlikely (scn == NULL))
1063 : 0 : error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
1064 : : elf_errmsg (-1));
1065 : :
1066 : : /* Get the section header. */
1067 : : GElf_Shdr shdr_mem;
1068 : 7090 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1069 [ - + ]: 7090 : if (unlikely (shdr == NULL))
1070 : 0 : error (EXIT_FAILURE, 0,
1071 : 0 : gettext ("cannot get section header: %s"),
1072 : : elf_errmsg (-1));
1073 : :
1074 [ + - ]: 7090 : if (shdr->sh_size > 0
1075 : : /* Compare allocated sections by VMA, unallocated
1076 : : sections by file offset. */
1077 [ + + ][ + + ]: 14180 : && (shdr->sh_flags & SHF_ALLOC
1078 : 5084 : ? (shdr->sh_addr >= phdr->p_vaddr
1079 [ + + ][ + + ]: 5084 : && (shdr->sh_addr + shdr->sh_size
1080 : 3453 : <= phdr->p_vaddr + phdr->p_memsz))
1081 : 2006 : : (shdr->sh_offset >= phdr->p_offset
1082 [ + - ][ + - ]: 2006 : && (shdr->sh_offset + shdr->sh_size
1083 : 2006 : <= phdr->p_offset + phdr->p_filesz))))
1084 : : {
1085 [ + + ]: 792 : if (has_relro && !in_relro
1086 [ + + ]: 24 : && shdr->sh_addr >= relro_from
1087 [ + + ]: 6 : && shdr->sh_addr + shdr->sh_size <= relro_to)
1088 : : {
1089 : 4 : fputs_unlocked (" [RELRO:", stdout);
1090 : 4 : in_relro = true;
1091 : : }
1092 [ + + ][ - + ]: 788 : else if (has_relro && in_relro && shdr->sh_addr >= relro_to)
1093 : : {
1094 : 0 : fputs_unlocked ("]", stdout);
1095 : 0 : in_relro = false;
1096 : : }
1097 [ + + ]: 788 : else if (has_relro && in_relro
1098 [ + + ]: 13 : && shdr->sh_addr + shdr->sh_size > relro_to)
1099 : 1 : fputs_unlocked ("] <RELRO:", stdout);
1100 [ + + ]: 787 : else if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
1101 : : {
1102 [ + + ]: 428 : if (!in_ro)
1103 : : {
1104 : 26 : fputs_unlocked (" [RO:", stdout);
1105 : 26 : in_ro = true;
1106 : : }
1107 : : }
1108 : : else
1109 : : {
1110 : : /* Determine the segment this section is part of. */
1111 : : size_t cnt2;
1112 : : GElf_Phdr *phdr2 = NULL;
1113 [ + - ]: 1385 : for (cnt2 = 0; cnt2 < phnum; ++cnt2)
1114 : : {
1115 : : GElf_Phdr phdr2_mem;
1116 : 1026 : phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
1117 : :
1118 [ + - ][ + + ]: 1026 : if (phdr2 != NULL && phdr2->p_type == PT_LOAD
1119 [ + - ]: 642 : && shdr->sh_addr >= phdr2->p_vaddr
1120 [ + + ]: 642 : && (shdr->sh_addr + shdr->sh_size
1121 : 642 : <= phdr2->p_vaddr + phdr2->p_memsz))
1122 : : break;
1123 : : }
1124 : :
1125 [ + - ]: 359 : if (cnt2 < phnum)
1126 : : {
1127 [ + + ][ + + ]: 359 : if ((phdr2->p_flags & PF_W) == 0 && !in_ro)
1128 : : {
1129 : 64 : fputs_unlocked (" [RO:", stdout);
1130 : 64 : in_ro = true;
1131 : : }
1132 [ + + ][ - + ]: 295 : else if ((phdr2->p_flags & PF_W) != 0 && in_ro)
1133 : : {
1134 : 0 : fputs_unlocked ("]", stdout);
1135 : 0 : in_ro = false;
1136 : : }
1137 : : }
1138 : : }
1139 : :
1140 : 792 : printf (" %s",
1141 : 792 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1142 : :
1143 : : /* Signal that this sectin is only partially covered. */
1144 [ + + ]: 792 : if (has_relro && in_relro
1145 [ + + ]: 17 : && shdr->sh_addr + shdr->sh_size > relro_to)
1146 : : {
1147 : 1 : fputs_unlocked (">", stdout);
1148 : 1 : in_relro = false;
1149 : : }
1150 : : }
1151 : : }
1152 [ + + ]: 196 : if (in_relro || in_ro)
1153 : 93 : fputs_unlocked ("]", stdout);
1154 : :
1155 : : /* Finish the line. */
1156 : 196 : fputc_unlocked ('\n', stdout);
1157 : : }
1158 : : }
1159 : :
1160 : :
1161 : : static const char *
1162 : 262 : section_name (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
1163 : : {
1164 [ + - ]: 262 : return elf_strptr (ebl->elf, ehdr->e_shstrndx, shdr->sh_name) ?: "???";
1165 : : }
1166 : :
1167 : :
1168 : : static void
1169 : 0 : handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1170 : : {
1171 : : /* Get the data of the section. */
1172 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
1173 : :
1174 : 0 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1175 : : GElf_Shdr symshdr_mem;
1176 : 0 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1177 : 0 : Elf_Data *symdata = elf_getdata (symscn, NULL);
1178 : :
1179 [ # # ][ # # ]: 0 : if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL
1180 [ # # ]: 0 : || symdata == NULL)
1181 : 0 : return;
1182 : :
1183 : : /* Get the section header string table index. */
1184 : : size_t shstrndx;
1185 [ # # ]: 0 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1186 : : error (EXIT_FAILURE, 0,
1187 : 0 : gettext ("cannot get section header string table index"));
1188 : :
1189 : 0 : Elf32_Word *grpref = (Elf32_Word *) data->d_buf;
1190 : :
1191 : : GElf_Sym sym_mem;
1192 [ # # ][ # # ]: 0 : printf ((grpref[0] & GRP_COMDAT)
1193 : 0 : ? ngettext ("\
1194 : : \nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n",
1195 : : "\
1196 : : \nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1197 : : data->d_size / sizeof (Elf32_Word) - 1)
1198 : 0 : : ngettext ("\
1199 : : \nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\
1200 : : \nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1201 : : data->d_size / sizeof (Elf32_Word) - 1),
1202 : : elf_ndxscn (scn),
1203 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1204 : 0 : elf_strptr (ebl->elf, symshdr->sh_link,
1205 : 0 : gelf_getsym (symdata, shdr->sh_info, &sym_mem)->st_name)
1206 : : ?: gettext ("<INVALID SYMBOL>"),
1207 : : data->d_size / sizeof (Elf32_Word) - 1);
1208 : :
1209 [ # # ]: 0 : for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
1210 : : {
1211 : : GElf_Shdr grpshdr_mem;
1212 : 0 : GElf_Shdr *grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
1213 : : &grpshdr_mem);
1214 : :
1215 : : const char *str;
1216 [ # # ]: 0 : printf (" [%2u] %s\n",
1217 : : grpref[cnt],
1218 : : grpshdr != NULL
1219 [ # # ]: 0 : && (str = elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name))
1220 : : ? str : gettext ("<INVALID SECTION>"));
1221 : : }
1222 : : }
1223 : :
1224 : :
1225 : : static void
1226 : 36 : print_scngrp (Ebl *ebl)
1227 : : {
1228 : : /* Find all relocation sections and handle them. */
1229 : 36 : Elf_Scn *scn = NULL;
1230 : :
1231 [ + + ]: 1159 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1232 : : {
1233 : : /* Handle the section if it is a symbol table. */
1234 : : GElf_Shdr shdr_mem;
1235 : 1123 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1236 : :
1237 [ + - ][ - + ]: 1123 : if (shdr != NULL && shdr->sh_type == SHT_GROUP)
1238 : 1123 : handle_scngrp (ebl, scn, shdr);
1239 : : }
1240 : 36 : }
1241 : :
1242 : :
1243 : : static const struct flags
1244 : : {
1245 : : int mask;
1246 : : const char *str;
1247 : : } dt_flags[] =
1248 : : {
1249 : : { DF_ORIGIN, "ORIGIN" },
1250 : : { DF_SYMBOLIC, "SYMBOLIC" },
1251 : : { DF_TEXTREL, "TEXTREL" },
1252 : : { DF_BIND_NOW, "BIND_NOW" },
1253 : : { DF_STATIC_TLS, "STATIC_TLS" }
1254 : : };
1255 : : static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]);
1256 : :
1257 : : static const struct flags dt_flags_1[] =
1258 : : {
1259 : : { DF_1_NOW, "NOW" },
1260 : : { DF_1_GLOBAL, "GLOBAL" },
1261 : : { DF_1_GROUP, "GROUP" },
1262 : : { DF_1_NODELETE, "NODELETE" },
1263 : : { DF_1_LOADFLTR, "LOADFLTR" },
1264 : : { DF_1_INITFIRST, "INITFIRST" },
1265 : : { DF_1_NOOPEN, "NOOPEN" },
1266 : : { DF_1_ORIGIN, "ORIGIN" },
1267 : : { DF_1_DIRECT, "DIRECT" },
1268 : : { DF_1_TRANS, "TRANS" },
1269 : : { DF_1_INTERPOSE, "INTERPOSE" },
1270 : : { DF_1_NODEFLIB, "NODEFLIB" },
1271 : : { DF_1_NODUMP, "NODUMP" },
1272 : : { DF_1_CONFALT, "CONFALT" },
1273 : : { DF_1_ENDFILTEE, "ENDFILTEE" },
1274 : : { DF_1_DISPRELDNE, "DISPRELDNE" },
1275 : : { DF_1_DISPRELPND, "DISPRELPND" },
1276 : : };
1277 : : static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]);
1278 : :
1279 : : static const struct flags dt_feature_1[] =
1280 : : {
1281 : : { DTF_1_PARINIT, "PARINIT" },
1282 : : { DTF_1_CONFEXP, "CONFEXP" }
1283 : : };
1284 : : static const int ndt_feature_1 = (sizeof (dt_feature_1)
1285 : : / sizeof (dt_feature_1[0]));
1286 : :
1287 : : static const struct flags dt_posflag_1[] =
1288 : : {
1289 : : { DF_P1_LAZYLOAD, "LAZYLOAD" },
1290 : : { DF_P1_GROUPPERM, "GROUPPERM" }
1291 : : };
1292 : : static const int ndt_posflag_1 = (sizeof (dt_posflag_1)
1293 : : / sizeof (dt_posflag_1[0]));
1294 : :
1295 : :
1296 : : static void
1297 : 4 : print_flags (int class, GElf_Xword d_val, const struct flags *flags,
1298 : : int nflags)
1299 : : {
1300 : 4 : bool first = true;
1301 : : int cnt;
1302 : :
1303 [ + + ]: 30 : for (cnt = 0; cnt < nflags; ++cnt)
1304 [ + + ]: 26 : if (d_val & flags[cnt].mask)
1305 : : {
1306 [ + + ]: 22 : if (!first)
1307 : : putchar_unlocked (' ');
1308 : 22 : fputs_unlocked (flags[cnt].str, stdout);
1309 : 22 : d_val &= ~flags[cnt].mask;
1310 : 22 : first = false;
1311 : : }
1312 : :
1313 [ + - ]: 4 : if (d_val != 0)
1314 : : {
1315 [ + - ]: 4 : if (!first)
1316 : : putchar_unlocked (' ');
1317 [ - + ]: 4 : printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val);
1318 : : }
1319 : :
1320 : : putchar_unlocked ('\n');
1321 : 4 : }
1322 : :
1323 : :
1324 : : static void
1325 : 1 : print_dt_flags (int class, GElf_Xword d_val)
1326 : : {
1327 : 1 : print_flags (class, d_val, dt_flags, ndt_flags);
1328 : 1 : }
1329 : :
1330 : :
1331 : : static void
1332 : 1 : print_dt_flags_1 (int class, GElf_Xword d_val)
1333 : : {
1334 : 1 : print_flags (class, d_val, dt_flags_1, ndt_flags_1);
1335 : 1 : }
1336 : :
1337 : :
1338 : : static void
1339 : 1 : print_dt_feature_1 (int class, GElf_Xword d_val)
1340 : : {
1341 : 1 : print_flags (class, d_val, dt_feature_1, ndt_feature_1);
1342 : 1 : }
1343 : :
1344 : :
1345 : : static void
1346 : 1 : print_dt_posflag_1 (int class, GElf_Xword d_val)
1347 : : {
1348 : 1 : print_flags (class, d_val, dt_posflag_1, ndt_posflag_1);
1349 : 1 : }
1350 : :
1351 : :
1352 : : static void
1353 : 28 : handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1354 : : {
1355 : 28 : int class = gelf_getclass (ebl->elf);
1356 : : GElf_Shdr glink;
1357 : : Elf_Data *data;
1358 : : size_t cnt;
1359 : : size_t shstrndx;
1360 : :
1361 : : /* Get the data of the section. */
1362 : 28 : data = elf_getdata (scn, NULL);
1363 [ + - ]: 28 : if (data == NULL)
1364 : 28 : return;
1365 : :
1366 : : /* Get the section header string table index. */
1367 [ - + ]: 28 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1368 : : error (EXIT_FAILURE, 0,
1369 : 0 : gettext ("cannot get section header string table index"));
1370 : :
1371 [ + + ]: 28 : printf (ngettext ("\
1372 : : \nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
1373 : : "\
1374 : : \nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
1375 : : shdr->sh_size / shdr->sh_entsize),
1376 : : (unsigned long int) (shdr->sh_size / shdr->sh_entsize),
1377 : : class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
1378 : : shdr->sh_offset,
1379 : 28 : (int) shdr->sh_link,
1380 : : elf_strptr (ebl->elf, shstrndx,
1381 : 28 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
1382 : 28 : &glink)->sh_name));
1383 : 28 : fputs_unlocked (gettext (" Type Value\n"), stdout);
1384 : :
1385 [ + + ]: 962 : for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
1386 : : {
1387 : : GElf_Dyn dynmem;
1388 : 934 : GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
1389 [ + - ]: 934 : if (dyn == NULL)
1390 : : break;
1391 : :
1392 : : char buf[64];
1393 : 934 : printf (" %-17s ",
1394 : : ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));
1395 : :
1396 [ + + + + : 934 : switch (dyn->d_tag)
+ + + + +
+ + + + ]
1397 : : {
1398 : : case DT_NULL:
1399 : : case DT_DEBUG:
1400 : : case DT_BIND_NOW:
1401 : : case DT_TEXTREL:
1402 : : /* No further output. */
1403 : 164 : fputc_unlocked ('\n', stdout);
1404 : : break;
1405 : :
1406 : : case DT_NEEDED:
1407 : 96 : printf (gettext ("Shared library: [%s]\n"),
1408 : 96 : elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1409 : 96 : break;
1410 : :
1411 : : case DT_SONAME:
1412 : 4 : printf (gettext ("Library soname: [%s]\n"),
1413 : 4 : elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1414 : 4 : break;
1415 : :
1416 : : case DT_RPATH:
1417 : 2 : printf (gettext ("Library rpath: [%s]\n"),
1418 : 2 : elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1419 : 2 : break;
1420 : :
1421 : : case DT_RUNPATH:
1422 : 2 : printf (gettext ("Library runpath: [%s]\n"),
1423 : 2 : elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1424 : 2 : break;
1425 : :
1426 : : case DT_PLTRELSZ:
1427 : : case DT_RELASZ:
1428 : : case DT_STRSZ:
1429 : : case DT_RELSZ:
1430 : : case DT_RELAENT:
1431 : : case DT_SYMENT:
1432 : : case DT_RELENT:
1433 : : case DT_PLTPADSZ:
1434 : : case DT_MOVEENT:
1435 : : case DT_MOVESZ:
1436 : : case DT_INIT_ARRAYSZ:
1437 : : case DT_FINI_ARRAYSZ:
1438 : : case DT_SYMINSZ:
1439 : : case DT_SYMINENT:
1440 : : case DT_GNU_CONFLICTSZ:
1441 : : case DT_GNU_LIBLISTSZ:
1442 : 203 : printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val);
1443 : 203 : break;
1444 : :
1445 : : case DT_VERDEFNUM:
1446 : : case DT_VERNEEDNUM:
1447 : : case DT_RELACOUNT:
1448 : : case DT_RELCOUNT:
1449 : 61 : printf ("%" PRId64 "\n", dyn->d_un.d_val);
1450 : 61 : break;
1451 : :
1452 : : case DT_PLTREL:;
1453 : 28 : const char *tagname = ebl_dynamic_tag_name (ebl, dyn->d_un.d_val,
1454 : : NULL, 0);
1455 [ + + ]: 28 : puts (tagname ?: "???");
1456 : 28 : break;
1457 : :
1458 : : case DT_FLAGS:
1459 : 1 : print_dt_flags (class, dyn->d_un.d_val);
1460 : 1 : break;
1461 : :
1462 : : case DT_FLAGS_1:
1463 : 1 : print_dt_flags_1 (class, dyn->d_un.d_val);
1464 : 1 : break;
1465 : :
1466 : : case DT_FEATURE_1:
1467 : 1 : print_dt_feature_1 (class, dyn->d_un.d_val);
1468 : 1 : break;
1469 : :
1470 : : case DT_POSFLAG_1:
1471 : 1 : print_dt_posflag_1 (class, dyn->d_un.d_val);
1472 : 1 : break;
1473 : :
1474 : : default:
1475 [ + + ]: 370 : printf ("%#0*" PRIx64 "\n",
1476 : : class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val);
1477 : 370 : break;
1478 : : }
1479 : : }
1480 : : }
1481 : :
1482 : :
1483 : : /* Print the dynamic segment. */
1484 : : static void
1485 : 38 : print_dynamic (Ebl *ebl)
1486 : : {
1487 [ + + ]: 118 : for (size_t i = 0; i < phnum; ++i)
1488 : : {
1489 : : GElf_Phdr phdr_mem;
1490 : 108 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
1491 : :
1492 [ + - ][ + + ]: 108 : if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
1493 : : {
1494 : 28 : Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
1495 : : GElf_Shdr shdr_mem;
1496 : 28 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1497 [ + - ][ + - ]: 28 : if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
1498 : 28 : handle_dynamic (ebl, scn, shdr);
1499 : : break;
1500 : : }
1501 : : }
1502 : 38 : }
1503 : :
1504 : :
1505 : : /* Print relocations. */
1506 : : static void
1507 : 37 : print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
1508 : : {
1509 : : /* Find all relocation sections and handle them. */
1510 : 37 : Elf_Scn *scn = NULL;
1511 : :
1512 [ + + ]: 1194 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1513 : : {
1514 : : /* Handle the section if it is a symbol table. */
1515 : : GElf_Shdr shdr_mem;
1516 : 1157 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1517 : :
1518 [ + - ]: 1157 : if (likely (shdr != NULL))
1519 : : {
1520 [ + + ]: 1157 : if (shdr->sh_type == SHT_REL)
1521 : 8 : handle_relocs_rel (ebl, ehdr, scn, shdr);
1522 [ + + ]: 1149 : else if (shdr->sh_type == SHT_RELA)
1523 : 1157 : handle_relocs_rela (ebl, ehdr, scn, shdr);
1524 : : }
1525 : : }
1526 : 37 : }
1527 : :
1528 : :
1529 : : /* Handle a relocation section. */
1530 : : static void
1531 : 8 : handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
1532 : : {
1533 : 8 : int class = gelf_getclass (ebl->elf);
1534 : 8 : int nentries = shdr->sh_size / shdr->sh_entsize;
1535 : :
1536 : : /* Get the data of the section. */
1537 : 8 : Elf_Data *data = elf_getdata (scn, NULL);
1538 [ + - ]: 8 : if (data == NULL)
1539 : : return;
1540 : :
1541 : : /* Get the symbol table information. */
1542 : 8 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1543 : : GElf_Shdr symshdr_mem;
1544 : 8 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1545 : 8 : Elf_Data *symdata = elf_getdata (symscn, NULL);
1546 : :
1547 : : /* Get the section header of the section the relocations are for. */
1548 : : GElf_Shdr destshdr_mem;
1549 : 8 : GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1550 : : &destshdr_mem);
1551 : :
1552 [ + - ][ - + ]: 8 : if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
1553 : : {
1554 : 0 : printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1555 : : shdr->sh_offset);
1556 : : return;
1557 : : }
1558 : :
1559 : : /* Search for the optional extended section index table. */
1560 : 8 : Elf_Data *xndxdata = NULL;
1561 : 8 : int xndxscnidx = elf_scnshndx (scn);
1562 [ - + ]: 8 : if (unlikely (xndxscnidx > 0))
1563 : 0 : xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
1564 : :
1565 : : /* Get the section header string table index. */
1566 : : size_t shstrndx;
1567 [ - + ]: 8 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1568 : : error (EXIT_FAILURE, 0,
1569 : 0 : gettext ("cannot get section header string table index"));
1570 : :
1571 [ + - ]: 8 : if (shdr->sh_info != 0)
1572 : 8 : printf (ngettext ("\
1573 : : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1574 : : "\
1575 : : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1576 : : nentries),
1577 : : elf_ndxscn (scn),
1578 : 8 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1579 : : (unsigned int) shdr->sh_info,
1580 : 8 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1581 : : shdr->sh_offset,
1582 : : nentries);
1583 : : else
1584 : : /* The .rel.dyn section does not refer to a specific section but
1585 : : instead of section index zero. Do not try to print a section
1586 : : name. */
1587 : 0 : printf (ngettext ("\
1588 : : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1589 : : "\
1590 : : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1591 : : nentries),
1592 : 0 : (unsigned int) elf_ndxscn (scn),
1593 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1594 : : shdr->sh_offset,
1595 : : nentries);
1596 [ + - ]: 8 : fputs_unlocked (class == ELFCLASS32
1597 : : ? gettext ("\
1598 : : Offset Type Value Name\n")
1599 : : : gettext ("\
1600 : : Offset Type Value Name\n"),
1601 : : stdout);
1602 : :
1603 : 8 : int is_statically_linked = 0;
1604 [ + + ]: 33 : for (int cnt = 0; cnt < nentries; ++cnt)
1605 : : {
1606 : : GElf_Rel relmem;
1607 : 25 : GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
1608 [ + - ]: 25 : if (likely (rel != NULL))
1609 : : {
1610 : : char buf[128];
1611 : : GElf_Sym symmem;
1612 : : Elf32_Word xndx;
1613 : 25 : GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
1614 : 25 : GELF_R_SYM (rel->r_info),
1615 : : &symmem, &xndx);
1616 [ - + ]: 25 : if (unlikely (sym == NULL))
1617 : : {
1618 : : /* As a special case we have to handle relocations in static
1619 : : executables. This only happens for IRELATIVE relocations
1620 : : (so far). There is no symbol table. */
1621 [ # # ]: 0 : if (is_statically_linked == 0)
1622 : : {
1623 : : /* Find the program header and look for a PT_INTERP entry. */
1624 : 0 : is_statically_linked = -1;
1625 [ # # ]: 0 : if (ehdr->e_type == ET_EXEC)
1626 : : {
1627 : : is_statically_linked = 1;
1628 : :
1629 [ # # ]: 0 : for (size_t inner = 0; inner < phnum; ++inner)
1630 : : {
1631 : : GElf_Phdr phdr_mem;
1632 : 0 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
1633 : : &phdr_mem);
1634 [ # # ][ # # ]: 0 : if (phdr != NULL && phdr->p_type == PT_INTERP)
1635 : : {
1636 : 0 : is_statically_linked = -1;
1637 : : break;
1638 : : }
1639 : : }
1640 : : }
1641 : : }
1642 : :
1643 [ # # ][ # # ]: 0 : if (is_statically_linked > 0 && shdr->sh_link == 0)
1644 [ # # ][ # # ]: 0 : printf ("\
[ # # ]
1645 : : %#0*" PRIx64 " %-20s %*s %s\n",
1646 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1647 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1648 : : /* Avoid the leading R_ which isn't carrying any
1649 : : information. */
1650 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1651 : : buf, sizeof (buf)) + 2
1652 : : : gettext ("<INVALID RELOC>"),
1653 : : class == ELFCLASS32 ? 10 : 18, "",
1654 : 0 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1655 : : else
1656 [ # # ][ # # ]: 0 : printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
1657 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1658 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1659 : : /* Avoid the leading R_ which isn't carrying any
1660 : : information. */
1661 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1662 : : buf, sizeof (buf)) + 2
1663 : : : gettext ("<INVALID RELOC>"),
1664 : : gettext ("INVALID SYMBOL"),
1665 : 0 : (long int) GELF_R_SYM (rel->r_info));
1666 : : }
1667 [ + + ]: 25 : else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
1668 [ - + ][ + - ]: 51 : printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
[ - + ]
1669 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1670 : 17 : likely (ebl_reloc_type_check (ebl,
1671 : : GELF_R_TYPE (rel->r_info)))
1672 : : /* Avoid the leading R_ which isn't carrying any
1673 : : information. */
1674 : 17 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1675 : : buf, sizeof (buf)) + 2
1676 : : : gettext ("<INVALID RELOC>"),
1677 : : class == ELFCLASS32 ? 10 : 18, sym->st_value,
1678 : 34 : elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
1679 : : else
1680 : : {
1681 [ + - ]: 8 : destshdr = gelf_getshdr (elf_getscn (ebl->elf,
1682 : 8 : sym->st_shndx == SHN_XINDEX
1683 : : ? xndx : sym->st_shndx),
1684 : : &destshdr_mem);
1685 : :
1686 [ - + ]: 8 : if (unlikely (destshdr == NULL))
1687 [ # # ][ # # ]: 0 : printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
[ # # ]
1688 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1689 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1690 : : /* Avoid the leading R_ which isn't carrying any
1691 : : information. */
1692 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1693 : : buf, sizeof (buf)) + 2
1694 : : : gettext ("<INVALID RELOC>"),
1695 : : gettext ("INVALID SECTION"),
1696 : 0 : (long int) (sym->st_shndx == SHN_XINDEX
1697 : : ? xndx : sym->st_shndx));
1698 : : else
1699 [ - + ][ + - ]: 41 : printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
[ - + ]
1700 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1701 : 8 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1702 : : /* Avoid the leading R_ which isn't carrying any
1703 : : information. */
1704 : 8 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1705 : : buf, sizeof (buf)) + 2
1706 : : : gettext ("<INVALID RELOC>"),
1707 : : class == ELFCLASS32 ? 10 : 18, sym->st_value,
1708 : 8 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1709 : : }
1710 : : }
1711 : : }
1712 : : }
1713 : :
1714 : :
1715 : : /* Handle a relocation section. */
1716 : : static void
1717 : 88 : handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
1718 : : {
1719 : 88 : int class = gelf_getclass (ebl->elf);
1720 : 88 : int nentries = shdr->sh_size / shdr->sh_entsize;
1721 : :
1722 : : /* Get the data of the section. */
1723 : 88 : Elf_Data *data = elf_getdata (scn, NULL);
1724 [ + - ]: 88 : if (data == NULL)
1725 : : return;
1726 : :
1727 : : /* Get the symbol table information. */
1728 : 88 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1729 : : GElf_Shdr symshdr_mem;
1730 : 88 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1731 : 88 : Elf_Data *symdata = elf_getdata (symscn, NULL);
1732 : :
1733 : : /* Get the section header of the section the relocations are for. */
1734 : : GElf_Shdr destshdr_mem;
1735 : 88 : GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1736 : : &destshdr_mem);
1737 : :
1738 [ + - ][ - + ]: 88 : if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
1739 : : {
1740 : 0 : printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1741 : : shdr->sh_offset);
1742 : : return;
1743 : : }
1744 : :
1745 : : /* Search for the optional extended section index table. */
1746 : 88 : Elf_Data *xndxdata = NULL;
1747 : 88 : int xndxscnidx = elf_scnshndx (scn);
1748 [ - + ]: 88 : if (unlikely (xndxscnidx > 0))
1749 : 0 : xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
1750 : :
1751 : : /* Get the section header string table index. */
1752 : : size_t shstrndx;
1753 [ - + ]: 88 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1754 : : error (EXIT_FAILURE, 0,
1755 : 0 : gettext ("cannot get section header string table index"));
1756 : :
1757 : 88 : printf (ngettext ("\
1758 : : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1759 : : "\
1760 : : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1761 : : nentries),
1762 : : elf_ndxscn (scn),
1763 : 88 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1764 : : (unsigned int) shdr->sh_info,
1765 : 88 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1766 : : shdr->sh_offset,
1767 : : nentries);
1768 [ - + ]: 88 : fputs_unlocked (class == ELFCLASS32
1769 : : ? gettext ("\
1770 : : Offset Type Value Addend Name\n")
1771 : : : gettext ("\
1772 : : Offset Type Value Addend Name\n"),
1773 : : stdout);
1774 : :
1775 : 88 : int is_statically_linked = 0;
1776 [ + + ]: 7250 : for (int cnt = 0; cnt < nentries; ++cnt)
1777 : : {
1778 : : GElf_Rela relmem;
1779 : 7162 : GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
1780 [ + - ]: 7162 : if (likely (rel != NULL))
1781 : : {
1782 : : char buf[64];
1783 : : GElf_Sym symmem;
1784 : : Elf32_Word xndx;
1785 : 7162 : GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
1786 : 7162 : GELF_R_SYM (rel->r_info),
1787 : : &symmem, &xndx);
1788 : :
1789 [ - + ]: 7162 : if (unlikely (sym == NULL))
1790 : : {
1791 : : /* As a special case we have to handle relocations in static
1792 : : executables. This only happens for IRELATIVE relocations
1793 : : (so far). There is no symbol table. */
1794 [ # # ]: 0 : if (is_statically_linked == 0)
1795 : : {
1796 : : /* Find the program header and look for a PT_INTERP entry. */
1797 : 0 : is_statically_linked = -1;
1798 [ # # ]: 0 : if (ehdr->e_type == ET_EXEC)
1799 : : {
1800 : : is_statically_linked = 1;
1801 : :
1802 [ # # ]: 0 : for (size_t inner = 0; inner < phnum; ++inner)
1803 : : {
1804 : : GElf_Phdr phdr_mem;
1805 : 0 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
1806 : : &phdr_mem);
1807 [ # # ][ # # ]: 0 : if (phdr != NULL && phdr->p_type == PT_INTERP)
1808 : : {
1809 : 0 : is_statically_linked = -1;
1810 : : break;
1811 : : }
1812 : : }
1813 : : }
1814 : : }
1815 : :
1816 [ # # ][ # # ]: 0 : if (is_statically_linked > 0 && shdr->sh_link == 0)
1817 [ # # ][ # # ]: 0 : printf ("\
[ # # ]
1818 : : %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " %s\n",
1819 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1820 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1821 : : /* Avoid the leading R_ which isn't carrying any
1822 : : information. */
1823 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1824 : : buf, sizeof (buf)) + 2
1825 : : : gettext ("<INVALID RELOC>"),
1826 : : class == ELFCLASS32 ? 10 : 18, "",
1827 : : rel->r_addend,
1828 : 0 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1829 : : else
1830 [ # # ][ # # ]: 0 : printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
1831 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1832 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1833 : : /* Avoid the leading R_ which isn't carrying any
1834 : : information. */
1835 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1836 : : buf, sizeof (buf)) + 2
1837 : : : gettext ("<INVALID RELOC>"),
1838 : : gettext ("INVALID SYMBOL"),
1839 : 0 : (long int) GELF_R_SYM (rel->r_info));
1840 : : }
1841 [ + + ]: 7162 : else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
1842 [ + - ][ + - ]: 14418 : printf ("\
[ + - ]
1843 : : %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
1844 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1845 : 4806 : likely (ebl_reloc_type_check (ebl,
1846 : : GELF_R_TYPE (rel->r_info)))
1847 : : /* Avoid the leading R_ which isn't carrying any
1848 : : information. */
1849 : 4806 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1850 : : buf, sizeof (buf)) + 2
1851 : : : gettext ("<INVALID RELOC>"),
1852 : : class == ELFCLASS32 ? 10 : 18, sym->st_value,
1853 : : rel->r_addend,
1854 : 9612 : elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
1855 : : else
1856 : : {
1857 [ + - ]: 2356 : destshdr = gelf_getshdr (elf_getscn (ebl->elf,
1858 : 2356 : sym->st_shndx == SHN_XINDEX
1859 : : ? xndx : sym->st_shndx),
1860 : : &destshdr_mem);
1861 : :
1862 [ - + ]: 2356 : if (unlikely (shdr == NULL))
1863 [ # # ][ # # ]: 0 : printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
[ # # ]
1864 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1865 : 0 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1866 : : /* Avoid the leading R_ which isn't carrying any
1867 : : information. */
1868 : 0 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1869 : : buf, sizeof (buf)) + 2
1870 : : : gettext ("<INVALID RELOC>"),
1871 : : gettext ("INVALID SECTION"),
1872 : 0 : (long int) (sym->st_shndx == SHN_XINDEX
1873 : : ? xndx : sym->st_shndx));
1874 : : else
1875 [ + - ][ + - ]: 11874 : printf ("\
[ + - ]
1876 : : %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
1877 : : class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1878 : 2356 : ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1879 : : /* Avoid the leading R_ which isn't carrying any
1880 : : information. */
1881 : 2356 : ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1882 : : buf, sizeof (buf)) + 2
1883 : : : gettext ("<INVALID RELOC>"),
1884 : : class == ELFCLASS32 ? 10 : 18, sym->st_value,
1885 : : rel->r_addend,
1886 : 2356 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1887 : : }
1888 : : }
1889 : : }
1890 : : }
1891 : :
1892 : :
1893 : : /* Print the program header. */
1894 : : static void
1895 : 72 : print_symtab (Ebl *ebl, int type)
1896 : : {
1897 : : /* Find the symbol table(s). For this we have to search through the
1898 : : section table. */
1899 : 72 : Elf_Scn *scn = NULL;
1900 : :
1901 [ + + ]: 2318 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1902 : : {
1903 : : /* Handle the section if it is a symbol table. */
1904 : : GElf_Shdr shdr_mem;
1905 : 2246 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1906 : :
1907 [ + - ][ + + ]: 2246 : if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
1908 : 2246 : handle_symtab (ebl, scn, shdr);
1909 : : }
1910 : 72 : }
1911 : :
1912 : :
1913 : : static void
1914 : 60 : handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1915 : : {
1916 : 60 : Elf_Data *versym_data = NULL;
1917 : 60 : Elf_Data *verneed_data = NULL;
1918 : 60 : Elf_Data *verdef_data = NULL;
1919 : 60 : Elf_Data *xndx_data = NULL;
1920 : 60 : int class = gelf_getclass (ebl->elf);
1921 : 60 : Elf32_Word verneed_stridx = 0;
1922 : 60 : Elf32_Word verdef_stridx = 0;
1923 : :
1924 : : /* Get the data of the section. */
1925 : 60 : Elf_Data *data = elf_getdata (scn, NULL);
1926 [ + - ]: 60 : if (data == NULL)
1927 : 60 : return;
1928 : :
1929 : : /* Find out whether we have other sections we might need. */
1930 : : Elf_Scn *runscn = NULL;
1931 [ + + ]: 2060 : while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL)
1932 : : {
1933 : : GElf_Shdr runshdr_mem;
1934 : 2000 : GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
1935 : :
1936 [ + - ]: 2000 : if (likely (runshdr != NULL))
1937 : : {
1938 [ + + ]: 2000 : if (runshdr->sh_type == SHT_GNU_versym
1939 [ + + ]: 50 : && runshdr->sh_link == elf_ndxscn (scn))
1940 : : /* Bingo, found the version information. Now get the data. */
1941 : 26 : versym_data = elf_getdata (runscn, NULL);
1942 [ + + ]: 1974 : else if (runshdr->sh_type == SHT_GNU_verneed)
1943 : : {
1944 : : /* This is the information about the needed versions. */
1945 : 50 : verneed_data = elf_getdata (runscn, NULL);
1946 : 50 : verneed_stridx = runshdr->sh_link;
1947 : : }
1948 [ + + ]: 1924 : else if (runshdr->sh_type == SHT_GNU_verdef)
1949 : : {
1950 : : /* This is the information about the defined versions. */
1951 : 28 : verdef_data = elf_getdata (runscn, NULL);
1952 : 28 : verdef_stridx = runshdr->sh_link;
1953 : : }
1954 [ - + ]: 1896 : else if (runshdr->sh_type == SHT_SYMTAB_SHNDX
1955 [ # # ]: 0 : && runshdr->sh_link == elf_ndxscn (scn))
1956 : : /* Extended section index. */
1957 : 2000 : xndx_data = elf_getdata (runscn, NULL);
1958 : : }
1959 : : }
1960 : :
1961 : : /* Get the section header string table index. */
1962 : : size_t shstrndx;
1963 [ - + ]: 60 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1964 : : error (EXIT_FAILURE, 0,
1965 : 0 : gettext ("cannot get section header string table index"));
1966 : :
1967 : : /* Now we can compute the number of entries in the section. */
1968 : 120 : unsigned int nsyms = data->d_size / (class == ELFCLASS32
1969 : : ? sizeof (Elf32_Sym)
1970 [ + + ]: 60 : : sizeof (Elf64_Sym));
1971 : :
1972 : 120 : printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n",
1973 : : "\nSymbol table [%2u] '%s' contains %u entries:\n",
1974 : : nsyms),
1975 : 60 : (unsigned int) elf_ndxscn (scn),
1976 : 60 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms);
1977 : : GElf_Shdr glink;
1978 : 60 : printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n",
1979 : : " %lu local symbols String table: [%2u] '%s'\n",
1980 : : shdr->sh_info),
1981 : : (unsigned long int) shdr->sh_info,
1982 : : (unsigned int) shdr->sh_link,
1983 : : elf_strptr (ebl->elf, shstrndx,
1984 : 60 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
1985 : 60 : &glink)->sh_name));
1986 : :
1987 [ + + ]: 60 : fputs_unlocked (class == ELFCLASS32
1988 : : ? gettext ("\
1989 : : Num: Value Size Type Bind Vis Ndx Name\n")
1990 : : : gettext ("\
1991 : : Num: Value Size Type Bind Vis Ndx Name\n"),
1992 : : stdout);
1993 : :
1994 [ + + ]: 18588 : for (unsigned int cnt = 0; cnt < nsyms; ++cnt)
1995 : : {
1996 : : char typebuf[64];
1997 : : char bindbuf[64];
1998 : : char scnbuf[64];
1999 : : Elf32_Word xndx;
2000 : : GElf_Sym sym_mem;
2001 : 18528 : GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
2002 : :
2003 [ - + ]: 18528 : if (unlikely (sym == NULL))
2004 : 0 : continue;
2005 : :
2006 : : /* Determine the real section index. */
2007 [ + - ]: 18528 : if (likely (sym->st_shndx != SHN_XINDEX))
2008 : 18528 : xndx = sym->st_shndx;
2009 : :
2010 [ + - ][ + + ]: 18528 : printf (gettext ("\
2011 : : %5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"),
2012 : : cnt,
2013 : : class == ELFCLASS32 ? 8 : 16,
2014 : : sym->st_value,
2015 : : sym->st_size,
2016 : 18528 : ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
2017 : : typebuf, sizeof (typebuf)),
2018 : 18528 : ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info),
2019 : : bindbuf, sizeof (bindbuf)),
2020 : 18528 : get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)),
2021 : 18528 : ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf,
2022 : : sizeof (scnbuf), NULL, shnum),
2023 : 37056 : elf_strptr (ebl->elf, shdr->sh_link, sym->st_name));
2024 : :
2025 [ + + ]: 18528 : if (versym_data != NULL)
2026 : : {
2027 : : /* Get the version information. */
2028 : : GElf_Versym versym_mem;
2029 : 2115 : GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem);
2030 : :
2031 [ + - ][ + + ]: 2115 : if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1))
2032 : : {
2033 : 1674 : bool is_nobits = false;
2034 : 1674 : bool check_def = xndx != SHN_UNDEF;
2035 : :
2036 [ + + ][ - + ]: 1674 : if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX)
2037 : : {
2038 : : GElf_Shdr symshdr_mem;
2039 : 1641 : GElf_Shdr *symshdr =
2040 : 1641 : gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem);
2041 : :
2042 : 1641 : is_nobits = (symshdr != NULL
2043 [ + - ][ + + ]: 1641 : && symshdr->sh_type == SHT_NOBITS);
2044 : : }
2045 : :
2046 [ + + ]: 1674 : if (is_nobits || ! check_def)
2047 : : {
2048 : : /* We must test both. */
2049 : : GElf_Vernaux vernaux_mem;
2050 : 1316 : GElf_Vernaux *vernaux = NULL;
2051 : 1316 : size_t vn_offset = 0;
2052 : :
2053 : : GElf_Verneed verneed_mem;
2054 : 1316 : GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0,
2055 : : &verneed_mem);
2056 [ + - ]: 4334 : while (verneed != NULL)
2057 : : {
2058 : 4334 : size_t vna_offset = vn_offset;
2059 : :
2060 : 4334 : vernaux = gelf_getvernaux (verneed_data,
2061 : 4334 : vna_offset += verneed->vn_aux,
2062 : : &vernaux_mem);
2063 [ + - ]: 6905 : while (vernaux != NULL
2064 [ + + ]: 6905 : && vernaux->vna_other != *versym
2065 [ + + ]: 5589 : && vernaux->vna_next != 0)
2066 : : {
2067 : : /* Update the offset. */
2068 : 2571 : vna_offset += vernaux->vna_next;
2069 : :
2070 : 2571 : vernaux = (vernaux->vna_next == 0
2071 : : ? NULL
2072 [ + - ]: 2571 : : gelf_getvernaux (verneed_data,
2073 : : vna_offset,
2074 : : &vernaux_mem));
2075 : : }
2076 : :
2077 : : /* Check whether we found the version. */
2078 [ + - ][ + + ]: 4334 : if (vernaux != NULL && vernaux->vna_other == *versym)
2079 : : /* Found it. */
2080 : : break;
2081 : :
2082 : 3018 : vn_offset += verneed->vn_next;
2083 : 3018 : verneed = (verneed->vn_next == 0
2084 : : ? NULL
2085 [ + - ]: 3018 : : gelf_getverneed (verneed_data, vn_offset,
2086 : : &verneed_mem));
2087 : : }
2088 : :
2089 [ + - ][ + - ]: 1316 : if (vernaux != NULL && vernaux->vna_other == *versym)
2090 : : {
2091 : 1316 : printf ("@%s (%u)",
2092 : : elf_strptr (ebl->elf, verneed_stridx,
2093 : 1316 : vernaux->vna_name),
2094 : : (unsigned int) vernaux->vna_other);
2095 : 1316 : check_def = 0;
2096 : : }
2097 [ # # ]: 0 : else if (unlikely (! is_nobits))
2098 : 0 : error (0, 0, gettext ("bad dynamic symbol"));
2099 : : else
2100 : : check_def = 1;
2101 : : }
2102 : :
2103 [ + + ][ + - ]: 1674 : if (check_def && *versym != 0x8001)
2104 : : {
2105 : : /* We must test both. */
2106 : 358 : size_t vd_offset = 0;
2107 : :
2108 : : GElf_Verdef verdef_mem;
2109 : 358 : GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0,
2110 : : &verdef_mem);
2111 [ + - ]: 1298 : while (verdef != NULL)
2112 : : {
2113 [ + + ]: 1298 : if (verdef->vd_ndx == (*versym & 0x7fff))
2114 : : /* Found the definition. */
2115 : : break;
2116 : :
2117 : 940 : vd_offset += verdef->vd_next;
2118 : 940 : verdef = (verdef->vd_next == 0
2119 : : ? NULL
2120 [ + - ]: 940 : : gelf_getverdef (verdef_data, vd_offset,
2121 : : &verdef_mem));
2122 : : }
2123 : :
2124 [ + - ]: 358 : if (verdef != NULL)
2125 : : {
2126 : : GElf_Verdaux verdaux_mem;
2127 : 358 : GElf_Verdaux *verdaux
2128 : 358 : = gelf_getverdaux (verdef_data,
2129 : 358 : vd_offset + verdef->vd_aux,
2130 : : &verdaux_mem);
2131 : :
2132 [ + - ]: 358 : if (verdaux != NULL)
2133 [ + + ]: 2115 : printf ((*versym & 0x8000) ? "@%s" : "@@%s",
2134 : : elf_strptr (ebl->elf, verdef_stridx,
2135 : 358 : verdaux->vda_name));
2136 : : }
2137 : : }
2138 : : }
2139 : : }
2140 : :
2141 : : putchar_unlocked ('\n');
2142 : : }
2143 : : }
2144 : :
2145 : :
2146 : : /* Print version information. */
2147 : : static void
2148 : 36 : print_verinfo (Ebl *ebl)
2149 : : {
2150 : : /* Find the version information sections. For this we have to
2151 : : search through the section table. */
2152 : 36 : Elf_Scn *scn = NULL;
2153 : :
2154 [ + + ]: 1159 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2155 : : {
2156 : : /* Handle the section if it is part of the versioning handling. */
2157 : : GElf_Shdr shdr_mem;
2158 : 1123 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2159 : :
2160 [ + - ]: 1123 : if (likely (shdr != NULL))
2161 : : {
2162 [ + + ]: 1123 : if (shdr->sh_type == SHT_GNU_verneed)
2163 : 26 : handle_verneed (ebl, scn, shdr);
2164 [ + + ]: 1097 : else if (shdr->sh_type == SHT_GNU_verdef)
2165 : 14 : handle_verdef (ebl, scn, shdr);
2166 [ + + ]: 1083 : else if (shdr->sh_type == SHT_GNU_versym)
2167 : 1123 : handle_versym (ebl, scn, shdr);
2168 : : }
2169 : : }
2170 : 36 : }
2171 : :
2172 : :
2173 : : static const char *
2174 : 175 : get_ver_flags (unsigned int flags)
2175 : : {
2176 : : static char buf[32];
2177 : : char *endp;
2178 : :
2179 [ + + ]: 175 : if (flags == 0)
2180 : 160 : return gettext ("none");
2181 : :
2182 [ + + ]: 15 : if (flags & VER_FLG_BASE)
2183 : 14 : endp = stpcpy (buf, "BASE ");
2184 : : else
2185 : : endp = buf;
2186 : :
2187 [ + + ]: 15 : if (flags & VER_FLG_WEAK)
2188 : : {
2189 [ - + ]: 1 : if (endp != buf)
2190 : 0 : endp = stpcpy (endp, "| ");
2191 : :
2192 : 1 : endp = stpcpy (endp, "WEAK ");
2193 : : }
2194 : :
2195 [ - + ]: 15 : if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
2196 : : {
2197 : 0 : strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
2198 : 175 : buf[sizeof (buf) - 1] = '\0';
2199 : : }
2200 : :
2201 : : return buf;
2202 : : }
2203 : :
2204 : :
2205 : : static void
2206 : 26 : handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2207 : : {
2208 : 26 : int class = gelf_getclass (ebl->elf);
2209 : :
2210 : : /* Get the data of the section. */
2211 : 26 : Elf_Data *data = elf_getdata (scn, NULL);
2212 [ + - ]: 26 : if (data == NULL)
2213 : 26 : return;
2214 : :
2215 : : /* Get the section header string table index. */
2216 : : size_t shstrndx;
2217 [ - + ]: 26 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2218 : : error (EXIT_FAILURE, 0,
2219 : 0 : gettext ("cannot get section header string table index"));
2220 : :
2221 : : GElf_Shdr glink;
2222 [ + - ]: 52 : printf (ngettext ("\
2223 : : \nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2224 : : "\
2225 : : \nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2226 : : shdr->sh_info),
2227 : 26 : (unsigned int) elf_ndxscn (scn),
2228 : 26 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info,
2229 : : class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2230 : : shdr->sh_offset,
2231 : : (unsigned int) shdr->sh_link,
2232 : : elf_strptr (ebl->elf, shstrndx,
2233 : 26 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2234 : 26 : &glink)->sh_name));
2235 : :
2236 : 26 : unsigned int offset = 0;
2237 [ + + ]: 109 : for (int cnt = shdr->sh_info; --cnt >= 0; )
2238 : : {
2239 : : /* Get the data at the next offset. */
2240 : : GElf_Verneed needmem;
2241 : 83 : GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
2242 [ + - ]: 83 : if (unlikely (need == NULL))
2243 : : break;
2244 : :
2245 : 83 : printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"),
2246 : 83 : offset, (unsigned short int) need->vn_version,
2247 : 166 : elf_strptr (ebl->elf, shdr->sh_link, need->vn_file),
2248 : 83 : (unsigned short int) need->vn_cnt);
2249 : :
2250 : 83 : unsigned int auxoffset = offset + need->vn_aux;
2251 [ + + ]: 211 : for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
2252 : : {
2253 : : GElf_Vernaux auxmem;
2254 : 128 : GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
2255 [ + - ]: 128 : if (unlikely (aux == NULL))
2256 : : break;
2257 : :
2258 : 128 : printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"),
2259 : : auxoffset,
2260 : 256 : elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name),
2261 : 128 : get_ver_flags (aux->vna_flags),
2262 : 128 : (unsigned short int) aux->vna_other);
2263 : :
2264 : 128 : auxoffset += aux->vna_next;
2265 : : }
2266 : :
2267 : : /* Find the next offset. */
2268 : 83 : offset += need->vn_next;
2269 : : }
2270 : : }
2271 : :
2272 : :
2273 : : static void
2274 : 14 : handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2275 : : {
2276 : : /* Get the data of the section. */
2277 : 14 : Elf_Data *data = elf_getdata (scn, NULL);
2278 [ + - ]: 14 : if (data == NULL)
2279 : 14 : return;
2280 : :
2281 : : /* Get the section header string table index. */
2282 : : size_t shstrndx;
2283 [ - + ]: 14 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2284 : : error (EXIT_FAILURE, 0,
2285 : 0 : gettext ("cannot get section header string table index"));
2286 : :
2287 : 14 : int class = gelf_getclass (ebl->elf);
2288 : : GElf_Shdr glink;
2289 [ + - ]: 28 : printf (ngettext ("\
2290 : : \nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2291 : : "\
2292 : : \nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2293 : : shdr->sh_info),
2294 : 14 : (unsigned int) elf_ndxscn (scn),
2295 : 14 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2296 : : shdr->sh_info,
2297 : : class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2298 : : shdr->sh_offset,
2299 : : (unsigned int) shdr->sh_link,
2300 : : elf_strptr (ebl->elf, shstrndx,
2301 : 14 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2302 : 14 : &glink)->sh_name));
2303 : :
2304 : 14 : unsigned int offset = 0;
2305 [ + + ]: 61 : for (int cnt = shdr->sh_info; --cnt >= 0; )
2306 : : {
2307 : : /* Get the data at the next offset. */
2308 : : GElf_Verdef defmem;
2309 : 47 : GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
2310 [ + - ]: 47 : if (unlikely (def == NULL))
2311 : : break;
2312 : :
2313 : 47 : unsigned int auxoffset = offset + def->vd_aux;
2314 : : GElf_Verdaux auxmem;
2315 : 47 : GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
2316 [ + - ]: 47 : if (unlikely (aux == NULL))
2317 : : break;
2318 : :
2319 : 47 : printf (gettext ("\
2320 : : %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"),
2321 : 47 : offset, def->vd_version,
2322 : 47 : get_ver_flags (def->vd_flags),
2323 : 47 : def->vd_ndx,
2324 : 47 : def->vd_cnt,
2325 : 94 : elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2326 : :
2327 : 47 : auxoffset += aux->vda_next;
2328 [ + + ]: 66 : for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
2329 : : {
2330 : 19 : aux = gelf_getverdaux (data, auxoffset, &auxmem);
2331 [ + - ]: 19 : if (unlikely (aux == NULL))
2332 : : break;
2333 : :
2334 : 19 : printf (gettext (" %#06x: Parent %d: %s\n"),
2335 : : auxoffset, cnt2,
2336 : 38 : elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2337 : :
2338 : 19 : auxoffset += aux->vda_next;
2339 : : }
2340 : :
2341 : : /* Find the next offset. */
2342 : 47 : offset += def->vd_next;
2343 : : }
2344 : : }
2345 : :
2346 : :
2347 : : static void
2348 : 26 : handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2349 : : {
2350 : 26 : int class = gelf_getclass (ebl->elf);
2351 : : const char **vername;
2352 : : const char **filename;
2353 : :
2354 : : /* Get the data of the section. */
2355 : 26 : Elf_Data *data = elf_getdata (scn, NULL);
2356 [ + - ]: 26 : if (data == NULL)
2357 : : return;
2358 : :
2359 : : /* Get the section header string table index. */
2360 : : size_t shstrndx;
2361 [ + - ]: 26 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2362 : : error (EXIT_FAILURE, 0,
2363 : 0 : gettext ("cannot get section header string table index"));
2364 : :
2365 : : /* We have to find the version definition section and extract the
2366 : : version names. */
2367 : : Elf_Scn *defscn = NULL;
2368 : : Elf_Scn *needscn = NULL;
2369 : :
2370 : : Elf_Scn *verscn = NULL;
2371 [ + + ]: 963 : while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL)
2372 : : {
2373 : : GElf_Shdr vershdr_mem;
2374 : 937 : GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
2375 : :
2376 [ + - ]: 937 : if (likely (vershdr != NULL))
2377 : : {
2378 [ + + ]: 937 : if (vershdr->sh_type == SHT_GNU_verdef)
2379 : : defscn = verscn;
2380 [ + + ]: 923 : else if (vershdr->sh_type == SHT_GNU_verneed)
2381 : 937 : needscn = verscn;
2382 : : }
2383 : : }
2384 : :
2385 : : size_t nvername;
2386 [ + - ]: 26 : if (defscn != NULL || needscn != NULL)
2387 : : {
2388 : : /* We have a version information (better should have). Now get
2389 : : the version names. First find the maximum version number. */
2390 : 26 : nvername = 0;
2391 [ + + ]: 26 : if (defscn != NULL)
2392 : : {
2393 : : /* Run through the version definitions and find the highest
2394 : : index. */
2395 : 14 : unsigned int offset = 0;
2396 : : Elf_Data *defdata;
2397 : : GElf_Shdr defshdrmem;
2398 : : GElf_Shdr *defshdr;
2399 : :
2400 : 14 : defdata = elf_getdata (defscn, NULL);
2401 [ + - ]: 14 : if (unlikely (defdata == NULL))
2402 : : return;
2403 : :
2404 : 14 : defshdr = gelf_getshdr (defscn, &defshdrmem);
2405 [ + - ]: 14 : if (unlikely (defshdr == NULL))
2406 : : return;
2407 : :
2408 [ + + ]: 61 : for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
2409 : : {
2410 : : GElf_Verdef defmem;
2411 : : GElf_Verdef *def;
2412 : :
2413 : : /* Get the data at the next offset. */
2414 : 47 : def = gelf_getverdef (defdata, offset, &defmem);
2415 [ + - ]: 47 : if (unlikely (def == NULL))
2416 : : break;
2417 : :
2418 : 47 : nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
2419 : :
2420 : 47 : offset += def->vd_next;
2421 : : }
2422 : : }
2423 [ + - ]: 26 : if (needscn != NULL)
2424 : : {
2425 : 26 : unsigned int offset = 0;
2426 : : Elf_Data *needdata;
2427 : : GElf_Shdr needshdrmem;
2428 : : GElf_Shdr *needshdr;
2429 : :
2430 : 26 : needdata = elf_getdata (needscn, NULL);
2431 [ + - ]: 26 : if (unlikely (needdata == NULL))
2432 : : return;
2433 : :
2434 : 26 : needshdr = gelf_getshdr (needscn, &needshdrmem);
2435 [ + - ]: 26 : if (unlikely (needshdr == NULL))
2436 : : return;
2437 : :
2438 [ + + ]: 109 : for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
2439 : : {
2440 : : GElf_Verneed needmem;
2441 : : GElf_Verneed *need;
2442 : : unsigned int auxoffset;
2443 : : int cnt2;
2444 : :
2445 : : /* Get the data at the next offset. */
2446 : 83 : need = gelf_getverneed (needdata, offset, &needmem);
2447 [ + - ]: 83 : if (unlikely (need == NULL))
2448 : : break;
2449 : :
2450 : : /* Run through the auxiliary entries. */
2451 : 83 : auxoffset = offset + need->vn_aux;
2452 [ + + ]: 211 : for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
2453 : : {
2454 : : GElf_Vernaux auxmem;
2455 : : GElf_Vernaux *aux;
2456 : :
2457 : 128 : aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
2458 [ + - ]: 128 : if (unlikely (aux == NULL))
2459 : : break;
2460 : :
2461 : 128 : nvername = MAX (nvername,
2462 : : (size_t) (aux->vna_other & 0x7fff));
2463 : :
2464 : 128 : auxoffset += aux->vna_next;
2465 : : }
2466 : :
2467 : 83 : offset += need->vn_next;
2468 : : }
2469 : : }
2470 : :
2471 : : /* This is the number of versions we know about. */
2472 : 26 : ++nvername;
2473 : :
2474 : : /* Allocate the array. */
2475 : 26 : vername = (const char **) alloca (nvername * sizeof (const char *));
2476 : 26 : filename = (const char **) alloca (nvername * sizeof (const char *));
2477 : :
2478 : : /* Run through the data structures again and collect the strings. */
2479 [ + + ]: 26 : if (defscn != NULL)
2480 : : {
2481 : : /* Run through the version definitions and find the highest
2482 : : index. */
2483 : 14 : unsigned int offset = 0;
2484 : : Elf_Data *defdata;
2485 : : GElf_Shdr defshdrmem;
2486 : : GElf_Shdr *defshdr;
2487 : :
2488 : 14 : defdata = elf_getdata (defscn, NULL);
2489 [ + - ]: 14 : if (unlikely (defdata == NULL))
2490 : : return;
2491 : :
2492 : 14 : defshdr = gelf_getshdr (defscn, &defshdrmem);
2493 [ + - ]: 14 : if (unlikely (defshdr == NULL))
2494 : : return;
2495 : :
2496 [ + + ]: 61 : for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
2497 : : {
2498 : :
2499 : : /* Get the data at the next offset. */
2500 : : GElf_Verdef defmem;
2501 : 47 : GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
2502 : : GElf_Verdaux auxmem;
2503 : 47 : GElf_Verdaux *aux = gelf_getverdaux (defdata,
2504 : 47 : offset + def->vd_aux,
2505 : : &auxmem);
2506 [ + - ]: 47 : if (unlikely (def == NULL || aux == NULL))
2507 : : break;
2508 : :
2509 : 47 : vername[def->vd_ndx & 0x7fff]
2510 : 47 : = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name);
2511 : 47 : filename[def->vd_ndx & 0x7fff] = NULL;
2512 : :
2513 : 47 : offset += def->vd_next;
2514 : : }
2515 : : }
2516 [ + - ]: 26 : if (needscn != NULL)
2517 : : {
2518 : 26 : unsigned int offset = 0;
2519 : :
2520 : 26 : Elf_Data *needdata = elf_getdata (needscn, NULL);
2521 : : GElf_Shdr needshdrmem;
2522 : 26 : GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
2523 [ + - ]: 26 : if (unlikely (needdata == NULL || needshdr == NULL))
2524 : : return;
2525 : :
2526 [ + + ]: 109 : for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
2527 : : {
2528 : : /* Get the data at the next offset. */
2529 : : GElf_Verneed needmem;
2530 : 83 : GElf_Verneed *need = gelf_getverneed (needdata, offset,
2531 : : &needmem);
2532 [ + - ]: 83 : if (unlikely (need == NULL))
2533 : : break;
2534 : :
2535 : : /* Run through the auxiliary entries. */
2536 : 83 : unsigned int auxoffset = offset + need->vn_aux;
2537 [ + + ]: 211 : for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
2538 : : {
2539 : : GElf_Vernaux auxmem;
2540 : 128 : GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
2541 : : &auxmem);
2542 [ + - ]: 128 : if (unlikely (aux == NULL))
2543 : : break;
2544 : :
2545 : 128 : vername[aux->vna_other & 0x7fff]
2546 : 128 : = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name);
2547 : 128 : filename[aux->vna_other & 0x7fff]
2548 : 128 : = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file);
2549 : :
2550 : 128 : auxoffset += aux->vna_next;
2551 : : }
2552 : :
2553 : 83 : offset += need->vn_next;
2554 : : }
2555 : : }
2556 : : }
2557 : : else
2558 : : {
2559 : : vername = NULL;
2560 : : nvername = 1;
2561 : : filename = NULL;
2562 : : }
2563 : :
2564 : : /* Print the header. */
2565 : : GElf_Shdr glink;
2566 [ + - ]: 52 : printf (ngettext ("\
2567 : : \nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
2568 : : "\
2569 : : \nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
2570 : : shdr->sh_size / shdr->sh_entsize),
2571 : 26 : (unsigned int) elf_ndxscn (scn),
2572 : 26 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2573 : 26 : (int) (shdr->sh_size / shdr->sh_entsize),
2574 : : class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2575 : : shdr->sh_offset,
2576 : : (unsigned int) shdr->sh_link,
2577 : : elf_strptr (ebl->elf, shstrndx,
2578 : 26 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2579 : 26 : &glink)->sh_name));
2580 : :
2581 : : /* Now we can finally look at the actual contents of this section. */
2582 [ + + ]: 2141 : for (unsigned int cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
2583 : : {
2584 [ + + ]: 2115 : if (cnt % 2 == 0)
2585 : 1065 : printf ("\n %4d:", cnt);
2586 : :
2587 : : GElf_Versym symmem;
2588 : 2115 : GElf_Versym *sym = gelf_getversym (data, cnt, &symmem);
2589 [ + - ]: 2115 : if (sym == NULL)
2590 : : break;
2591 : :
2592 [ + + + ]: 2115 : switch (*sym)
2593 : : {
2594 : : ssize_t n;
2595 : : case 0:
2596 : 185 : fputs_unlocked (gettext (" 0 *local* "),
2597 : : stdout);
2598 : : break;
2599 : :
2600 : : case 1:
2601 : 256 : fputs_unlocked (gettext (" 1 *global* "),
2602 : : stdout);
2603 : : break;
2604 : :
2605 : : default:
2606 [ + - ][ + + ]: 1674 : n = printf ("%4d%c%s",
2607 : 1674 : *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ',
2608 : 1674 : (unsigned int) (*sym & 0x7fff) < nvername
2609 : 1674 : ? vername[*sym & 0x7fff] : "???");
2610 [ + - ]: 1674 : if ((unsigned int) (*sym & 0x7fff) < nvername
2611 [ + + ]: 1674 : && filename[*sym & 0x7fff] != NULL)
2612 : 1316 : n += printf ("(%s)", filename[*sym & 0x7fff]);
2613 : 1674 : printf ("%*s", MAX (0, 33 - (int) n), " ");
2614 : : break;
2615 : : }
2616 : : }
2617 : : putchar_unlocked ('\n');
2618 : : }
2619 : :
2620 : :
2621 : : static void
2622 : 26 : print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
2623 : : uint_fast32_t maxlength, Elf32_Word nbucket,
2624 : : uint_fast32_t nsyms, uint32_t *lengths, const char *extrastr)
2625 : : {
2626 : 26 : uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
2627 : :
2628 [ + + ]: 537 : for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2629 : 511 : ++counts[lengths[cnt]];
2630 : :
2631 : : GElf_Shdr glink;
2632 [ + - ]: 78 : printf (ngettext ("\
2633 : : \nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2634 : : "\
2635 : : \nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2636 : : nbucket),
2637 : 26 : (unsigned int) elf_ndxscn (scn),
2638 : 26 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2639 : : (int) nbucket,
2640 : 26 : gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
2641 : : shdr->sh_addr,
2642 : : shdr->sh_offset,
2643 : : (unsigned int) shdr->sh_link,
2644 : : elf_strptr (ebl->elf, shstrndx,
2645 : 26 : gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2646 : 26 : &glink)->sh_name));
2647 : :
2648 [ + - ]: 26 : if (extrastr != NULL)
2649 : 26 : fputs (extrastr, stdout);
2650 : :
2651 [ + - ]: 26 : if (likely (nbucket > 0))
2652 : : {
2653 : 26 : uint64_t success = 0;
2654 : :
2655 : : /* xgettext:no-c-format */
2656 : 26 : fputs_unlocked (gettext ("\
2657 : : Length Number % of total Coverage\n"), stdout);
2658 : 26 : printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
2659 : 26 : counts[0], (counts[0] * 100.0) / nbucket);
2660 : :
2661 : 26 : uint64_t nzero_counts = 0;
2662 [ + + ]: 107 : for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2663 : : {
2664 : 81 : nzero_counts += counts[cnt] * cnt;
2665 : 81 : printf (gettext ("\
2666 : : %7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
2667 : 81 : (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
2668 : 81 : (nzero_counts * 100.0) / nsyms);
2669 : : }
2670 : :
2671 : : Elf32_Word acc = 0;
2672 [ + + ]: 107 : for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2673 : : {
2674 : 81 : acc += cnt;
2675 : 81 : success += counts[cnt] * acc;
2676 : : }
2677 : :
2678 : 26 : printf (gettext ("\
2679 : : Average number of tests: successful lookup: %f\n\
2680 : : unsuccessful lookup: %f\n"),
2681 : 26 : (double) success / (double) nzero_counts,
2682 : 26 : (double) nzero_counts / (double) nbucket);
2683 : : }
2684 : :
2685 : 26 : free (counts);
2686 : 26 : }
2687 : :
2688 : :
2689 : : /* This function handles the traditional System V-style hash table format. */
2690 : : static void
2691 : 0 : handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2692 : : {
2693 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
2694 [ # # ]: 0 : if (unlikely (data == NULL))
2695 : : {
2696 : 0 : error (0, 0, gettext ("cannot get data for section %d: %s"),
2697 : 0 : (int) elf_ndxscn (scn), elf_errmsg (-1));
2698 : 0 : return;
2699 : : }
2700 : :
2701 : 0 : Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
2702 : 0 : Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
2703 : 0 : Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
2704 : 0 : Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
2705 : :
2706 : 0 : uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2707 : :
2708 : 0 : uint_fast32_t maxlength = 0;
2709 : 0 : uint_fast32_t nsyms = 0;
2710 [ # # ]: 0 : for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2711 : : {
2712 : 0 : Elf32_Word inner = bucket[cnt];
2713 [ # # ]: 0 : while (inner > 0 && inner < nchain)
2714 : : {
2715 : 0 : ++nsyms;
2716 [ # # ]: 0 : if (maxlength < ++lengths[cnt])
2717 : 0 : ++maxlength;
2718 : :
2719 : 0 : inner = chain[inner];
2720 : : }
2721 : : }
2722 : :
2723 : 0 : print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
2724 : : lengths, NULL);
2725 : :
2726 : 0 : free (lengths);
2727 : : }
2728 : :
2729 : :
2730 : : /* This function handles the incorrect, System V-style hash table
2731 : : format some 64-bit architectures use. */
2732 : : static void
2733 : 0 : handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2734 : : {
2735 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
2736 [ # # ]: 0 : if (unlikely (data == NULL))
2737 : : {
2738 : 0 : error (0, 0, gettext ("cannot get data for section %d: %s"),
2739 : 0 : (int) elf_ndxscn (scn), elf_errmsg (-1));
2740 : 0 : return;
2741 : : }
2742 : :
2743 : 0 : Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
2744 : 0 : Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
2745 : 0 : Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
2746 : 0 : Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
2747 : :
2748 : 0 : uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2749 : :
2750 : 0 : uint_fast32_t maxlength = 0;
2751 : 0 : uint_fast32_t nsyms = 0;
2752 [ # # ]: 0 : for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
2753 : : {
2754 : 0 : Elf64_Xword inner = bucket[cnt];
2755 [ # # ]: 0 : while (inner > 0 && inner < nchain)
2756 : : {
2757 : 0 : ++nsyms;
2758 [ # # ]: 0 : if (maxlength < ++lengths[cnt])
2759 : 0 : ++maxlength;
2760 : :
2761 : 0 : inner = chain[inner];
2762 : : }
2763 : : }
2764 : :
2765 : 0 : print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
2766 : : lengths, NULL);
2767 : :
2768 : 0 : free (lengths);
2769 : : }
2770 : :
2771 : :
2772 : : /* This function handles the GNU-style hash table format. */
2773 : : static void
2774 : 26 : handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2775 : : {
2776 : 26 : Elf_Data *data = elf_getdata (scn, NULL);
2777 [ - + ]: 26 : if (unlikely (data == NULL))
2778 : : {
2779 : 0 : error (0, 0, gettext ("cannot get data for section %d: %s"),
2780 : 0 : (int) elf_ndxscn (scn), elf_errmsg (-1));
2781 : 26 : return;
2782 : : }
2783 : :
2784 : 26 : Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
2785 : 26 : Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
2786 : :
2787 : : /* Next comes the size of the bitmap. It's measured in words for
2788 : : the architecture. It's 32 bits for 32 bit archs, and 64 bits for
2789 : : 64 bit archs. */
2790 : 26 : Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
2791 [ + - ]: 26 : if (gelf_getclass (ebl->elf) == ELFCLASS64)
2792 : 26 : bitmask_words *= 2;
2793 : :
2794 : 26 : Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
2795 : :
2796 : 26 : uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2797 : :
2798 : 26 : Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
2799 : 26 : Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
2800 : 26 : Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[4 + bitmask_words
2801 : 26 : + nbucket];
2802 : :
2803 : : /* Compute distribution of chain lengths. */
2804 : 26 : uint_fast32_t maxlength = 0;
2805 : 26 : uint_fast32_t nsyms = 0;
2806 [ + + ]: 537 : for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2807 [ + + ]: 511 : if (bucket[cnt] != 0)
2808 : : {
2809 : 357 : Elf32_Word inner = bucket[cnt] - symbias;
2810 : : do
2811 : : {
2812 : 653 : ++nsyms;
2813 [ + + ]: 653 : if (maxlength < ++lengths[cnt])
2814 : 81 : ++maxlength;
2815 : : }
2816 [ + + ]: 653 : while ((chain[inner++] & 1) == 0);
2817 : : }
2818 : :
2819 : : /* Count bits in bitmask. */
2820 : : uint_fast32_t nbits = 0;
2821 [ + + ]: 212 : for (Elf32_Word cnt = 0; cnt < bitmask_words; ++cnt)
2822 : : {
2823 : 186 : uint_fast32_t word = bitmask[cnt];
2824 : :
2825 : 186 : word = (word & 0x55555555) + ((word >> 1) & 0x55555555);
2826 : 186 : word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
2827 : 186 : word = (word & 0x0f0f0f0f) + ((word >> 4) & 0x0f0f0f0f);
2828 : 186 : word = (word & 0x00ff00ff) + ((word >> 8) & 0x00ff00ff);
2829 : 186 : nbits += (word & 0x0000ffff) + ((word >> 16) & 0x0000ffff);
2830 : : }
2831 : :
2832 : : char *str;
2833 [ - + ]: 26 : if (unlikely (asprintf (&str, gettext ("\
2834 : : Symbol Bias: %u\n\
2835 : : Bitmask Size: %zu bytes %" PRIuFAST32 "%% bits set 2nd hash shift: %u\n"),
2836 : : (unsigned int) symbias,
2837 : : bitmask_words * sizeof (Elf32_Word),
2838 : : ((nbits * 100 + 50)
2839 : : / (uint_fast32_t) (bitmask_words
2840 : : * sizeof (Elf32_Word) * 8)),
2841 : : (unsigned int) shift) == -1))
2842 : 0 : error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
2843 : :
2844 : 26 : print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
2845 : : lengths, str);
2846 : :
2847 : 26 : free (str);
2848 : 26 : free (lengths);
2849 : : }
2850 : :
2851 : :
2852 : : /* Find the symbol table(s). For this we have to search through the
2853 : : section table. */
2854 : : static void
2855 : 36 : handle_hash (Ebl *ebl)
2856 : : {
2857 : : /* Get the section header string table index. */
2858 : : size_t shstrndx;
2859 [ + - ]: 36 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2860 : : error (EXIT_FAILURE, 0,
2861 : 0 : gettext ("cannot get section header string table index"));
2862 : :
2863 : : Elf_Scn *scn = NULL;
2864 [ + + ]: 1159 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2865 : : {
2866 : : /* Handle the section if it is a symbol table. */
2867 : : GElf_Shdr shdr_mem;
2868 : 1123 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2869 : :
2870 [ + - ]: 1123 : if (likely (shdr != NULL))
2871 : : {
2872 [ - + ]: 1123 : if (shdr->sh_type == SHT_HASH)
2873 : : {
2874 [ # # ]: 0 : if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
2875 : 0 : handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
2876 : : else
2877 : 0 : handle_sysv_hash (ebl, scn, shdr, shstrndx);
2878 : : }
2879 [ + + ]: 1123 : else if (shdr->sh_type == SHT_GNU_HASH)
2880 : 1123 : handle_gnu_hash (ebl, scn, shdr, shstrndx);
2881 : : }
2882 : : }
2883 : 36 : }
2884 : :
2885 : :
2886 : : static void
2887 : 36 : print_liblist (Ebl *ebl)
2888 : : {
2889 : : /* Find the library list sections. For this we have to search
2890 : : through the section table. */
2891 : 36 : Elf_Scn *scn = NULL;
2892 : :
2893 : : /* Get the section header string table index. */
2894 : : size_t shstrndx;
2895 [ + - ]: 36 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2896 : : error (EXIT_FAILURE, 0,
2897 : 0 : gettext ("cannot get section header string table index"));
2898 : :
2899 [ + + ]: 1159 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2900 : : {
2901 : : GElf_Shdr shdr_mem;
2902 : 1123 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2903 : :
2904 [ + - ][ - + ]: 1123 : if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST)
2905 : : {
2906 : 0 : int nentries = shdr->sh_size / shdr->sh_entsize;
2907 : 0 : printf (ngettext ("\
2908 : : \nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
2909 : : "\
2910 : : \nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
2911 : : nentries),
2912 : : elf_ndxscn (scn),
2913 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2914 : : shdr->sh_offset,
2915 : : nentries);
2916 : :
2917 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
2918 [ # # ]: 0 : if (data == NULL)
2919 : 36 : return;
2920 : :
2921 : 0 : puts (gettext ("\
2922 : : Library Time Stamp Checksum Version Flags"));
2923 : :
2924 [ # # ]: 1123 : for (int cnt = 0; cnt < nentries; ++cnt)
2925 : : {
2926 : : GElf_Lib lib_mem;
2927 : 0 : GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
2928 [ # # ]: 0 : if (unlikely (lib == NULL))
2929 : 0 : continue;
2930 : :
2931 : 0 : time_t t = (time_t) lib->l_time_stamp;
2932 : 0 : struct tm *tm = gmtime (&t);
2933 [ # # ]: 0 : if (unlikely (tm == NULL))
2934 : 0 : continue;
2935 : :
2936 : 0 : printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
2937 : 0 : cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name),
2938 : 0 : tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
2939 : : tm->tm_hour, tm->tm_min, tm->tm_sec,
2940 : : (unsigned int) lib->l_checksum,
2941 : : (unsigned int) lib->l_version,
2942 : : (unsigned int) lib->l_flags);
2943 : : }
2944 : : }
2945 : : }
2946 : : }
2947 : :
2948 : : static void
2949 : 36 : print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
2950 : : {
2951 : : /* Find the object attributes sections. For this we have to search
2952 : : through the section table. */
2953 : 36 : Elf_Scn *scn = NULL;
2954 : :
2955 : : /* Get the section header string table index. */
2956 : : size_t shstrndx;
2957 [ + - ]: 36 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2958 : : error (EXIT_FAILURE, 0,
2959 : 0 : gettext ("cannot get section header string table index"));
2960 : :
2961 [ + + ]: 1159 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2962 : : {
2963 : : GElf_Shdr shdr_mem;
2964 : 1123 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2965 : :
2966 [ + - ][ + - ]: 1123 : if (shdr == NULL || (shdr->sh_type != SHT_GNU_ATTRIBUTES
2967 [ - + ]: 1123 : && (shdr->sh_type != SHT_ARM_ATTRIBUTES
2968 [ # # ]: 0 : || ehdr->e_machine != EM_ARM)))
2969 : 1123 : continue;
2970 : :
2971 : 0 : printf (gettext ("\
2972 : : \nObject attributes section [%2zu] '%s' of %" PRIu64
2973 : : " bytes at offset %#0" PRIx64 ":\n"),
2974 : : elf_ndxscn (scn),
2975 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2976 : : shdr->sh_size, shdr->sh_offset);
2977 : :
2978 : 0 : Elf_Data *data = elf_rawdata (scn, NULL);
2979 [ # # ]: 0 : if (data == NULL)
2980 : : return;
2981 : :
2982 : 0 : const unsigned char *p = data->d_buf;
2983 : :
2984 [ # # ]: 0 : if (unlikely (*p++ != 'A'))
2985 : : return;
2986 : :
2987 : 0 : fputs_unlocked (gettext (" Owner Size\n"), stdout);
2988 : :
2989 : : inline size_t left (void)
2990 : : {
2991 : 0 : return (const unsigned char *) data->d_buf + data->d_size - p;
2992 : : }
2993 : :
2994 [ # # ]: 1123 : while (left () >= 4)
2995 : : {
2996 : : uint32_t len;
2997 : 0 : memcpy (&len, p, sizeof len);
2998 : :
2999 [ # # ]: 0 : if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3000 [ # # ]: 0 : CONVERT (len);
3001 : :
3002 [ # # ]: 0 : if (unlikely (len > left ()))
3003 : : break;
3004 : :
3005 : 0 : const unsigned char *name = p + sizeof len;
3006 : 0 : p += len;
3007 : :
3008 : 0 : unsigned const char *q = memchr (name, '\0', len);
3009 [ # # ]: 0 : if (unlikely (q == NULL))
3010 : 0 : continue;
3011 : 0 : ++q;
3012 : :
3013 : 0 : printf (gettext (" %-13s %4" PRIu32 "\n"), name, len);
3014 : :
3015 [ # # ]: 0 : if (shdr->sh_type != SHT_GNU_ATTRIBUTES
3016 [ # # ]: 0 : || (q - name == sizeof "gnu"
3017 [ # # ]: 0 : && !memcmp (name, "gnu", sizeof "gnu")))
3018 [ # # ]: 0 : while (q < p)
3019 : : {
3020 : 0 : const unsigned char *const sub = q;
3021 : :
3022 : : unsigned int subsection_tag;
3023 [ # # ]: 0 : get_uleb128 (subsection_tag, q);
3024 [ # # ]: 0 : if (unlikely (q >= p))
3025 : : break;
3026 : :
3027 : : uint32_t subsection_len;
3028 [ # # ]: 0 : if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len))
3029 : : break;
3030 : :
3031 : 0 : memcpy (&subsection_len, q, sizeof subsection_len);
3032 : :
3033 [ # # ]: 0 : if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3034 [ # # ]: 0 : CONVERT (subsection_len);
3035 : :
3036 [ # # ]: 0 : if (unlikely (p - sub < (ptrdiff_t) subsection_len))
3037 : : break;
3038 : :
3039 : 0 : const unsigned char *r = q + sizeof subsection_len;
3040 : 0 : q = sub + subsection_len;
3041 : :
3042 [ # # ]: 0 : switch (subsection_tag)
3043 : : {
3044 : : default:
3045 : 0 : printf (gettext (" %-4u %12" PRIu32 "\n"),
3046 : : subsection_tag, subsection_len);
3047 : : break;
3048 : :
3049 : : case 1: /* Tag_File */
3050 : 0 : printf (gettext (" File: %11" PRIu32 "\n"),
3051 : : subsection_len);
3052 : :
3053 [ # # ]: 0 : while (r < q)
3054 : : {
3055 : : unsigned int tag;
3056 [ # # ]: 0 : get_uleb128 (tag, r);
3057 [ # # ]: 0 : if (unlikely (r >= q))
3058 : : break;
3059 : :
3060 : 0 : uint64_t value = 0;
3061 : 0 : const char *string = NULL;
3062 [ # # ][ # # ]: 0 : if (tag == 32 || (tag & 1) == 0)
3063 : : {
3064 [ # # ]: 0 : get_uleb128 (value, r);
3065 [ # # ]: 0 : if (r > q)
3066 : : break;
3067 : : }
3068 [ # # ][ # # ]: 0 : if (tag == 32 || (tag & 1) != 0)
3069 : : {
3070 : 0 : r = memchr (r, '\0', q - r);
3071 [ # # ]: 0 : if (r == NULL)
3072 : : break;
3073 : 0 : ++r;
3074 : : }
3075 : :
3076 : 0 : const char *tag_name = NULL;
3077 : 0 : const char *value_name = NULL;
3078 : 0 : ebl_check_object_attribute (ebl, (const char *) name,
3079 : : tag, value,
3080 : : &tag_name, &value_name);
3081 : :
3082 [ # # ]: 0 : if (tag_name != NULL)
3083 : : {
3084 [ # # ]: 0 : if (tag == 32)
3085 : 0 : printf (gettext (" %s: %" PRId64 ", %s\n"),
3086 : : tag_name, value, string);
3087 [ # # ]: 0 : else if (string == NULL && value_name == NULL)
3088 : 0 : printf (gettext (" %s: %" PRId64 "\n"),
3089 : : tag_name, value);
3090 : : else
3091 : 0 : printf (gettext (" %s: %s\n"),
3092 : : tag_name, string ?: value_name);
3093 : : }
3094 : : else
3095 : : {
3096 [ # # ]: 0 : assert (tag != 32);
3097 : : if (string == NULL)
3098 : 0 : printf (gettext (" %u: %" PRId64 "\n"),
3099 : : tag, value);
3100 : : else
3101 : : printf (gettext (" %u: %s\n"),
3102 : : tag, string);
3103 : : }
3104 : : }
3105 : : }
3106 : : }
3107 : : }
3108 : : }
3109 : : }
3110 : :
3111 : :
3112 : : static char *
3113 : 525397 : format_dwarf_addr (Dwfl_Module *dwflmod,
3114 : : int address_size, Dwarf_Addr address)
3115 : : {
3116 : : /* See if there is a name we can give for this address. */
3117 : : GElf_Sym sym;
3118 : 525397 : const char *name = print_address_names
3119 [ + - ]: 525397 : ? dwfl_module_addrsym (dwflmod, address, &sym, NULL) : NULL;
3120 [ + + ]: 525397 : if (name != NULL)
3121 : 445080 : sym.st_value = address - sym.st_value;
3122 : :
3123 : : /* Relativize the address. */
3124 : 525397 : int n = dwfl_module_relocations (dwflmod);
3125 [ + + ]: 525397 : int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
3126 : :
3127 : : /* In an ET_REL file there is a section name to refer to. */
3128 : 525397 : const char *scn = (i < 0 ? NULL
3129 [ + + ]: 525397 : : dwfl_module_relocation_info (dwflmod, i, NULL));
3130 : :
3131 : : char *result;
3132 [ - + ]: 525397 : if ((name != NULL
3133 : 445080 : ? (sym.st_value != 0
3134 : : ? (scn != NULL
3135 : : ? (address_size == 0
3136 : 33258 : ? asprintf (&result,
3137 : 33258 : gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
3138 : : scn, address, name, sym.st_value)
3139 : 22522 : : asprintf (&result,
3140 : 22522 : gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
3141 : : scn, 2 + address_size * 2, address,
3142 : : name, sym.st_value))
3143 : : : (address_size == 0
3144 : 106556 : ? asprintf (&result,
3145 : 106556 : gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
3146 : : address, name, sym.st_value)
3147 : 259241 : : asprintf (&result,
3148 : 259241 : gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
3149 : : 2 + address_size * 2, address,
3150 : : name, sym.st_value)))
3151 : : : (scn != NULL
3152 : : ? (address_size == 0
3153 : 2234 : ? asprintf (&result,
3154 : 2234 : gettext ("%s+%#" PRIx64 " <%s>"),
3155 : : scn, address, name)
3156 : 3022 : : asprintf (&result,
3157 : 3022 : gettext ("%s+%#0*" PRIx64 " <%s>"),
3158 : : scn, 2 + address_size * 2, address, name))
3159 : : : (address_size == 0
3160 : 6004 : ? asprintf (&result,
3161 : 6004 : gettext ("%#" PRIx64 " <%s>"),
3162 : : address, name)
3163 : 12243 : : asprintf (&result,
3164 : 12243 : gettext ("%#0*" PRIx64 " <%s>"),
3165 : : 2 + address_size * 2, address, name))))
3166 : : : (scn != NULL
3167 : : ? (address_size == 0
3168 : 1734 : ? asprintf (&result,
3169 : 1734 : gettext ("%s+%#" PRIx64),
3170 : : scn, address)
3171 : 53772 : : asprintf (&result,
3172 : 53772 : gettext ("%s+%#0*" PRIx64),
3173 : : scn, 2 + address_size * 2, address))
3174 : : : (address_size == 0
3175 : 4613 : ? asprintf (&result,
3176 : : "%#" PRIx64,
3177 : : address)
3178 : 20198 : : asprintf (&result,
3179 : : "%#0*" PRIx64,
3180 [ + + ][ + + ]: 1050794 : 2 + address_size * 2, address)))) < 0)
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ]
3181 : 0 : error (EXIT_FAILURE, 0, _("memory exhausted"));
3182 : :
3183 : 525397 : return result;
3184 : : }
3185 : :
3186 : : static const char *
3187 : 788990 : dwarf_tag_string (unsigned int tag)
3188 : : {
3189 [ - + + - : 788990 : switch (tag)
- - - - +
+ - - - -
- + - + -
- - + + -
+ - - - -
- + - + -
+ + + - -
- - - - -
+ - - - -
- - - + +
+ + - - -
- - - + +
+ - + - -
+ - - - ]
3190 : : {
3191 : : #define ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
3192 : 788990 : ALL_KNOWN_DW_TAG
3193 : : #undef ONE_KNOWN_DW_TAG
3194 : : default:
3195 : 788990 : return NULL;
3196 : : }
3197 : : }
3198 : :
3199 : :
3200 : : static const char *
3201 : 2800381 : dwarf_attr_string (unsigned int attrnum)
3202 : : {
3203 [ - + - + : 2800381 : switch (attrnum)
- + - - -
- + - - -
- + - - -
- - - - -
- - - - -
- - - - -
- + - - -
+ - - - +
+ - - - +
- - + + -
- + - + -
- - - + -
- - + + +
- - - - -
- - - + -
+ - - - +
+ - + - +
+ - + + +
+ - - + -
- - + - -
- - - + +
- + - - -
- + - - -
- - - + +
- - - - +
+ - - - -
- - - + ]
3204 : : {
3205 : : #define ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
3206 : 2793104 : ALL_KNOWN_DW_AT
3207 : : #undef ONE_KNOWN_DW_AT
3208 : : default:
3209 : 2800381 : return NULL;
3210 : : }
3211 : : }
3212 : :
3213 : :
3214 : : static const char *
3215 : 2800381 : dwarf_form_string (unsigned int form)
3216 : : {
3217 [ + + - + : 2800381 : switch (form)
+ - + + +
- + + + -
- - + - -
- + + + +
+ + - + ]
3218 : : {
3219 : : #define ONE_KNOWN_DW_FORM_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_FORM (NAME, CODE)
3220 : : #define ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
3221 : 2800373 : ALL_KNOWN_DW_FORM
3222 : : #undef ONE_KNOWN_DW_FORM
3223 : : #undef ONE_KNOWN_DW_FORM_DESC
3224 : : default:
3225 : 2800381 : return NULL;
3226 : : }
3227 : : }
3228 : :
3229 : :
3230 : : static const char *
3231 : 1345 : dwarf_lang_string (unsigned int lang)
3232 : : {
3233 [ - - + - : 1345 : switch (lang)
- - - - -
- - - - -
- - - - -
- - - - ]
3234 : : {
3235 : : #define ONE_KNOWN_DW_LANG_DESC(NAME, CODE, DESC) case CODE: return #NAME;
3236 : 1345 : ALL_KNOWN_DW_LANG
3237 : : #undef ONE_KNOWN_DW_LANG_DESC
3238 : : default:
3239 : 1345 : return NULL;
3240 : : }
3241 : : }
3242 : :
3243 : :
3244 : : static const char *
3245 : : dwarf_inline_string (unsigned int code)
3246 : : {
3247 : : static const char *const known[] =
3248 : : {
3249 : : #define ONE_KNOWN_DW_INL(NAME, CODE) [CODE] = #NAME,
3250 : : ALL_KNOWN_DW_INL
3251 : : #undef ONE_KNOWN_DW_INL
3252 : : };
3253 : :
3254 [ + - ]: 1627 : if (likely (code < sizeof (known) / sizeof (known[0])))
3255 : 1627 : return known[code];
3256 : :
3257 : : return NULL;
3258 : : }
3259 : :
3260 : :
3261 : : static const char *
3262 : : dwarf_encoding_string (unsigned int code)
3263 : : {
3264 : : static const char *const known[] =
3265 : : {
3266 : : #define ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
3267 : : ALL_KNOWN_DW_ATE
3268 : : #undef ONE_KNOWN_DW_ATE
3269 : : };
3270 : :
3271 [ + - ]: 16784 : if (likely (code < sizeof (known) / sizeof (known[0])))
3272 : 16784 : return known[code];
3273 : :
3274 : : return NULL;
3275 : : }
3276 : :
3277 : :
3278 : : static const char *
3279 : : dwarf_access_string (unsigned int code)
3280 : : {
3281 : : static const char *const known[] =
3282 : : {
3283 : : #define ONE_KNOWN_DW_ACCESS(NAME, CODE) [CODE] = #NAME,
3284 : : ALL_KNOWN_DW_ACCESS
3285 : : #undef ONE_KNOWN_DW_ACCESS
3286 : : };
3287 : :
3288 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3289 : 0 : return known[code];
3290 : :
3291 : : return NULL;
3292 : : }
3293 : :
3294 : :
3295 : : static const char *
3296 : : dwarf_visibility_string (unsigned int code)
3297 : : {
3298 : : static const char *const known[] =
3299 : : {
3300 : : #define ONE_KNOWN_DW_VIS(NAME, CODE) [CODE] = #NAME,
3301 : : ALL_KNOWN_DW_VIS
3302 : : #undef ONE_KNOWN_DW_VIS
3303 : : };
3304 : :
3305 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3306 : 0 : return known[code];
3307 : :
3308 : : return NULL;
3309 : : }
3310 : :
3311 : :
3312 : : static const char *
3313 : : dwarf_virtuality_string (unsigned int code)
3314 : : {
3315 : : static const char *const known[] =
3316 : : {
3317 : : #define ONE_KNOWN_DW_VIRTUALITY(NAME, CODE) [CODE] = #NAME,
3318 : : ALL_KNOWN_DW_VIRTUALITY
3319 : : #undef ONE_KNOWN_DW_VIRTUALITY
3320 : : };
3321 : :
3322 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3323 : 0 : return known[code];
3324 : :
3325 : : return NULL;
3326 : : }
3327 : :
3328 : :
3329 : : static const char *
3330 : : dwarf_identifier_case_string (unsigned int code)
3331 : : {
3332 : : static const char *const known[] =
3333 : : {
3334 : : #define ONE_KNOWN_DW_ID(NAME, CODE) [CODE] = #NAME,
3335 : : ALL_KNOWN_DW_ID
3336 : : #undef ONE_KNOWN_DW_ID
3337 : : };
3338 : :
3339 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3340 : 0 : return known[code];
3341 : :
3342 : : return NULL;
3343 : : }
3344 : :
3345 : :
3346 : : static const char *
3347 : : dwarf_calling_convention_string (unsigned int code)
3348 : : {
3349 : : static const char *const known[] =
3350 : : {
3351 : : #define ONE_KNOWN_DW_CC(NAME, CODE) [CODE] = #NAME,
3352 : : ALL_KNOWN_DW_CC
3353 : : #undef ONE_KNOWN_DW_CC
3354 : : };
3355 : :
3356 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3357 : 0 : return known[code];
3358 : :
3359 : : return NULL;
3360 : : }
3361 : :
3362 : :
3363 : : static const char *
3364 : : dwarf_ordering_string (unsigned int code)
3365 : : {
3366 : : static const char *const known[] =
3367 : : {
3368 : : #define ONE_KNOWN_DW_ORD(NAME, CODE) [CODE] = #NAME,
3369 : : ALL_KNOWN_DW_ORD
3370 : : #undef ONE_KNOWN_DW_ORD
3371 : : };
3372 : :
3373 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3374 : 0 : return known[code];
3375 : :
3376 : : return NULL;
3377 : : }
3378 : :
3379 : :
3380 : : static const char *
3381 : : dwarf_discr_list_string (unsigned int code)
3382 : : {
3383 : : static const char *const known[] =
3384 : : {
3385 : : #define ONE_KNOWN_DW_DSC(NAME, CODE) [CODE] = #NAME,
3386 : : ALL_KNOWN_DW_DSC
3387 : : #undef ONE_KNOWN_DW_DSC
3388 : : };
3389 : :
3390 [ # # ]: 0 : if (likely (code < sizeof (known) / sizeof (known[0])))
3391 : 0 : return known[code];
3392 : :
3393 : : return NULL;
3394 : : }
3395 : :
3396 : :
3397 : : static const char *
3398 : : dwarf_locexpr_opcode_string (unsigned int code)
3399 : : {
3400 : : static const char *const known[] =
3401 : : {
3402 : : /* Normally we can't affort building huge table of 64K entries,
3403 : : most of them zero, just because there are a couple defined
3404 : : values at the far end. In case of opcodes, it's OK. */
3405 : : #define ONE_KNOWN_DW_OP_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_OP (NAME, CODE)
3406 : : #define ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
3407 : : ALL_KNOWN_DW_OP
3408 : : #undef ONE_KNOWN_DW_OP
3409 : : #undef ONE_KNOWN_DW_OP_DESC
3410 : : };
3411 : :
3412 [ + - ]: 307862 : if (likely (code < sizeof (known) / sizeof (known[0])))
3413 : 307862 : return known[code];
3414 : :
3415 : : return NULL;
3416 : : }
3417 : :
3418 : :
3419 : : /* Used by all dwarf_foo_name functions. */
3420 : : static const char *
3421 : 6409508 : string_or_unknown (const char *known, unsigned int code,
3422 : : unsigned int lo_user, unsigned int hi_user,
3423 : : bool print_unknown_num)
3424 : : {
3425 : : static char unknown_buf[20];
3426 : :
3427 [ - + ]: 6409508 : if (likely (known != NULL))
3428 : : return known;
3429 : :
3430 [ # # ][ # # ]: 0 : if (lo_user != 0 && code >= lo_user && code <= hi_user)
3431 : : {
3432 : 0 : snprintf (unknown_buf, sizeof unknown_buf, "lo_user+%#x",
3433 : : code - lo_user);
3434 : 0 : return unknown_buf;
3435 : : }
3436 : :
3437 [ # # ]: 0 : if (print_unknown_num)
3438 : : {
3439 : 0 : snprintf (unknown_buf, sizeof unknown_buf, "??? (%#x)", code);
3440 : 6409508 : return unknown_buf;
3441 : : }
3442 : :
3443 : : return "???";
3444 : : }
3445 : :
3446 : :
3447 : : static const char *
3448 : 788990 : dwarf_tag_name (unsigned int tag)
3449 : : {
3450 : 788990 : const char *ret = dwarf_tag_string (tag);
3451 : 788990 : return string_or_unknown (ret, tag, DW_TAG_lo_user, DW_TAG_hi_user, true);
3452 : : }
3453 : :
3454 : : static const char *
3455 : 2800381 : dwarf_attr_name (unsigned int attr)
3456 : : {
3457 : 2800381 : const char *ret = dwarf_attr_string (attr);
3458 : 2800381 : return string_or_unknown (ret, attr, DW_AT_lo_user, DW_AT_hi_user, true);
3459 : : }
3460 : :
3461 : :
3462 : : static const char *
3463 : 2800381 : dwarf_form_name (unsigned int form)
3464 : : {
3465 : 2800381 : const char *ret = dwarf_form_string (form);
3466 : 2800381 : return string_or_unknown (ret, form, 0, 0, true);
3467 : : }
3468 : :
3469 : :
3470 : : static const char *
3471 : 1345 : dwarf_lang_name (unsigned int lang)
3472 : : {
3473 : 1345 : const char *ret = dwarf_lang_string (lang);
3474 : 1345 : return string_or_unknown (ret, lang, DW_LANG_lo_user, DW_LANG_hi_user, false);
3475 : : }
3476 : :
3477 : :
3478 : : static const char *
3479 : 1627 : dwarf_inline_name (unsigned int code)
3480 : : {
3481 : 1627 : const char *ret = dwarf_inline_string (code);
3482 : 1627 : return string_or_unknown (ret, code, 0, 0, false);
3483 : : }
3484 : :
3485 : :
3486 : : static const char *
3487 : 16784 : dwarf_encoding_name (unsigned int code)
3488 : : {
3489 : 16784 : const char *ret = dwarf_encoding_string (code);
3490 : 16784 : return string_or_unknown (ret, code, DW_ATE_lo_user, DW_ATE_hi_user, false);
3491 : : }
3492 : :
3493 : :
3494 : : static const char *
3495 : 0 : dwarf_access_name (unsigned int code)
3496 : : {
3497 : 0 : const char *ret = dwarf_access_string (code);
3498 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3499 : : }
3500 : :
3501 : :
3502 : : static const char *
3503 : 0 : dwarf_visibility_name (unsigned int code)
3504 : : {
3505 : 0 : const char *ret = dwarf_visibility_string (code);
3506 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3507 : : }
3508 : :
3509 : :
3510 : : static const char *
3511 : 0 : dwarf_virtuality_name (unsigned int code)
3512 : : {
3513 : 0 : const char *ret = dwarf_virtuality_string (code);
3514 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3515 : : }
3516 : :
3517 : :
3518 : : static const char *
3519 : 0 : dwarf_identifier_case_name (unsigned int code)
3520 : : {
3521 : 0 : const char *ret = dwarf_identifier_case_string (code);
3522 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3523 : : }
3524 : :
3525 : :
3526 : : static const char *
3527 : 0 : dwarf_calling_convention_name (unsigned int code)
3528 : : {
3529 : 0 : const char *ret = dwarf_calling_convention_string (code);
3530 : 0 : return string_or_unknown (ret, code, DW_CC_lo_user, DW_CC_hi_user, false);
3531 : : }
3532 : :
3533 : :
3534 : : static const char *
3535 : 0 : dwarf_ordering_name (unsigned int code)
3536 : : {
3537 : 0 : const char *ret = dwarf_ordering_string (code);
3538 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3539 : : }
3540 : :
3541 : :
3542 : : static const char *
3543 : 0 : dwarf_discr_list_name (unsigned int code)
3544 : : {
3545 : 0 : const char *ret = dwarf_discr_list_string (code);
3546 : 0 : return string_or_unknown (ret, code, 0, 0, false);
3547 : : }
3548 : :
3549 : :
3550 : : static void
3551 : 4 : print_block (size_t n, const void *block)
3552 : : {
3553 [ - + ]: 4 : if (n == 0)
3554 : 0 : puts (_("empty block"));
3555 : : else
3556 : : {
3557 : 4 : printf (_("%zu byte block:"), n);
3558 : 4 : const unsigned char *data = block;
3559 : : do
3560 : 1232 : printf (" %02x", *data++);
3561 [ + + ]: 1232 : while (--n > 0);
3562 : : putchar ('\n');
3563 : : }
3564 : 4 : }
3565 : :
3566 : : static void
3567 : 234268 : print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
3568 : : unsigned int vers, unsigned int addrsize, unsigned int offset_size,
3569 : : Dwarf_Word len, const unsigned char *data)
3570 : : {
3571 [ + + ]: 234268 : const unsigned int ref_size = vers < 3 ? addrsize : offset_size;
3572 : :
3573 [ + - ]: 234268 : if (len == 0)
3574 : : {
3575 : 0 : printf ("%*s(empty)\n", indent, "");
3576 : 234268 : return;
3577 : : }
3578 : :
3579 : : #define NEED(n) if (len < (Dwarf_Word) (n)) goto invalid
3580 : : #define CONSUME(n) NEED (n); else len -= (n)
3581 : :
3582 : : Dwarf_Word offset = 0;
3583 [ + + ]: 542130 : while (len-- > 0)
3584 : : {
3585 : 307862 : uint_fast8_t op = *data++;
3586 : :
3587 : 615724 : const char *op_name = dwarf_locexpr_opcode_string (op);
3588 [ - + ]: 307862 : if (unlikely (op_name == NULL))
3589 : : {
3590 : : static char buf[20];
3591 [ # # ]: 0 : if (op >= DW_OP_lo_user)
3592 : 0 : snprintf (buf, sizeof buf, "lo_user+%#x", op - DW_OP_lo_user);
3593 : : else
3594 : 0 : snprintf (buf, sizeof buf, "??? (%#x)", op);
3595 : : op_name = buf;
3596 : : }
3597 : :
3598 [ + - + + : 307862 : switch (op)
+ + + + -
- + - + -
- - + - +
+ + - + +
+ + ]
3599 : : {
3600 : : case DW_OP_addr:;
3601 : : /* Address operand. */
3602 : : Dwarf_Word addr;
3603 [ + - ]: 8868 : NEED (addrsize);
3604 [ + + ]: 8868 : if (addrsize == 4)
3605 [ - + ][ # # ]: 8 : addr = read_4ubyte_unaligned (dbg, data);
3606 : : else
3607 : : {
3608 [ - + ]: 8860 : assert (addrsize == 8);
3609 [ + + ][ - + ]: 8860 : addr = read_8ubyte_unaligned (dbg, data);
3610 : : }
3611 : 8868 : data += addrsize;
3612 [ + - ]: 8868 : CONSUME (addrsize);
3613 : :
3614 : 8868 : char *a = format_dwarf_addr (dwflmod, 0, addr);
3615 : 8868 : printf ("%*s[%4" PRIuMAX "] %s %s\n",
3616 : : indent, "", (uintmax_t) offset, op_name, a);
3617 : 8868 : free (a);
3618 : :
3619 : 8868 : offset += 1 + addrsize;
3620 : 8868 : break;
3621 : :
3622 : : case DW_OP_call_ref:
3623 : : /* Offset operand. */
3624 [ # # ]: 0 : NEED (ref_size);
3625 [ # # ]: 0 : if (ref_size == 4)
3626 [ # # ][ # # ]: 0 : addr = read_4ubyte_unaligned (dbg, data);
3627 : : else
3628 : : {
3629 [ # # ]: 0 : assert (ref_size == 8);
3630 [ # # ][ # # ]: 0 : addr = read_8ubyte_unaligned (dbg, data);
3631 : : }
3632 : 0 : data += ref_size;
3633 [ # # ]: 0 : CONSUME (ref_size);
3634 : :
3635 : 0 : printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
3636 : : indent, "", (uintmax_t) offset,
3637 : : op_name, (uintmax_t) addr);
3638 : 0 : offset += 1 + ref_size;
3639 : 0 : break;
3640 : :
3641 : : case DW_OP_deref_size:
3642 : : case DW_OP_xderef_size:
3643 : : case DW_OP_pick:
3644 : : case DW_OP_const1u:
3645 : : // XXX value might be modified by relocation
3646 [ + - ]: 6863 : NEED (1);
3647 : 6863 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
3648 : : indent, "", (uintmax_t) offset,
3649 : 6863 : op_name, *((uint8_t *) data));
3650 : 6863 : ++data;
3651 : 6863 : --len;
3652 : 6863 : offset += 2;
3653 : 6863 : break;
3654 : :
3655 : : case DW_OP_const2u:
3656 [ + - ]: 1206 : NEED (2);
3657 : : // XXX value might be modified by relocation
3658 [ - + ]: 1206 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
3659 : : indent, "", (uintmax_t) offset,
3660 [ # # ]: 0 : op_name, read_2ubyte_unaligned (dbg, data));
3661 [ + - ]: 1206 : CONSUME (2);
3662 : 1206 : data += 2;
3663 : 1206 : offset += 3;
3664 : 1206 : break;
3665 : :
3666 : : case DW_OP_const4u:
3667 [ + - ]: 785 : NEED (4);
3668 : : // XXX value might be modified by relocation
3669 [ - + ]: 785 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
3670 : : indent, "", (uintmax_t) offset,
3671 [ # # ]: 0 : op_name, read_4ubyte_unaligned (dbg, data));
3672 [ + - ]: 785 : CONSUME (4);
3673 : 785 : data += 4;
3674 : 785 : offset += 5;
3675 : 785 : break;
3676 : :
3677 : : case DW_OP_const8u:
3678 [ + - ]: 105 : NEED (8);
3679 : : // XXX value might be modified by relocation
3680 [ - + ]: 105 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
3681 : : indent, "", (uintmax_t) offset,
3682 [ # # ]: 0 : op_name, (uint64_t) read_8ubyte_unaligned (dbg, data));
3683 [ + - ]: 105 : CONSUME (8);
3684 : 105 : data += 8;
3685 : 105 : offset += 9;
3686 : 105 : break;
3687 : :
3688 : : case DW_OP_const1s:
3689 [ + - ]: 906 : NEED (1);
3690 : : // XXX value might be modified by relocation
3691 : 906 : printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
3692 : : indent, "", (uintmax_t) offset,
3693 : 906 : op_name, *((int8_t *) data));
3694 : 906 : ++data;
3695 : 906 : --len;
3696 : 906 : offset += 2;
3697 : 906 : break;
3698 : :
3699 : : case DW_OP_const2s:
3700 [ + - ]: 5 : NEED (2);
3701 : : // XXX value might be modified by relocation
3702 [ - + ]: 5 : printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
3703 : : indent, "", (uintmax_t) offset,
3704 [ # # ]: 0 : op_name, read_2sbyte_unaligned (dbg, data));
3705 [ + - ]: 5 : CONSUME (2);
3706 : 5 : data += 2;
3707 : 5 : offset += 3;
3708 : 5 : break;
3709 : :
3710 : : case DW_OP_const4s:
3711 [ # # ]: 0 : NEED (4);
3712 : : // XXX value might be modified by relocation
3713 [ # # ]: 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
3714 : : indent, "", (uintmax_t) offset,
3715 [ # # ]: 0 : op_name, read_4sbyte_unaligned (dbg, data));
3716 [ # # ]: 0 : CONSUME (4);
3717 : 0 : data += 4;
3718 : 0 : offset += 5;
3719 : 0 : break;
3720 : :
3721 : : case DW_OP_const8s:
3722 [ # # ]: 0 : NEED (8);
3723 : : // XXX value might be modified by relocation
3724 [ # # ]: 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
3725 : : indent, "", (uintmax_t) offset,
3726 [ # # ]: 0 : op_name, read_8sbyte_unaligned (dbg, data));
3727 [ # # ]: 0 : CONSUME (8);
3728 : 0 : data += 8;
3729 : 0 : offset += 9;
3730 : 0 : break;
3731 : :
3732 : : case DW_OP_piece:
3733 : : case DW_OP_regx:
3734 : : case DW_OP_plus_uconst:
3735 : : case DW_OP_constu:;
3736 : 3197 : const unsigned char *start = data;
3737 : : uint64_t uleb;
3738 [ + - ]: 3197 : NEED (1);
3739 [ + + ]: 3533 : get_uleb128 (uleb, data); /* XXX check overrun */
3740 : 3197 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
3741 : : indent, "", (uintmax_t) offset, op_name, uleb);
3742 [ + - ]: 3197 : CONSUME (data - start);
3743 : 3197 : offset += 1 + (data - start);
3744 : 3197 : break;
3745 : :
3746 : : case DW_OP_bit_piece:
3747 : 0 : start = data;
3748 : : uint64_t uleb2;
3749 [ # # ]: 0 : NEED (2);
3750 [ # # ]: 0 : get_uleb128 (uleb, data); /* XXX check overrun */
3751 [ # # ]: 0 : get_uleb128 (uleb2, data); /* XXX check overrun */
3752 : 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n",
3753 : : indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
3754 [ # # ]: 0 : CONSUME (data - start);
3755 : 0 : offset += 1 + (data - start);
3756 : 0 : break;
3757 : :
3758 : : case DW_OP_fbreg:
3759 : : case DW_OP_breg0 ... DW_OP_breg31:
3760 : : case DW_OP_consts:
3761 : 60721 : start = data;
3762 : : int64_t sleb;
3763 [ + - ]: 60721 : NEED (1);
3764 [ + + ]: 60721 : get_sleb128 (sleb, data); /* XXX check overrun */
3765 : 60721 : printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
3766 : : indent, "", (uintmax_t) offset, op_name, sleb);
3767 [ + - ]: 60721 : CONSUME (data - start);
3768 : 60721 : offset += 1 + (data - start);
3769 : 60721 : break;
3770 : :
3771 : : case DW_OP_bregx:
3772 : 0 : start = data;
3773 [ # # ]: 0 : NEED (2);
3774 [ # # ]: 0 : get_uleb128 (uleb, data); /* XXX check overrun */
3775 [ # # ]: 0 : get_sleb128 (sleb, data); /* XXX check overrun */
3776 : 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n",
3777 : : indent, "", (uintmax_t) offset, op_name, uleb, sleb);
3778 [ # # ]: 0 : CONSUME (data - start);
3779 : 0 : offset += 1 + (data - start);
3780 : 0 : break;
3781 : :
3782 : : case DW_OP_call2:
3783 [ # # ]: 0 : NEED (2);
3784 [ # # ]: 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
3785 : : indent, "", (uintmax_t) offset, op_name,
3786 [ # # ]: 0 : read_2ubyte_unaligned (dbg, data));
3787 [ # # ]: 0 : CONSUME (2);
3788 : 0 : offset += 3;
3789 : 0 : break;
3790 : :
3791 : : case DW_OP_call4:
3792 [ # # ]: 0 : NEED (4);
3793 [ # # ]: 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
3794 : : indent, "", (uintmax_t) offset, op_name,
3795 [ # # ]: 0 : read_4ubyte_unaligned (dbg, data));
3796 [ # # ]: 0 : CONSUME (4);
3797 : 0 : offset += 5;
3798 : 0 : break;
3799 : :
3800 : : case DW_OP_skip:
3801 : : case DW_OP_bra:
3802 [ + - ]: 98 : NEED (2);
3803 [ - + ]: 98 : printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
3804 : : indent, "", (uintmax_t) offset, op_name,
3805 [ # # ]: 0 : (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data)));
3806 [ + - ]: 98 : CONSUME (2);
3807 : 98 : data += 2;
3808 : 98 : offset += 3;
3809 : 98 : break;
3810 : :
3811 : : case DW_OP_implicit_value:
3812 : 0 : start = data;
3813 [ # # ]: 0 : NEED (1);
3814 [ # # ]: 0 : get_uleb128 (uleb, data); /* XXX check overrun */
3815 : 0 : printf ("%*s[%4" PRIuMAX "] %s: ",
3816 : : indent, "", (uintmax_t) offset, op_name);
3817 [ # # ]: 0 : NEED (uleb);
3818 : 0 : print_block (uleb, data);
3819 : 0 : data += uleb;
3820 [ # # ]: 0 : CONSUME (data - start);
3821 : 0 : offset += 1 + (data - start);
3822 : 0 : break;
3823 : :
3824 : : case DW_OP_GNU_implicit_pointer:
3825 : : /* DIE offset operand. */
3826 : 440 : start = data;
3827 [ + - ]: 440 : NEED (ref_size + 1);
3828 [ + - ]: 440 : if (ref_size == 4)
3829 [ - + ][ # # ]: 440 : addr = read_4ubyte_unaligned (dbg, data);
3830 : : else
3831 : : {
3832 [ # # ]: 0 : assert (ref_size == 8);
3833 [ # # ][ # # ]: 0 : addr = read_8ubyte_unaligned (dbg, data);
3834 : : }
3835 : 440 : data += ref_size;
3836 : : /* Byte offset operand. */
3837 [ + - ]: 440 : get_sleb128 (sleb, data); /* XXX check overrun */
3838 : :
3839 : 440 : printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX ", %+" PRId64 "\n",
3840 : : indent, "", (intmax_t) offset,
3841 : : op_name, (uintmax_t) addr, sleb);
3842 [ + - ]: 440 : CONSUME (data - start);
3843 : 440 : offset += 1 + (data - start);
3844 : 440 : break;
3845 : :
3846 : : case DW_OP_GNU_entry_value:
3847 : : /* Size plus expression block. */
3848 : 15228 : start = data;
3849 [ + - ]: 15228 : NEED (1);
3850 [ - + ]: 15228 : get_uleb128 (uleb, data); /* XXX check overrun */
3851 : 15228 : printf ("%*s[%4" PRIuMAX "] %s:\n",
3852 : : indent, "", (uintmax_t) offset, op_name);
3853 [ + - ]: 15228 : NEED (uleb);
3854 : 15228 : print_ops (dwflmod, dbg, indent + 6, indent + 6, vers,
3855 : : addrsize, offset_size, uleb, data);
3856 : 15228 : data += uleb;
3857 [ + - ]: 15228 : CONSUME (data - start);
3858 : 15228 : offset += 1 + (data - start);
3859 : 15228 : break;
3860 : :
3861 : : case DW_OP_GNU_const_type:
3862 : : /* DIE offset, size plus block. */
3863 : 1 : start = data;
3864 [ + - ]: 1 : NEED (2);
3865 [ - + ]: 1 : get_uleb128 (uleb, data); /* XXX check overrun */
3866 : 1 : uint8_t usize = *(uint8_t *) data++;
3867 [ + - ]: 1 : NEED (usize);
3868 : 1 : printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] ",
3869 : : indent, "", (uintmax_t) offset, op_name, uleb);
3870 : 1 : print_block (usize, data);
3871 : 1 : data += usize;
3872 [ + - ]: 1 : CONSUME (data - start);
3873 : 1 : offset += 1 + (data - start);
3874 : 1 : break;
3875 : :
3876 : : case DW_OP_GNU_regval_type:
3877 : 0 : start = data;
3878 [ # # ]: 0 : NEED (2);
3879 [ # # ]: 0 : get_uleb128 (uleb, data); /* XXX check overrun */
3880 [ # # ]: 0 : get_uleb128 (uleb2, data); /* XXX check overrun */
3881 : 0 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %#" PRIx64 "\n",
3882 : : indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
3883 [ # # ]: 0 : CONSUME (data - start);
3884 : 0 : offset += 1 + (data - start);
3885 : 0 : break;
3886 : :
3887 : : case DW_OP_GNU_deref_type:
3888 : 1 : start = data;
3889 [ + - ]: 1 : NEED (2);
3890 : 1 : usize = *(uint8_t *) data++;
3891 [ - + ]: 1 : get_uleb128 (uleb, data); /* XXX check overrun */
3892 : 1 : printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
3893 : : indent, "", (uintmax_t) offset,
3894 : : op_name, usize, uleb);
3895 [ + - ]: 1 : CONSUME (data - start);
3896 : 1 : offset += 1 + (data - start);
3897 : 1 : break;
3898 : :
3899 : : case DW_OP_GNU_convert:
3900 : : case DW_OP_GNU_reinterpret:
3901 : 23 : start = data;
3902 [ + - ]: 23 : NEED (1);
3903 [ - + ]: 23 : get_uleb128 (uleb, data); /* XXX check overrun */
3904 : 23 : printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
3905 : : indent, "", (uintmax_t) offset, op_name, uleb);
3906 [ + - ]: 23 : CONSUME (data - start);
3907 : 23 : offset += 1 + (data - start);
3908 : 23 : break;
3909 : :
3910 : : case DW_OP_GNU_parameter_ref:
3911 : : /* 4 byte CU relative reference to the abstract optimized away
3912 : : DW_TAG_formal_parameter. */
3913 [ + - ]: 151 : NEED (4);
3914 [ - + ]: 151 : printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
3915 : : indent, "", (uintmax_t) offset, op_name,
3916 [ # # ]: 0 : (uintmax_t) read_4ubyte_unaligned (dbg, data));
3917 [ + - ]: 151 : CONSUME (4);
3918 : 151 : data += 4;
3919 : 151 : offset += 5;
3920 : 151 : break;
3921 : :
3922 : : default:
3923 : : /* No Operand. */
3924 : 209264 : printf ("%*s[%4" PRIuMAX "] %s\n",
3925 : : indent, "", (uintmax_t) offset, op_name);
3926 : 209264 : ++offset;
3927 : 209264 : break;
3928 : : }
3929 : :
3930 : 307862 : indent = indentrest;
3931 : 307862 : continue;
3932 : :
3933 : : invalid:
3934 : 0 : printf (gettext ("%*s[%4" PRIuMAX "] %s <TRUNCATED>\n"),
3935 : : indent, "", (uintmax_t) offset, op_name);
3936 : 0 : break;
3937 : : }
3938 : : }
3939 : :
3940 : :
3941 : : struct listptr
3942 : : {
3943 : : Dwarf_Off offset:(64 - 3);
3944 : : bool addr64:1;
3945 : : bool dwarf64:1;
3946 : : bool warned:1;
3947 : : };
3948 : :
3949 : : #define listptr_offset_size(p) ((p)->dwarf64 ? 8 : 4)
3950 : : #define listptr_address_size(p) ((p)->addr64 ? 8 : 4)
3951 : :
3952 : : static int
3953 : 245999 : compare_listptr (const void *a, const void *b, void *arg)
3954 : : {
3955 : 245999 : const char *name = arg;
3956 : 245999 : struct listptr *p1 = (void *) a;
3957 : 245999 : struct listptr *p2 = (void *) b;
3958 : :
3959 [ + + ]: 245999 : if (p1->offset < p2->offset)
3960 : : return -1;
3961 [ + + ]: 9913 : if (p1->offset > p2->offset)
3962 : : return 1;
3963 : :
3964 [ + - ][ + - ]: 2141 : if (!p1->warned && !p2->warned)
3965 : : {
3966 [ - + ]: 2141 : if (p1->addr64 != p2->addr64)
3967 : : {
3968 : 0 : p1->warned = p2->warned = true;
3969 : 0 : error (0, 0,
3970 : 0 : gettext ("%s %#" PRIx64 " used with different address sizes"),
3971 : : name, (uint64_t) p1->offset);
3972 : : }
3973 [ - + ]: 2141 : if (p1->dwarf64 != p2->dwarf64)
3974 : : {
3975 : 0 : p1->warned = p2->warned = true;
3976 : 0 : error (0, 0,
3977 : 0 : gettext ("%s %#" PRIx64 " used with different offset sizes"),
3978 : 0 : name, (uint64_t) p1->offset);
3979 : : }
3980 : : }
3981 : :
3982 : : return 0;
3983 : : }
3984 : :
3985 : : struct listptr_table
3986 : : {
3987 : : size_t n;
3988 : : size_t alloc;
3989 : : struct listptr *table;
3990 : : };
3991 : :
3992 : : static struct listptr_table known_loclistptr;
3993 : : static struct listptr_table known_rangelistptr;
3994 : :
3995 : : static void
3996 : 90 : reset_listptr (struct listptr_table *table)
3997 : : {
3998 : 90 : free (table->table);
3999 : 90 : table->table = NULL;
4000 : 90 : table->n = table->alloc = 0;
4001 : 90 : }
4002 : :
4003 : : static void
4004 : 45293 : notice_listptr (enum section_e section, struct listptr_table *table,
4005 : : uint_fast8_t address_size, uint_fast8_t offset_size,
4006 : : Dwarf_Off offset)
4007 : : {
4008 [ + - ]: 45293 : if (print_debug_sections & section)
4009 : : {
4010 [ + + ]: 45293 : if (table->n == table->alloc)
4011 : : {
4012 [ + + ]: 166 : if (table->alloc == 0)
4013 : 57 : table->alloc = 128;
4014 : : else
4015 : 109 : table->alloc *= 2;
4016 : 166 : table->table = xrealloc (table->table,
4017 : 166 : table->alloc * sizeof table->table[0]);
4018 : : }
4019 : :
4020 : 45293 : struct listptr *p = &table->table[table->n++];
4021 : :
4022 : 90586 : *p = (struct listptr)
4023 : : {
4024 : 45293 : .addr64 = address_size == 8,
4025 : 45293 : .dwarf64 = offset_size == 8,
4026 : : .offset = offset
4027 : : };
4028 [ - + ]: 45293 : assert (p->offset == offset);
4029 : : }
4030 : 45293 : }
4031 : :
4032 : : static void
4033 : 57 : sort_listptr (struct listptr_table *table, const char *name)
4034 : : {
4035 [ + - ]: 57 : if (table->n > 0)
4036 : 57 : qsort_r (table->table, table->n, sizeof table->table[0],
4037 : : &compare_listptr, (void *) name);
4038 : 57 : }
4039 : :
4040 : : static bool
4041 : 43167 : skip_listptr_hole (struct listptr_table *table, size_t *idxp,
4042 : : uint_fast8_t *address_sizep, uint_fast8_t *offset_sizep,
4043 : : ptrdiff_t offset, unsigned char **readp, unsigned char *endp)
4044 : : {
4045 [ + - ]: 43167 : if (table->n == 0)
4046 : : return false;
4047 : :
4048 [ + - ][ + + ]: 88398 : while (*idxp < table->n && table->table[*idxp].offset < (Dwarf_Off) offset)
4049 : 45231 : ++*idxp;
4050 : :
4051 : 43167 : struct listptr *p = &table->table[*idxp];
4052 : :
4053 [ + - ]: 43167 : if (*idxp == table->n
4054 [ - + ]: 43167 : || p->offset >= (Dwarf_Off) (endp - *readp + offset))
4055 : : {
4056 : 0 : *readp = endp;
4057 : 0 : printf (gettext (" [%6tx] <UNUSED GARBAGE IN REST OF SECTION>\n"),
4058 : : offset);
4059 : : return true;
4060 : : }
4061 : :
4062 [ - + ]: 43167 : if (p->offset != (Dwarf_Off) offset)
4063 : : {
4064 : 0 : *readp += p->offset - offset;
4065 : 0 : printf (gettext (" [%6tx] <UNUSED GARBAGE> ... %" PRIu64 " bytes ...\n"),
4066 : : offset, (Dwarf_Off) p->offset - offset);
4067 : : return true;
4068 : : }
4069 : :
4070 [ + - ]: 43167 : if (address_sizep != NULL)
4071 [ - + ]: 43167 : *address_sizep = listptr_address_size (p);
4072 [ + + ]: 43167 : if (offset_sizep != NULL)
4073 [ + - ]: 43167 : *offset_sizep = listptr_offset_size (p);
4074 : :
4075 : : return false;
4076 : : }
4077 : :
4078 : :
4079 : : static void
4080 : 38 : print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4081 : : Ebl *ebl, GElf_Ehdr *ehdr,
4082 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
4083 : : {
4084 : 76 : const size_t sh_size = (dbg->sectiondata[IDX_debug_abbrev] ?
4085 [ + - ]: 38 : dbg->sectiondata[IDX_debug_abbrev]->d_size : 0);
4086 : :
4087 : 38 : printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
4088 : : " [ Code]\n"),
4089 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4090 : : (uint64_t) shdr->sh_offset);
4091 : :
4092 : 38 : Dwarf_Off offset = 0;
4093 [ + + ]: 1379 : while (offset < sh_size)
4094 : : {
4095 : 1341 : printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
4096 : : offset);
4097 : :
4098 : : while (1)
4099 : : {
4100 : : size_t length;
4101 : : Dwarf_Abbrev abbrev;
4102 : :
4103 : 66123 : int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
4104 [ + + ]: 66123 : if (res != 0)
4105 : : {
4106 [ - + ]: 1341 : if (unlikely (res < 0))
4107 : : {
4108 : 0 : printf (gettext ("\
4109 : : *** error while reading abbreviation: %s\n"),
4110 : : dwarf_errmsg (-1));
4111 : 38 : return;
4112 : : }
4113 : :
4114 : : /* This is the NUL byte at the end of the section. */
4115 : 1341 : ++offset;
4116 : : break;
4117 : : }
4118 : :
4119 : : /* We know these calls can never fail. */
4120 : 64782 : unsigned int code = dwarf_getabbrevcode (&abbrev);
4121 : 64782 : unsigned int tag = dwarf_getabbrevtag (&abbrev);
4122 : 64782 : int has_children = dwarf_abbrevhaschildren (&abbrev);
4123 : :
4124 [ + + ]: 64782 : printf (gettext (" [%5u] offset: %" PRId64
4125 : : ", children: %s, tag: %s\n"),
4126 : : code, (int64_t) offset,
4127 : : has_children ? gettext ("yes") : gettext ("no"),
4128 : : dwarf_tag_name (tag));
4129 : :
4130 : 64782 : size_t cnt = 0;
4131 : : unsigned int name;
4132 : : unsigned int form;
4133 : : Dwarf_Off enoffset;
4134 [ + + ]: 324891 : while (dwarf_getabbrevattr (&abbrev, cnt,
4135 : : &name, &form, &enoffset) == 0)
4136 : : {
4137 : 260109 : printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n",
4138 : : dwarf_attr_name (name), dwarf_form_name (form),
4139 : : (uint64_t) enoffset);
4140 : :
4141 : 260109 : ++cnt;
4142 : : }
4143 : :
4144 : 64782 : offset += length;
4145 : 64782 : }
4146 : : }
4147 : : }
4148 : :
4149 : :
4150 : : /* Print content of DWARF .debug_aranges section. We fortunately do
4151 : : not have to know a bit about the structure of the section, libdwarf
4152 : : takes care of it. */
4153 : : static void
4154 : 38 : print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4155 : : Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
4156 : : GElf_Shdr *shdr, Dwarf *dbg)
4157 : : {
4158 : : Dwarf_Aranges *aranges;
4159 : : size_t cnt;
4160 [ - + ]: 38 : if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
4161 : : {
4162 : 0 : error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
4163 : : dwarf_errmsg (-1));
4164 : : return;
4165 : : }
4166 : :
4167 : 38 : printf (ngettext ("\
4168 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n",
4169 : : "\
4170 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
4171 : : cnt),
4172 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4173 : : (uint64_t) shdr->sh_offset, cnt);
4174 : :
4175 : : /* Compute floor(log16(cnt)). */
4176 : 38 : size_t tmp = cnt;
4177 : 38 : int digits = 1;
4178 [ + + ]: 56 : while (tmp >= 16)
4179 : : {
4180 : 18 : ++digits;
4181 : 18 : tmp >>= 4;
4182 : : }
4183 : :
4184 [ + + ]: 2351 : for (size_t n = 0; n < cnt; ++n)
4185 : : {
4186 : 2313 : Dwarf_Arange *runp = dwarf_onearange (aranges, n);
4187 [ - + ]: 2313 : if (unlikely (runp == NULL))
4188 : : {
4189 : 0 : printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
4190 : : return;
4191 : : }
4192 : :
4193 : : Dwarf_Addr start;
4194 : : Dwarf_Word length;
4195 : : Dwarf_Off offset;
4196 : :
4197 [ - + ]: 2313 : if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
4198 : 0 : printf (gettext (" [%*zu] ???\n"), digits, n);
4199 : : else
4200 [ + + ]: 2313 : printf (gettext (" [%*zu] start: %0#*" PRIx64
4201 : : ", length: %5" PRIu64 ", CU DIE offset: %6"
4202 : : PRId64 "\n"),
4203 : 2313 : digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18,
4204 : : (uint64_t) start, (uint64_t) length, (int64_t) offset);
4205 : : }
4206 : : }
4207 : :
4208 : : /* Print content of DWARF .debug_ranges section. */
4209 : : static void
4210 : 27 : print_debug_ranges_section (Dwfl_Module *dwflmod,
4211 : : Ebl *ebl, GElf_Ehdr *ehdr,
4212 : : Elf_Scn *scn, GElf_Shdr *shdr,
4213 : : Dwarf *dbg)
4214 : : {
4215 : 27 : Elf_Data *data = elf_rawdata (scn, NULL);
4216 : :
4217 [ - + ]: 27 : if (unlikely (data == NULL))
4218 : : {
4219 : 0 : error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
4220 : : elf_errmsg (-1));
4221 : 27 : return;
4222 : : }
4223 : :
4224 : 27 : printf (gettext ("\
4225 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4226 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4227 : : (uint64_t) shdr->sh_offset);
4228 : :
4229 : 27 : sort_listptr (&known_rangelistptr, "rangelistptr");
4230 : 27 : size_t listptr_idx = 0;
4231 : :
4232 [ + - ]: 27 : uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4233 : :
4234 : 27 : bool first = true;
4235 : 27 : unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
4236 : 27 : unsigned char *readp = data->d_buf;
4237 [ + + ]: 31116 : while (readp < endp)
4238 : : {
4239 : 31089 : ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
4240 : :
4241 [ + + ][ - + ]: 31089 : if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
4242 : : &address_size, NULL,
4243 : : offset, &readp, endp))
4244 : 0 : continue;
4245 : :
4246 [ - + ]: 31089 : if (unlikely (data->d_size - offset < address_size * 2))
4247 : : {
4248 : 0 : printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
4249 : 0 : break;
4250 : : }
4251 : :
4252 : : Dwarf_Addr begin;
4253 : : Dwarf_Addr end;
4254 [ + - ]: 31089 : if (address_size == 8)
4255 : : {
4256 [ - + ][ # # ]: 31089 : begin = read_8ubyte_unaligned_inc (dbg, readp);
4257 [ - + ][ # # ]: 31089 : end = read_8ubyte_unaligned_inc (dbg, readp);
4258 : : }
4259 : : else
4260 : : {
4261 [ # # ][ # # ]: 0 : begin = read_4ubyte_unaligned_inc (dbg, readp);
4262 [ # # ][ # # ]: 0 : end = read_4ubyte_unaligned_inc (dbg, readp);
4263 [ # # ]: 0 : if (begin == (Dwarf_Addr) (uint32_t) -1)
4264 : 0 : begin = (Dwarf_Addr) -1l;
4265 : : }
4266 : :
4267 [ - + ]: 31089 : if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
4268 : : {
4269 : 0 : char *b = format_dwarf_addr (dwflmod, address_size, end);
4270 : 0 : printf (gettext (" [%6tx] base address %s\n"), offset, b);
4271 : 0 : free (b);
4272 : : }
4273 [ + + ]: 31089 : else if (begin == 0 && end == 0) /* End of list entry. */
4274 : : {
4275 [ - + ]: 7890 : if (first)
4276 : 0 : printf (gettext (" [%6tx] empty list\n"), offset);
4277 : : first = true;
4278 : : }
4279 : : else
4280 : : {
4281 : 23199 : char *b = format_dwarf_addr (dwflmod, address_size, begin);
4282 : 23199 : char *e = format_dwarf_addr (dwflmod, address_size, end);
4283 : : /* We have an address range entry. */
4284 [ + + ]: 23199 : if (first) /* First address range entry in a list. */
4285 : 7890 : printf (gettext (" [%6tx] %s..%s\n"), offset, b, e);
4286 : : else
4287 : 15309 : printf (gettext (" %s..%s\n"), b, e);
4288 : 23199 : free (b);
4289 : 23199 : free (e);
4290 : :
4291 : 31089 : first = false;
4292 : : }
4293 : : }
4294 : : }
4295 : :
4296 : : #define REGNAMESZ 16
4297 : : static const char *
4298 : 7344 : register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc,
4299 : : char name[REGNAMESZ], int *bits, int *type)
4300 : : {
4301 : : const char *set;
4302 : : const char *pfx;
4303 : : int ignore;
4304 [ + + ][ + + ]: 7344 : ssize_t n = ebl_register_info (ebl, regno, name, REGNAMESZ, &pfx, &set,
4305 : : bits ?: &ignore, type ?: &ignore);
4306 [ - + ]: 7344 : if (n <= 0)
4307 : : {
4308 [ # # ]: 0 : if (loc != NULL)
4309 : 0 : snprintf (name, REGNAMESZ, "reg%u", loc->regno);
4310 : : else
4311 : 0 : snprintf (name, REGNAMESZ, "??? 0x%x", regno);
4312 [ # # ]: 0 : if (bits != NULL)
4313 [ # # ]: 0 : *bits = loc != NULL ? loc->bits : 0;
4314 [ # # ]: 0 : if (type != NULL)
4315 : 0 : *type = DW_ATE_unsigned;
4316 : 0 : set = "??? unrecognized";
4317 : : }
4318 : : else
4319 : : {
4320 [ + + ][ - + ]: 7344 : if (bits != NULL && *bits <= 0)
4321 [ # # ]: 0 : *bits = loc != NULL ? loc->bits : 0;
4322 [ + + ][ - + ]: 7344 : if (type != NULL && *type == DW_ATE_void)
4323 : 0 : *type = DW_ATE_unsigned;
4324 : :
4325 : : }
4326 : 7344 : return set;
4327 : : }
4328 : :
4329 : : static void
4330 : 4433 : print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
4331 : : Dwarf_Word vma_base, unsigned int code_align,
4332 : : int data_align,
4333 : : unsigned int version, unsigned int ptr_size,
4334 : : Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
4335 : : {
4336 : : char regnamebuf[REGNAMESZ];
4337 : 7126 : const char *regname (unsigned int regno)
4338 : : {
4339 : 7126 : register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
4340 : 7126 : return regnamebuf;
4341 : : }
4342 : :
4343 : 4433 : puts ("\n Program:");
4344 : 4433 : Dwarf_Word pc = vma_base;
4345 [ + + ]: 66117 : while (readp < endp)
4346 : : {
4347 : 61684 : unsigned int opcode = *readp++;
4348 : :
4349 [ + + ]: 61684 : if (opcode < DW_CFA_advance_loc)
4350 : : /* Extended opcode. */
4351 [ + - + + : 39129 : switch (opcode)
+ + - - -
- + + + +
+ + - + -
- - - - -
- - - ]
4352 : : {
4353 : : uint64_t op1;
4354 : : int64_t sop1;
4355 : : uint64_t op2;
4356 : : int64_t sop2;
4357 : :
4358 : : case DW_CFA_nop:
4359 : 17733 : puts (" nop");
4360 : 17733 : break;
4361 : : case DW_CFA_set_loc:
4362 : : // XXX overflow check
4363 [ # # ]: 0 : get_uleb128 (op1, readp);
4364 : 0 : op1 += vma_base;
4365 : 0 : printf (" set_loc %" PRIu64 "\n", op1 * code_align);
4366 : 0 : break;
4367 : : case DW_CFA_advance_loc1:
4368 : 1402 : printf (" advance_loc1 %u to %#" PRIx64 "\n",
4369 : 1402 : *readp, pc += *readp * code_align);
4370 : 1402 : ++readp;
4371 : 1402 : break;
4372 : : case DW_CFA_advance_loc2:
4373 [ - + ][ # # ]: 481 : op1 = read_2ubyte_unaligned_inc (dbg, readp);
4374 : 481 : printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n",
4375 : 481 : op1, pc += op1 * code_align);
4376 : 481 : break;
4377 : : case DW_CFA_advance_loc4:
4378 [ + - ][ - + ]: 18 : op1 = read_4ubyte_unaligned_inc (dbg, readp);
4379 : 18 : printf (" advance_loc4 %" PRIu64 " to %#" PRIx64 "\n",
4380 : 18 : op1, pc += op1 * code_align);
4381 : 18 : break;
4382 : : case DW_CFA_offset_extended:
4383 : : // XXX overflow check
4384 [ - + ]: 4 : get_uleb128 (op1, readp);
4385 [ + - ]: 8 : get_uleb128 (op2, readp);
4386 : 4 : printf (" offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64
4387 : : "\n",
4388 : : op1, regname (op1), op2 * data_align);
4389 : 4 : break;
4390 : : case DW_CFA_restore_extended:
4391 : : // XXX overflow check
4392 [ # # ]: 0 : get_uleb128 (op1, readp);
4393 : 0 : printf (" restore_extended r%" PRIu64 " (%s)\n",
4394 : : op1, regname (op1));
4395 : 0 : break;
4396 : : case DW_CFA_undefined:
4397 : : // XXX overflow check
4398 [ # # ]: 0 : get_uleb128 (op1, readp);
4399 : 0 : printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1));
4400 : 0 : break;
4401 : : case DW_CFA_same_value:
4402 : : // XXX overflow check
4403 [ # # ]: 0 : get_uleb128 (op1, readp);
4404 : 0 : printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1));
4405 : 0 : break;
4406 : : case DW_CFA_register:
4407 : : // XXX overflow check
4408 [ # # ]: 0 : get_uleb128 (op1, readp);
4409 [ # # ]: 0 : get_uleb128 (op2, readp);
4410 : 0 : printf (" register r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n",
4411 : : op1, regname (op1), op2, regname (op2));
4412 : 0 : break;
4413 : : case DW_CFA_remember_state:
4414 : 2433 : puts (" remember_state");
4415 : 2433 : break;
4416 : : case DW_CFA_restore_state:
4417 : 2433 : puts (" restore_state");
4418 : 2433 : break;
4419 : : case DW_CFA_def_cfa:
4420 : : // XXX overflow check
4421 [ - + ]: 180 : get_uleb128 (op1, readp);
4422 [ + + ]: 184 : get_uleb128 (op2, readp);
4423 : 180 : printf (" def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n",
4424 : : op1, regname (op1), op2);
4425 : 180 : break;
4426 : : case DW_CFA_def_cfa_register:
4427 : : // XXX overflow check
4428 [ - + ]: 112 : get_uleb128 (op1, readp);
4429 : 112 : printf (" def_cfa_register r%" PRIu64 " (%s)\n",
4430 : : op1, regname (op1));
4431 : 112 : break;
4432 : : case DW_CFA_def_cfa_offset:
4433 : : // XXX overflow check
4434 [ + + ]: 14677 : get_uleb128 (op1, readp);
4435 : 14297 : printf (" def_cfa_offset %" PRIu64 "\n", op1);
4436 : 14297 : break;
4437 : : case DW_CFA_def_cfa_expression:
4438 : : // XXX overflow check
4439 [ - + ]: 24 : get_uleb128 (op1, readp); /* Length of DW_FORM_block. */
4440 : 24 : printf (" def_cfa_expression %" PRIu64 "\n", op1);
4441 : 24 : print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, op1, readp);
4442 : 24 : readp += op1;
4443 : 24 : break;
4444 : : case DW_CFA_expression:
4445 : : // XXX overflow check
4446 [ # # ]: 0 : get_uleb128 (op1, readp);
4447 [ # # ]: 0 : get_uleb128 (op2, readp); /* Length of DW_FORM_block. */
4448 : 0 : printf (" expression r%" PRIu64 " (%s) \n",
4449 : : op1, regname (op1));
4450 : 0 : print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, op2, readp);
4451 : 0 : readp += op2;
4452 : 0 : break;
4453 : : case DW_CFA_offset_extended_sf:
4454 : : // XXX overflow check
4455 [ - + ]: 12 : get_uleb128 (op1, readp);
4456 [ + - ]: 12 : get_sleb128 (sop2, readp);
4457 : 12 : printf (" offset_extended_sf r%" PRIu64 " (%s) at cfa%+"
4458 : : PRId64 "\n",
4459 : : op1, regname (op1), sop2 * data_align);
4460 : 12 : break;
4461 : : case DW_CFA_def_cfa_sf:
4462 : : // XXX overflow check
4463 [ # # ]: 0 : get_uleb128 (op1, readp);
4464 [ # # ]: 0 : get_sleb128 (sop2, readp);
4465 : 0 : printf (" def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n",
4466 : : op1, regname (op1), sop2 * data_align);
4467 : 0 : break;
4468 : : case DW_CFA_def_cfa_offset_sf:
4469 : : // XXX overflow check
4470 [ # # ]: 0 : get_sleb128 (sop1, readp);
4471 : 0 : printf (" def_cfa_offset_sf %" PRId64 "\n", sop1 * data_align);
4472 : 0 : break;
4473 : : case DW_CFA_val_offset:
4474 : : // XXX overflow check
4475 [ # # ]: 0 : get_uleb128 (op1, readp);
4476 [ # # ]: 0 : get_uleb128 (op2, readp);
4477 : 0 : printf (" val_offset %" PRIu64 " at offset %" PRIu64 "\n",
4478 : : op1, op2 * data_align);
4479 : 0 : break;
4480 : : case DW_CFA_val_offset_sf:
4481 : : // XXX overflow check
4482 [ # # ]: 0 : get_uleb128 (op1, readp);
4483 [ # # ]: 0 : get_sleb128 (sop2, readp);
4484 : 0 : printf (" val_offset_sf %" PRIu64 " at offset %" PRId64 "\n",
4485 : : op1, sop2 * data_align);
4486 : 0 : break;
4487 : : case DW_CFA_val_expression:
4488 : : // XXX overflow check
4489 [ # # ]: 0 : get_uleb128 (op1, readp);
4490 [ # # ]: 0 : get_uleb128 (op2, readp); /* Length of DW_FORM_block. */
4491 : 0 : printf (" val_expression r%" PRIu64 " (%s)\n",
4492 : : op1, regname (op1));
4493 : 0 : print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, op2, readp);
4494 : 0 : readp += op2;
4495 : 0 : break;
4496 : : case DW_CFA_MIPS_advance_loc8:
4497 [ # # ][ # # ]: 0 : op1 = read_8ubyte_unaligned_inc (dbg, readp);
4498 : 0 : printf (" MIPS_advance_loc8 %" PRIu64 " to %#" PRIx64 "\n",
4499 : 0 : op1, pc += op1 * code_align);
4500 : 0 : break;
4501 : : case DW_CFA_GNU_window_save:
4502 : 0 : puts (" GNU_window_save");
4503 : 0 : break;
4504 : : case DW_CFA_GNU_args_size:
4505 : : // XXX overflow check
4506 [ # # ]: 0 : get_uleb128 (op1, readp);
4507 : 0 : printf (" args_size %" PRIu64 "\n", op1);
4508 : 0 : break;
4509 : : default:
4510 : 0 : printf (" ??? (%u)\n", opcode);
4511 : 0 : break;
4512 : : }
4513 [ + + ]: 22555 : else if (opcode < DW_CFA_offset)
4514 : 15737 : printf (" advance_loc %u to %#" PRIx64 "\n",
4515 : 15737 : opcode & 0x3f, pc += (opcode & 0x3f) * code_align);
4516 [ + + ]: 6818 : else if (opcode < DW_CFA_restore)
4517 : : {
4518 : : uint64_t offset;
4519 : : // XXX overflow check
4520 [ - + ]: 6350 : get_uleb128 (offset, readp);
4521 : 6350 : printf (" offset r%u (%s) at cfa%+" PRId64 "\n",
4522 : : opcode & 0x3f, regname (opcode & 0x3f), offset * data_align);
4523 : : }
4524 : : else
4525 : 61684 : printf (" restore r%u (%s)\n",
4526 : : opcode & 0x3f, regname (opcode & 0x3f));
4527 : : }
4528 : 4433 : }
4529 : :
4530 : :
4531 : : static unsigned int
4532 : : encoded_ptr_size (int encoding, unsigned int ptr_size)
4533 : : {
4534 [ + - + - ]: 4387 : switch (encoding & 7)
4535 : : {
4536 : : case 2:
4537 : : return 2;
4538 : : case 3:
4539 : : return 4;
4540 : : case 4:
4541 : : return 8;
4542 : : default:
4543 : : return ptr_size;
4544 : : }
4545 : : }
4546 : :
4547 : :
4548 : : static unsigned int
4549 : 104 : print_encoding (unsigned int val)
4550 : : {
4551 [ - - - + : 104 : switch (val & 0xf)
- - - + -
- ]
4552 : : {
4553 : : case DW_EH_PE_absptr:
4554 : 0 : fputs ("absptr", stdout);
4555 : 0 : break;
4556 : : case DW_EH_PE_uleb128:
4557 : 0 : fputs ("uleb128", stdout);
4558 : 0 : break;
4559 : : case DW_EH_PE_udata2:
4560 : 0 : fputs ("udata2", stdout);
4561 : 0 : break;
4562 : : case DW_EH_PE_udata4:
4563 : 26 : fputs ("udata4", stdout);
4564 : 26 : break;
4565 : : case DW_EH_PE_udata8:
4566 : 0 : fputs ("udata8", stdout);
4567 : 0 : break;
4568 : : case DW_EH_PE_sleb128:
4569 : 0 : fputs ("sleb128", stdout);
4570 : 0 : break;
4571 : : case DW_EH_PE_sdata2:
4572 : 0 : fputs ("sdata2", stdout);
4573 : 0 : break;
4574 : : case DW_EH_PE_sdata4:
4575 : 78 : fputs ("sdata4", stdout);
4576 : 78 : break;
4577 : : case DW_EH_PE_sdata8:
4578 : 0 : fputs ("sdata8", stdout);
4579 : 0 : break;
4580 : : default:
4581 : : /* We did not use any of the bits after all. */
4582 : : return val;
4583 : : }
4584 : :
4585 : 104 : return val & ~0xf;
4586 : : }
4587 : :
4588 : :
4589 : : static unsigned int
4590 : 78 : print_relinfo (unsigned int val)
4591 : : {
4592 [ + - + - : 78 : switch (val & 0x70)
- - ]
4593 : : {
4594 : : case DW_EH_PE_pcrel:
4595 : 52 : fputs ("pcrel", stdout);
4596 : 52 : break;
4597 : : case DW_EH_PE_textrel:
4598 : 0 : fputs ("textrel", stdout);
4599 : 0 : break;
4600 : : case DW_EH_PE_datarel:
4601 : 26 : fputs ("datarel", stdout);
4602 : 26 : break;
4603 : : case DW_EH_PE_funcrel:
4604 : 0 : fputs ("funcrel", stdout);
4605 : 0 : break;
4606 : : case DW_EH_PE_aligned:
4607 : 0 : fputs ("aligned", stdout);
4608 : 0 : break;
4609 : : default:
4610 : : return val;
4611 : : }
4612 : :
4613 : 78 : return val & ~0x70;
4614 : : }
4615 : :
4616 : :
4617 : : static void
4618 : 104 : print_encoding_base (const char *pfx, unsigned int fde_encoding)
4619 : : {
4620 : 104 : printf ("(%s", pfx);
4621 : :
4622 [ - + ]: 104 : if (fde_encoding == DW_EH_PE_omit)
4623 : 0 : puts ("omit)");
4624 : : else
4625 : : {
4626 : 104 : unsigned int w = fde_encoding;
4627 : :
4628 : 104 : w = print_encoding (w);
4629 : :
4630 [ + + ]: 104 : if (w & 0x70)
4631 : : {
4632 [ + - ]: 78 : if (w != fde_encoding)
4633 : 78 : fputc_unlocked (' ', stdout);
4634 : :
4635 : 78 : w = print_relinfo (w);
4636 : : }
4637 : :
4638 [ - + ]: 104 : if (w != 0)
4639 [ # # ]: 0 : printf ("%s%x", w != fde_encoding ? " " : "", w);
4640 : :
4641 : 104 : puts (")");
4642 : : }
4643 : 104 : }
4644 : :
4645 : :
4646 : : static const unsigned char *
4647 : 52 : read_encoded (unsigned int encoding, const unsigned char *readp,
4648 : : const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
4649 : : {
4650 [ - + ]: 52 : if ((encoding & 0xf) == DW_EH_PE_absptr)
4651 [ # # ]: 0 : encoding = gelf_getclass (dbg->elf) == ELFCLASS32
4652 : : ? DW_EH_PE_udata4 : DW_EH_PE_udata8;
4653 : :
4654 [ - - - + : 52 : switch (encoding & 0xf)
- - + -
- ]
4655 : : {
4656 : : case DW_EH_PE_uleb128:
4657 : : // XXX buffer overrun check
4658 [ # # ]: 0 : get_uleb128 (*res, readp);
4659 : : break;
4660 : : case DW_EH_PE_sleb128:
4661 : : // XXX buffer overrun check
4662 [ # # ]: 0 : get_sleb128 (*res, readp);
4663 : : break;
4664 : : case DW_EH_PE_udata2:
4665 [ # # ]: 0 : if (readp + 2 > endp)
4666 : : goto invalid;
4667 [ # # ][ # # ]: 0 : *res = read_2ubyte_unaligned_inc (dbg, readp);
4668 : : break;
4669 : : case DW_EH_PE_udata4:
4670 [ + - ]: 26 : if (readp + 4 > endp)
4671 : : goto invalid;
4672 [ - + ][ # # ]: 26 : *res = read_4ubyte_unaligned_inc (dbg, readp);
4673 : : break;
4674 : : case DW_EH_PE_udata8:
4675 [ # # ]: 0 : if (readp + 8 > endp)
4676 : : goto invalid;
4677 [ # # ][ # # ]: 0 : *res = read_8ubyte_unaligned_inc (dbg, readp);
4678 : : break;
4679 : : case DW_EH_PE_sdata2:
4680 [ # # ]: 0 : if (readp + 2 > endp)
4681 : : goto invalid;
4682 [ # # ][ # # ]: 0 : *res = read_2sbyte_unaligned_inc (dbg, readp);
4683 : : break;
4684 : : case DW_EH_PE_sdata4:
4685 [ + - ]: 26 : if (readp + 4 > endp)
4686 : : goto invalid;
4687 [ - + ][ # # ]: 26 : *res = read_4sbyte_unaligned_inc (dbg, readp);
4688 : : break;
4689 : : case DW_EH_PE_sdata8:
4690 [ # # ]: 0 : if (readp + 8 > endp)
4691 : : goto invalid;
4692 [ # # ][ # # ]: 0 : *res = read_8sbyte_unaligned_inc (dbg, readp);
4693 : : break;
4694 : : default:
4695 : : invalid:
4696 : : error (1, 0,
4697 : 0 : gettext ("invalid encoding"));
4698 : : }
4699 : :
4700 : 52 : return readp;
4701 : : }
4702 : :
4703 : :
4704 : : static void
4705 : 36 : print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
4706 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
4707 : : {
4708 : : size_t shstrndx;
4709 : : /* We know this call will succeed since it did in the caller. */
4710 : 36 : (void) elf_getshdrstrndx (ebl->elf, &shstrndx);
4711 : 36 : const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
4712 : :
4713 : 36 : Elf_Data *data = elf_rawdata (scn, NULL);
4714 : :
4715 [ - + ]: 36 : if (unlikely (data == NULL))
4716 : : {
4717 : 0 : error (0, 0, gettext ("cannot get %s content: %s"),
4718 : : scnname, elf_errmsg (-1));
4719 : : return;
4720 : : }
4721 : 36 : bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0;
4722 : :
4723 [ + + ]: 36 : if (is_eh_frame)
4724 : 26 : printf (gettext ("\
4725 : : \nCall frame information section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4726 : : elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
4727 : : else
4728 : 10 : printf (gettext ("\
4729 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4730 : : elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
4731 : :
4732 : : struct cieinfo
4733 : : {
4734 : : ptrdiff_t cie_offset;
4735 : : const char *augmentation;
4736 : : unsigned int code_alignment_factor;
4737 : : unsigned int data_alignment_factor;
4738 : : uint8_t address_size;
4739 : : uint8_t fde_encoding;
4740 : : uint8_t lsda_encoding;
4741 : : struct cieinfo *next;
4742 : 36 : } *cies = NULL;
4743 : :
4744 : 36 : const unsigned char *readp = data->d_buf;
4745 : 36 : const unsigned char *const dataend = ((unsigned char *) data->d_buf
4746 : 36 : + data->d_size);
4747 [ + + ]: 4495 : while (readp < dataend)
4748 : : {
4749 [ - + ]: 4459 : if (unlikely (readp + 4 > dataend))
4750 : : {
4751 : : invalid_data:
4752 : 0 : error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
4753 : : elf_ndxscn (scn), scnname);
4754 : : return;
4755 : : }
4756 : :
4757 : : /* At the beginning there must be a CIE. There can be multiple,
4758 : : hence we test tis in a loop. */
4759 : 4459 : ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
4760 : :
4761 [ + + ][ - + ]: 4459 : Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp);
4762 : 4459 : unsigned int length = 4;
4763 [ - + ]: 4459 : if (unlikely (unit_length == 0xffffffff))
4764 : : {
4765 [ # # ]: 0 : if (unlikely (readp + 8 > dataend))
4766 : : goto invalid_data;
4767 : :
4768 [ # # ][ # # ]: 0 : unit_length = read_8ubyte_unaligned_inc (dbg, readp);
4769 : 0 : length = 8;
4770 : : }
4771 : :
4772 [ + + ]: 4459 : if (unlikely (unit_length == 0))
4773 : : {
4774 : 26 : printf (gettext ("\n [%6tx] Zero terminator\n"), offset);
4775 : 26 : continue;
4776 : : }
4777 : :
4778 [ + + ]: 4433 : unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4779 : :
4780 : 4433 : ptrdiff_t start = readp - (unsigned char *) data->d_buf;
4781 : 4433 : const unsigned char *const cieend = readp + unit_length;
4782 [ - + ][ - + ]: 4433 : if (unlikely (cieend > dataend || readp + 8 > dataend))
4783 : : goto invalid_data;
4784 : :
4785 : : Dwarf_Off cie_id;
4786 [ + - ]: 4433 : if (length == 4)
4787 : : {
4788 [ + + ][ - + ]: 4433 : cie_id = read_4ubyte_unaligned_inc (dbg, readp);
4789 [ + + ]: 4433 : if (!is_eh_frame && cie_id == DW_CIE_ID_32)
4790 : 18 : cie_id = DW_CIE_ID_64;
4791 : : }
4792 : : else
4793 [ # # ][ # # ]: 0 : cie_id = read_8ubyte_unaligned_inc (dbg, readp);
4794 : :
4795 : 4433 : uint_fast8_t version = 2;
4796 : : unsigned int code_alignment_factor;
4797 : : int data_alignment_factor;
4798 : 4433 : unsigned int fde_encoding = 0;
4799 : 4433 : unsigned int lsda_encoding = 0;
4800 : 4433 : Dwarf_Word initial_location = 0;
4801 : 4433 : Dwarf_Word vma_base = 0;
4802 : :
4803 [ + + ][ + + ]: 4433 : if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID_64))
4804 : : {
4805 : 46 : version = *readp++;
4806 : 46 : const char *const augmentation = (const char *) readp;
4807 : 46 : readp = memchr (readp, '\0', cieend - readp);
4808 [ - + ]: 46 : if (unlikely (readp == NULL))
4809 : : goto invalid_data;
4810 : 46 : ++readp;
4811 : :
4812 : 46 : uint_fast8_t segment_size = 0;
4813 [ - + ]: 46 : if (version >= 4)
4814 : : {
4815 [ # # ]: 0 : if (cieend - readp < 5)
4816 : : goto invalid_data;
4817 : 0 : ptr_size = *readp++;
4818 : 0 : segment_size = *readp++;
4819 : : }
4820 : :
4821 : : // XXX Check overflow
4822 [ - + ]: 46 : get_uleb128 (code_alignment_factor, readp);
4823 : : // XXX Check overflow
4824 [ + - ]: 46 : get_sleb128 (data_alignment_factor, readp);
4825 : :
4826 : : /* In some variant for unwind data there is another field. */
4827 [ - + ][ # # ]: 46 : if (strcmp (augmentation, "eh") == 0)
[ - + ]
4828 [ # # ]: 0 : readp += ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4829 : :
4830 : : unsigned int return_address_register;
4831 [ + + ]: 46 : if (unlikely (version == 1))
4832 : 38 : return_address_register = *readp++;
4833 : : else
4834 : : // XXX Check overflow
4835 [ - + ]: 8 : get_uleb128 (return_address_register, readp);
4836 : :
4837 : 46 : printf ("\n [%6tx] CIE length=%" PRIu64 "\n"
4838 : : " CIE_id: %" PRIu64 "\n"
4839 : : " version: %u\n"
4840 : : " augmentation: \"%s\"\n",
4841 : : offset, (uint64_t) unit_length, (uint64_t) cie_id,
4842 : : version, augmentation);
4843 [ - + ]: 46 : if (version >= 4)
4844 : 0 : printf (" address_size: %u\n"
4845 : : " segment_size: %u\n",
4846 : : ptr_size, segment_size);
4847 : 46 : printf (" code_alignment_factor: %u\n"
4848 : : " data_alignment_factor: %d\n"
4849 : : " return_address_register: %u\n",
4850 : : code_alignment_factor,
4851 : : data_alignment_factor, return_address_register);
4852 : :
4853 [ + + ]: 46 : if (augmentation[0] == 'z')
4854 : : {
4855 : : unsigned int augmentationlen;
4856 [ - + ]: 26 : get_uleb128 (augmentationlen, readp);
4857 : :
4858 [ - + ]: 26 : if (augmentationlen > (size_t) (dataend - readp))
4859 : 0 : error (1, 0, gettext ("invalid augmentation length"));
4860 : :
4861 : 26 : const char *hdr = "Augmentation data:";
4862 : 26 : const char *cp = augmentation + 1;
4863 [ + + ]: 52 : while (*cp != '\0')
4864 : : {
4865 : 26 : printf (" %-26s%#x ", hdr, *readp);
4866 : 26 : hdr = "";
4867 : :
4868 [ + - ]: 26 : if (*cp == 'R')
4869 : : {
4870 : 26 : fde_encoding = *readp++;
4871 : 26 : print_encoding_base (gettext ("FDE address encoding: "),
4872 : : fde_encoding);
4873 : : }
4874 [ # # ]: 0 : else if (*cp == 'L')
4875 : : {
4876 : 0 : lsda_encoding = *readp++;
4877 : 0 : print_encoding_base (gettext ("LSDA pointer encoding: "),
4878 : : lsda_encoding);
4879 : : }
4880 [ # # ]: 0 : else if (*cp == 'P')
4881 : : {
4882 : : /* Personality. This field usually has a relocation
4883 : : attached pointing to __gcc_personality_v0. */
4884 : 0 : const unsigned char *startp = readp;
4885 : 0 : unsigned int encoding = *readp++;
4886 : 0 : uint64_t val = 0;
4887 : 0 : readp = read_encoded (encoding, readp,
4888 : 0 : readp - 1 + augmentationlen,
4889 : : &val, dbg);
4890 : :
4891 [ # # ]: 0 : while (++startp < readp)
4892 : 0 : printf ("%#x ", *startp);
4893 : :
4894 : : putchar ('(');
4895 : 0 : print_encoding (encoding);
4896 : : putchar (' ');
4897 [ # # ]: 0 : switch (encoding & 0xf)
4898 : : {
4899 : : case DW_EH_PE_sleb128:
4900 : : case DW_EH_PE_sdata2:
4901 : : case DW_EH_PE_sdata4:
4902 : 0 : printf ("%" PRId64 ")\n", val);
4903 : 0 : break;
4904 : : default:
4905 : 0 : printf ("%#" PRIx64 ")\n", val);
4906 : 0 : break;
4907 : : }
4908 : : }
4909 : : else
4910 : 0 : printf ("(%x)\n", *readp++);
4911 : :
4912 : 26 : ++cp;
4913 : : }
4914 : : }
4915 : :
4916 [ + - ]: 46 : if (likely (ptr_size == 4 || ptr_size == 8))
4917 : : {
4918 : 46 : struct cieinfo *newp = alloca (sizeof (*newp));
4919 : 46 : newp->cie_offset = offset;
4920 : 46 : newp->augmentation = augmentation;
4921 : 46 : newp->fde_encoding = fde_encoding;
4922 : 46 : newp->lsda_encoding = lsda_encoding;
4923 : 46 : newp->address_size = ptr_size;
4924 : 46 : newp->code_alignment_factor = code_alignment_factor;
4925 : 46 : newp->data_alignment_factor = data_alignment_factor;
4926 : 46 : newp->next = cies;
4927 : 46 : cies = newp;
4928 : : }
4929 : : }
4930 : : else
4931 : : {
4932 : : struct cieinfo *cie = cies;
4933 [ + - ]: 4387 : while (cie != NULL)
4934 [ + + ][ - + ]: 4387 : if (is_eh_frame
4935 : 4365 : ? start - (ptrdiff_t) cie_id == cie->cie_offset
4936 : 22 : : (ptrdiff_t) cie_id == cie->cie_offset)
4937 : : break;
4938 : : else
4939 : 0 : cie = cie->next;
4940 [ - + ]: 4387 : if (unlikely (cie == NULL))
4941 : : {
4942 : 0 : puts ("invalid CIE reference in FDE");
4943 : : return;
4944 : : }
4945 : :
4946 : : /* Initialize from CIE data. */
4947 : 4387 : fde_encoding = cie->fde_encoding;
4948 : 4387 : lsda_encoding = cie->lsda_encoding;
4949 : 8774 : ptr_size = encoded_ptr_size (fde_encoding, cie->address_size);
4950 : 4387 : code_alignment_factor = cie->code_alignment_factor;
4951 : 4387 : data_alignment_factor = cie->data_alignment_factor;
4952 : :
4953 : 4387 : const unsigned char *base = readp;
4954 : : // XXX There are sometimes relocations for this value
4955 [ - + ][ # # ]: 4387 : initial_location = read_ubyte_unaligned_inc (ptr_size, dbg, readp);
[ # # ][ + + ]
[ - + ][ # # ]
[ + + ][ - + ]
4956 : 4387 : Dwarf_Word address_range
4957 [ - + ][ # # ]: 4387 : = read_ubyte_unaligned_inc (ptr_size, dbg, readp);
[ # # ][ + + ]
[ - + ][ # # ]
[ + + ][ - + ]
4958 : :
4959 : 4387 : char *a = format_dwarf_addr (dwflmod, cie->address_size,
4960 : : initial_location);
4961 : 4387 : printf ("\n [%6tx] FDE length=%" PRIu64 " cie=[%6tx]\n"
4962 : : " CIE_pointer: %" PRIu64 "\n"
4963 : : " initial_location: %s",
4964 : : offset, (uint64_t) unit_length,
4965 : : cie->cie_offset, (uint64_t) cie_id, a);
4966 : 4387 : free (a);
4967 [ + + ]: 4387 : if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
4968 : : {
4969 : 8718 : vma_base = (((uint64_t) shdr->sh_offset
4970 : 4359 : + (base - (const unsigned char *) data->d_buf)
4971 : 4359 : + (uint64_t) initial_location)
4972 : : & (ptr_size == 4
4973 : : ? UINT64_C (0xffffffff)
4974 [ - + ]: 4359 : : UINT64_C (0xffffffffffffffff)));
4975 : 4359 : printf (gettext (" (offset: %#" PRIx64 ")"),
4976 : : (uint64_t) vma_base);
4977 : : }
4978 : :
4979 : 4387 : printf ("\n address_range: %#" PRIx64,
4980 : : (uint64_t) address_range);
4981 [ + + ]: 4387 : if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
4982 : 4359 : printf (gettext (" (end offset: %#" PRIx64 ")"),
4983 : 4359 : ((uint64_t) vma_base + (uint64_t) address_range)
4984 : : & (ptr_size == 4
4985 : : ? UINT64_C (0xffffffff)
4986 [ - + ]: 4359 : : UINT64_C (0xffffffffffffffff)));
4987 : : putchar ('\n');
4988 : :
4989 [ + + ]: 4387 : if (cie->augmentation[0] == 'z')
4990 : : {
4991 : : unsigned int augmentationlen;
4992 [ - + ]: 4359 : get_uleb128 (augmentationlen, readp);
4993 : :
4994 [ - + ]: 4359 : if (augmentationlen > 0)
4995 : : {
4996 : 0 : const char *hdr = "Augmentation data:";
4997 : 0 : const char *cp = cie->augmentation + 1;
4998 : 0 : unsigned int u = 0;
4999 [ # # ]: 0 : while (*cp != '\0')
5000 : : {
5001 [ # # ]: 0 : if (*cp == 'L')
5002 : : {
5003 : : uint64_t lsda_pointer;
5004 : 0 : const unsigned char *p
5005 : 0 : = read_encoded (lsda_encoding, &readp[u],
5006 : : &readp[augmentationlen],
5007 : : &lsda_pointer, dbg);
5008 : 0 : u = p - readp;
5009 : 0 : printf (gettext ("\
5010 : : %-26sLSDA pointer: %#" PRIx64 "\n"),
5011 : : hdr, lsda_pointer);
5012 : 0 : hdr = "";
5013 : : }
5014 : 0 : ++cp;
5015 : : }
5016 : :
5017 [ # # ]: 0 : while (u < augmentationlen)
5018 : : {
5019 : 0 : printf (" %-26s%#x\n", hdr, readp[u++]);
5020 : 0 : hdr = "";
5021 : : }
5022 : : }
5023 : :
5024 : 4359 : readp += augmentationlen;
5025 : : }
5026 : : }
5027 : :
5028 : : /* Handle the initialization instructions. */
5029 : 4433 : print_cfa_program (readp, cieend, vma_base, code_alignment_factor,
5030 : : data_alignment_factor, version, ptr_size,
5031 : : dwflmod, ebl, dbg);
5032 : 4459 : readp = cieend;
5033 : : }
5034 : : }
5035 : :
5036 : :
5037 : : struct attrcb_args
5038 : : {
5039 : : Dwfl_Module *dwflmod;
5040 : : Dwarf *dbg;
5041 : : int level;
5042 : : bool silent;
5043 : : unsigned int version;
5044 : : unsigned int addrsize;
5045 : : unsigned int offset_size;
5046 : : Dwarf_Off cu_offset;
5047 : : };
5048 : :
5049 : :
5050 : : static int
5051 : 2540272 : attr_callback (Dwarf_Attribute *attrp, void *arg)
5052 : : {
5053 : 2540272 : struct attrcb_args *cbargs = (struct attrcb_args *) arg;
5054 : 2540272 : const int level = cbargs->level;
5055 : :
5056 : 2540272 : unsigned int attr = dwarf_whatattr (attrp);
5057 [ - + ]: 2540272 : if (unlikely (attr == 0))
5058 : : {
5059 [ # # ]: 0 : if (!cbargs->silent)
5060 : 0 : error (0, 0, gettext ("cannot get attribute code: %s"),
5061 : : dwarf_errmsg (-1));
5062 : : return DWARF_CB_ABORT;
5063 : : }
5064 : :
5065 : 2540272 : unsigned int form = dwarf_whatform (attrp);
5066 [ - + ]: 2540272 : if (unlikely (form == 0))
5067 : : {
5068 [ # # ]: 0 : if (!cbargs->silent)
5069 : 0 : error (0, 0, gettext ("cannot get attribute form: %s"),
5070 : : dwarf_errmsg (-1));
5071 : : return DWARF_CB_ABORT;
5072 : : }
5073 : :
5074 [ + + + - : 2540272 : switch (form)
+ + + +
- ]
5075 : : {
5076 : : case DW_FORM_addr:
5077 [ + - ]: 49707 : if (!cbargs->silent)
5078 : : {
5079 : : Dwarf_Addr addr;
5080 [ - + ]: 49707 : if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
5081 : : {
5082 : : attrval_out:
5083 [ # # ]: 0 : if (!cbargs->silent)
5084 : 0 : error (0, 0, gettext ("cannot get attribute value: %s"),
5085 : : dwarf_errmsg (-1));
5086 : : return DWARF_CB_ABORT;
5087 : : }
5088 : 49707 : char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr);
5089 : 49707 : printf (" %*s%-20s (%s) %s\n",
5090 : : (int) (level * 2), "", dwarf_attr_name (attr),
5091 : : dwarf_form_name (form), a);
5092 : 49707 : free (a);
5093 : : }
5094 : : break;
5095 : :
5096 : : case DW_FORM_indirect:
5097 : : case DW_FORM_strp:
5098 : : case DW_FORM_string:
5099 : : case DW_FORM_GNU_strp_alt:
5100 [ + - ]: 484292 : if (cbargs->silent)
5101 : : break;
5102 : 484292 : const char *str = dwarf_formstring (attrp);
5103 [ - + ]: 484292 : if (unlikely (str == NULL))
5104 : : goto attrval_out;
5105 : 484292 : printf (" %*s%-20s (%s) \"%s\"\n",
5106 : : (int) (level * 2), "", dwarf_attr_name (attr),
5107 : : dwarf_form_name (form), str);
5108 : : break;
5109 : :
5110 : : case DW_FORM_ref_addr:
5111 : : case DW_FORM_ref_udata:
5112 : : case DW_FORM_ref8:
5113 : : case DW_FORM_ref4:
5114 : : case DW_FORM_ref2:
5115 : : case DW_FORM_ref1:
5116 : : case DW_FORM_GNU_ref_alt:
5117 [ + - ]: 592658 : if (cbargs->silent)
5118 : : break;
5119 : : Dwarf_Die ref;
5120 [ - + ]: 592658 : if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
5121 : : goto attrval_out;
5122 : :
5123 : 592658 : printf (" %*s%-20s (%s) [%6" PRIxMAX "]\n",
5124 : : (int) (level * 2), "", dwarf_attr_name (attr),
5125 : : dwarf_form_name (form), (uintmax_t) dwarf_dieoffset (&ref));
5126 : : break;
5127 : :
5128 : : case DW_FORM_ref_sig8:
5129 [ # # ]: 0 : if (cbargs->silent)
5130 : : break;
5131 [ # # ]: 0 : printf (" %*s%-20s (%s) {%6" PRIx64 "}\n",
5132 : : (int) (level * 2), "", dwarf_attr_name (attr),
5133 : : dwarf_form_name (form),
5134 [ # # ]: 0 : (uint64_t) read_8ubyte_unaligned (attrp->cu->dbg, attrp->valp));
5135 : : break;
5136 : :
5137 : : case DW_FORM_sec_offset:
5138 : : case DW_FORM_udata:
5139 : : case DW_FORM_sdata:
5140 : : case DW_FORM_data8:
5141 : : case DW_FORM_data4:
5142 : : case DW_FORM_data2:
5143 : : case DW_FORM_data1:;
5144 : : Dwarf_Word num;
5145 [ - + ]: 1272156 : if (unlikely (dwarf_formudata (attrp, &num) != 0))
5146 : : goto attrval_out;
5147 : :
5148 : 1272156 : const char *valuestr = NULL;
5149 [ + + + + : 1272156 : switch (attr)
+ - - - -
- + - -
+ ]
5150 : : {
5151 : : /* This case can take either a constant or a loclistptr. */
5152 : : case DW_AT_data_member_location:
5153 [ + - ]: 226036 : if (form != DW_FORM_sec_offset
5154 [ + + ]: 226036 : && (cbargs->version >= 4
5155 [ + - ]: 23806 : || (form != DW_FORM_data4 && form != DW_FORM_data8)))
5156 : : {
5157 [ + - ]: 226036 : if (!cbargs->silent)
5158 : 226036 : printf (" %*s%-20s (%s) %" PRIxMAX "\n",
5159 : : (int) (level * 2), "", dwarf_attr_name (attr),
5160 : : dwarf_form_name (form), (uintmax_t) num);
5161 : : return DWARF_CB_OK;
5162 : : }
5163 : : /* else fallthrough */
5164 : :
5165 : : /* These cases always take a loclistptr and no constant. */
5166 : : case DW_AT_location:
5167 : : case DW_AT_data_location:
5168 : : case DW_AT_vtable_elem_location:
5169 : : case DW_AT_string_length:
5170 : : case DW_AT_use_location:
5171 : : case DW_AT_frame_base:
5172 : : case DW_AT_return_addr:
5173 : : case DW_AT_static_link:
5174 : : case DW_AT_GNU_call_site_value:
5175 : : case DW_AT_GNU_call_site_data_value:
5176 : : case DW_AT_GNU_call_site_target:
5177 : : case DW_AT_GNU_call_site_target_clobbered:
5178 : 36156 : notice_listptr (section_loc, &known_loclistptr,
5179 : 72312 : cbargs->addrsize, cbargs->offset_size, num);
5180 [ + - ]: 36156 : if (!cbargs->silent)
5181 : 36156 : printf (" %*s%-20s (%s) location list [%6" PRIxMAX "]\n",
5182 : : (int) (level * 2), "", dwarf_attr_name (attr),
5183 : : dwarf_form_name (form), (uintmax_t) num);
5184 : : return DWARF_CB_OK;
5185 : :
5186 : : case DW_AT_ranges:
5187 : 9137 : notice_listptr (section_ranges, &known_rangelistptr,
5188 : 18274 : cbargs->addrsize, cbargs->offset_size, num);
5189 [ + - ]: 9137 : if (!cbargs->silent)
5190 : 9137 : printf (" %*s%-20s (%s) range list [%6" PRIxMAX "]\n",
5191 : : (int) (level * 2), "", dwarf_attr_name (attr),
5192 : : dwarf_form_name (form), (uintmax_t) num);
5193 : : return DWARF_CB_OK;
5194 : :
5195 : : case DW_AT_language:
5196 : 1345 : valuestr = dwarf_lang_name (num);
5197 : 1345 : break;
5198 : : case DW_AT_encoding:
5199 : 16784 : valuestr = dwarf_encoding_name (num);
5200 : 16784 : break;
5201 : : case DW_AT_accessibility:
5202 : 0 : valuestr = dwarf_access_name (num);
5203 : 0 : break;
5204 : : case DW_AT_visibility:
5205 : 0 : valuestr = dwarf_visibility_name (num);
5206 : 0 : break;
5207 : : case DW_AT_virtuality:
5208 : 0 : valuestr = dwarf_virtuality_name (num);
5209 : 0 : break;
5210 : : case DW_AT_identifier_case:
5211 : 0 : valuestr = dwarf_identifier_case_name (num);
5212 : 0 : break;
5213 : : case DW_AT_calling_convention:
5214 : 0 : valuestr = dwarf_calling_convention_name (num);
5215 : 0 : break;
5216 : : case DW_AT_inline:
5217 : 1627 : valuestr = dwarf_inline_name (num);
5218 : 1627 : break;
5219 : : case DW_AT_ordering:
5220 : 0 : valuestr = dwarf_ordering_name (num);
5221 : 0 : break;
5222 : : case DW_AT_discr_list:
5223 : 0 : valuestr = dwarf_discr_list_name (num);
5224 : 0 : break;
5225 : : default:
5226 : : /* Nothing. */
5227 : : break;
5228 : : }
5229 : :
5230 [ + - ]: 1000827 : if (cbargs->silent)
5231 : : break;
5232 : :
5233 [ + + ]: 1000827 : if (valuestr == NULL)
5234 : 981071 : printf (" %*s%-20s (%s) %" PRIuMAX "\n",
5235 : : (int) (level * 2), "", dwarf_attr_name (attr),
5236 : : dwarf_form_name (form), (uintmax_t) num);
5237 : : else
5238 : 19756 : printf (" %*s%-20s (%s) %s (%" PRIuMAX ")\n",
5239 : : (int) (level * 2), "", dwarf_attr_name (attr),
5240 : : dwarf_form_name (form), valuestr, (uintmax_t) num);
5241 : : break;
5242 : :
5243 : : case DW_FORM_flag:
5244 [ + - ]: 9048 : if (cbargs->silent)
5245 : : break;
5246 : : bool flag;
5247 [ - + ]: 9048 : if (unlikely (dwarf_formflag (attrp, &flag) != 0))
5248 : : goto attrval_out;
5249 : :
5250 [ - + ]: 9048 : printf (" %*s%-20s (%s) %s\n",
5251 : : (int) (level * 2), "", dwarf_attr_name (attr),
5252 : : dwarf_form_name (form), nl_langinfo (flag ? YESSTR : NOSTR));
5253 : : break;
5254 : :
5255 : : case DW_FORM_flag_present:
5256 [ + - ]: 48641 : if (cbargs->silent)
5257 : : break;
5258 : 48641 : printf (" %*s%-20s (%s) %s\n",
5259 : : (int) (level * 2), "", dwarf_attr_name (attr),
5260 : : dwarf_form_name (form), nl_langinfo (YESSTR));
5261 : : break;
5262 : :
5263 : : case DW_FORM_exprloc:
5264 : : case DW_FORM_block4:
5265 : : case DW_FORM_block2:
5266 : : case DW_FORM_block1:
5267 : : case DW_FORM_block:
5268 [ + - ]: 83770 : if (cbargs->silent)
5269 : : break;
5270 : : Dwarf_Block block;
5271 [ - + ]: 83770 : if (unlikely (dwarf_formblock (attrp, &block) != 0))
5272 : : goto attrval_out;
5273 : :
5274 : 83770 : printf (" %*s%-20s (%s) ",
5275 : : (int) (level * 2), "", dwarf_attr_name (attr),
5276 : : dwarf_form_name (form));
5277 : :
5278 [ + + ]: 83770 : switch (attr)
5279 : : {
5280 : : default:
5281 [ + - ]: 3 : if (form != DW_FORM_exprloc)
5282 : : {
5283 : 3 : print_block (block.length, block.data);
5284 : 3 : break;
5285 : : }
5286 : : /* Fall through. */
5287 : :
5288 : : case DW_AT_location:
5289 : : case DW_AT_data_location:
5290 : : case DW_AT_data_member_location:
5291 : : case DW_AT_vtable_elem_location:
5292 : : case DW_AT_string_length:
5293 : : case DW_AT_use_location:
5294 : : case DW_AT_frame_base:
5295 : : case DW_AT_return_addr:
5296 : : case DW_AT_static_link:
5297 : : case DW_AT_allocated:
5298 : : case DW_AT_associated:
5299 : : case DW_AT_bit_size:
5300 : : case DW_AT_bit_offset:
5301 : : case DW_AT_bit_stride:
5302 : : case DW_AT_byte_size:
5303 : : case DW_AT_byte_stride:
5304 : : case DW_AT_count:
5305 : : case DW_AT_lower_bound:
5306 : : case DW_AT_upper_bound:
5307 : : case DW_AT_GNU_call_site_value:
5308 : : case DW_AT_GNU_call_site_data_value:
5309 : : case DW_AT_GNU_call_site_target:
5310 : : case DW_AT_GNU_call_site_target_clobbered:
5311 : : putchar ('\n');
5312 : 83767 : print_ops (cbargs->dwflmod, cbargs->dbg,
5313 : : 12 + level * 2, 12 + level * 2,
5314 : : cbargs->version, cbargs->addrsize, cbargs->offset_size,
5315 : 83767 : block.length, block.data);
5316 : 83767 : break;
5317 : : }
5318 : : break;
5319 : :
5320 : : default:
5321 [ # # ]: 0 : if (cbargs->silent)
5322 : : break;
5323 : 271329 : printf (" %*s%-20s (form: %#x) ???\n",
5324 : : (int) (level * 2), "", dwarf_attr_name (attr),
5325 : : (int) form);
5326 : : break;
5327 : : }
5328 : :
5329 : 2540272 : return DWARF_CB_OK;
5330 : : }
5331 : :
5332 : : static void
5333 : 42 : print_debug_units (Dwfl_Module *dwflmod,
5334 : : Ebl *ebl, GElf_Ehdr *ehdr,
5335 : : Elf_Scn *scn, GElf_Shdr *shdr,
5336 : : Dwarf *dbg, bool debug_types)
5337 : : {
5338 : 42 : const bool silent = !(print_debug_sections & section_info);
5339 : 42 : const char *secname = section_name (ebl, ehdr, shdr);
5340 : :
5341 [ + - ]: 42 : if (!silent)
5342 : 42 : printf (gettext ("\
5343 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"),
5344 : : elf_ndxscn (scn), secname, (uint64_t) shdr->sh_offset);
5345 : :
5346 : : /* If the section is empty we don't have to do anything. */
5347 [ + - ][ + - ]: 42 : if (!silent && shdr->sh_size == 0)
5348 : 42 : return;
5349 : :
5350 : 42 : int maxdies = 20;
5351 : 42 : Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
5352 : :
5353 : 42 : Dwarf_Off offset = 0;
5354 : :
5355 : : /* New compilation unit. */
5356 : : size_t cuhl;
5357 : : Dwarf_Half version;
5358 : : Dwarf_Off abbroffset;
5359 : : uint8_t addrsize;
5360 : : uint8_t offsize;
5361 : : Dwarf_Off nextcu;
5362 : : uint64_t typesig;
5363 : : Dwarf_Off typeoff;
5364 : : next_cu:
5365 [ + - ][ + - ]: 1387 : if (dwarf_next_unit (dbg, offset, &nextcu, &cuhl, &version,
[ + + ]
5366 : : &abbroffset, &addrsize, &offsize,
5367 : : debug_types ? &typesig : NULL,
5368 : : debug_types ? &typeoff : NULL) != 0)
5369 : : goto do_return;
5370 : :
5371 [ + - ]: 1345 : if (!silent)
5372 : : {
5373 [ - + ]: 1345 : if (debug_types)
5374 : 0 : printf (gettext (" Type unit at offset %" PRIu64 ":\n"
5375 : : " Version: %" PRIu16 ", Abbreviation section offset: %"
5376 : : PRIu64 ", Address size: %" PRIu8
5377 : : ", Offset size: %" PRIu8
5378 : : "\n Type signature: %#" PRIx64
5379 : : ", Type offset: %#" PRIx64 "\n"),
5380 : : (uint64_t) offset, version, abbroffset, addrsize, offsize,
5381 : : typesig, (uint64_t) typeoff);
5382 : : else
5383 : 1345 : printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
5384 : : " Version: %" PRIu16 ", Abbreviation section offset: %"
5385 : : PRIu64 ", Address size: %" PRIu8
5386 : : ", Offset size: %" PRIu8 "\n"),
5387 : : (uint64_t) offset, version, abbroffset, addrsize, offsize);
5388 : : }
5389 : :
5390 : 1345 : struct attrcb_args args =
5391 : : {
5392 : : .dwflmod = dwflmod,
5393 : : .dbg = dbg,
5394 : : .silent = silent,
5395 : : .version = version,
5396 : : .addrsize = addrsize,
5397 : : .offset_size = offsize,
5398 : : .cu_offset = offset
5399 : : };
5400 : :
5401 : 1345 : offset += cuhl;
5402 : :
5403 : 1345 : int level = 0;
5404 : :
5405 [ + - ][ - + ]: 1345 : if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie)
5406 : : (dbg, offset, &dies[level]) == NULL))
5407 : : {
5408 [ # # ]: 0 : if (!silent)
5409 : 0 : error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
5410 : : " in section '%s': %s"),
5411 : : (uint64_t) offset, secname, dwarf_errmsg (-1));
5412 : : goto do_return;
5413 : : }
5414 : :
5415 : : do
5416 : : {
5417 : 724208 : offset = dwarf_dieoffset (&dies[level]);
5418 [ - + ]: 724208 : if (unlikely (offset == ~0ul))
5419 : : {
5420 [ # # ]: 0 : if (!silent)
5421 : 0 : error (0, 0, gettext ("cannot get DIE offset: %s"),
5422 : : dwarf_errmsg (-1));
5423 : : goto do_return;
5424 : : }
5425 : :
5426 : 724208 : int tag = dwarf_tag (&dies[level]);
5427 [ - + ]: 724208 : if (unlikely (tag == DW_TAG_invalid))
5428 : : {
5429 [ # # ]: 0 : if (!silent)
5430 : 0 : error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
5431 : : " in section '%s': %s"),
5432 : : (uint64_t) offset, secname, dwarf_errmsg (-1));
5433 : : goto do_return;
5434 : : }
5435 : :
5436 [ + - ]: 724208 : if (!silent)
5437 : 724208 : printf (" [%6" PRIx64 "] %*s%s\n",
5438 : : (uint64_t) offset, (int) (level * 2), "",
5439 : : dwarf_tag_name (tag));
5440 : :
5441 : : /* Print the attribute values. */
5442 : 724208 : args.level = level;
5443 : 724208 : (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0);
5444 : :
5445 : : /* Make room for the next level's DIE. */
5446 [ - + ]: 724208 : if (level + 1 == maxdies)
5447 : 0 : dies = (Dwarf_Die *) xrealloc (dies,
5448 : 0 : (maxdies += 10)
5449 : : * sizeof (Dwarf_Die));
5450 : :
5451 : 724208 : int res = dwarf_child (&dies[level], &dies[level + 1]);
5452 [ + + ]: 724208 : if (res > 0)
5453 : : {
5454 [ + + ]: 724208 : while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1)
5455 [ + + ]: 725553 : if (level-- == 0)
5456 : : break;
5457 : :
5458 [ - + ]: 620191 : if (unlikely (res == -1))
5459 : : {
5460 [ # # ]: 0 : if (!silent)
5461 : 0 : error (0, 0, gettext ("cannot get next DIE: %s\n"),
5462 : : dwarf_errmsg (-1));
5463 : : goto do_return;
5464 : : }
5465 : : }
5466 [ - + ]: 104017 : else if (unlikely (res < 0))
5467 : : {
5468 [ # # ]: 0 : if (!silent)
5469 : 0 : error (0, 0, gettext ("cannot get next DIE: %s"),
5470 : : dwarf_errmsg (-1));
5471 : : goto do_return;
5472 : : }
5473 : : else
5474 : : ++level;
5475 : : }
5476 [ + + ]: 724208 : while (level >= 0);
5477 : :
5478 : 1345 : offset = nextcu;
5479 [ + - ]: 1345 : if (offset != 0)
5480 : : goto next_cu;
5481 : :
5482 : : do_return:
5483 : 42 : free (dies);
5484 : : }
5485 : :
5486 : : static void
5487 : 42 : print_debug_info_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
5488 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5489 : : {
5490 : 42 : print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, false);
5491 : 42 : }
5492 : :
5493 : : static void
5494 : 0 : print_debug_types_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
5495 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5496 : : {
5497 : 0 : print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, true);
5498 : 0 : }
5499 : :
5500 : :
5501 : : static void
5502 : 38 : print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
5503 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5504 : : {
5505 : 38 : printf (gettext ("\
5506 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5507 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
5508 : : (uint64_t) shdr->sh_offset);
5509 : :
5510 [ + - ]: 38 : if (shdr->sh_size == 0)
5511 : : return;
5512 : :
5513 : : /* There is no functionality in libdw to read the information in the
5514 : : way it is represented here. Hardcode the decoder. */
5515 : 38 : Elf_Data *data = elf_getdata (scn, NULL);
5516 [ + - ][ - + ]: 38 : if (unlikely (data == NULL || data->d_buf == NULL))
5517 : : {
5518 : 0 : error (0, 0, gettext ("cannot get line data section data: %s"),
5519 : : elf_errmsg (-1));
5520 : : return;
5521 : : }
5522 : :
5523 : 38 : const unsigned char *linep = (const unsigned char *) data->d_buf;
5524 : : const unsigned char *lineendp;
5525 : :
5526 [ + + ]: 1379 : while (linep
5527 : 1379 : < (lineendp = (const unsigned char *) data->d_buf + data->d_size))
5528 : : {
5529 : 1341 : size_t start_offset = linep - (const unsigned char *) data->d_buf;
5530 : :
5531 : 1341 : printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
5532 : :
5533 [ + + ][ - + ]: 1341 : Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
5534 : 1341 : unsigned int length = 4;
5535 [ - + ]: 1341 : if (unlikely (unit_length == 0xffffffff))
5536 : : {
5537 [ # # ]: 0 : if (unlikely (linep + 8 > lineendp))
5538 : : {
5539 : : invalid_data:
5540 : 0 : error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
5541 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
5542 : : return;
5543 : : }
5544 [ # # ][ # # ]: 0 : unit_length = read_8ubyte_unaligned_inc (dbg, linep);
5545 : 0 : length = 8;
5546 : : }
5547 : :
5548 : : /* Check whether we have enough room in the section. */
5549 [ - + ]: 1341 : if (unit_length < 2 + length + 5 * 1
5550 [ - + ]: 1341 : || unlikely (linep + unit_length > lineendp))
5551 : : goto invalid_data;
5552 : 1341 : lineendp = linep + unit_length;
5553 : :
5554 : : /* The next element of the header is the version identifier. */
5555 [ + + ][ - + ]: 1341 : uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
5556 : :
5557 : : /* Next comes the header length. */
5558 : : Dwarf_Word header_length;
5559 [ + - ]: 1341 : if (length == 4)
5560 [ + + ][ - + ]: 1341 : header_length = read_4ubyte_unaligned_inc (dbg, linep);
5561 : : else
5562 [ # # ][ # # ]: 0 : header_length = read_8ubyte_unaligned_inc (dbg, linep);
5563 : : //const unsigned char *header_start = linep;
5564 : :
5565 : : /* Next the minimum instruction length. */
5566 : 1341 : uint_fast8_t minimum_instr_len = *linep++;
5567 : :
5568 : : /* Next the maximum operations per instruction, in version 4 format. */
5569 [ - + ]: 1341 : uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++;
5570 : :
5571 : : /* Then the flag determining the default value of the is_stmt
5572 : : register. */
5573 : 1341 : uint_fast8_t default_is_stmt = *linep++;
5574 : :
5575 : : /* Now the line base. */
5576 : 1341 : int_fast8_t line_base = *((const int_fast8_t *) linep);
5577 : 1341 : ++linep;
5578 : :
5579 : : /* And the line range. */
5580 : 1341 : uint_fast8_t line_range = *linep++;
5581 : :
5582 : : /* The opcode base. */
5583 : 1341 : uint_fast8_t opcode_base = *linep++;
5584 : :
5585 : : /* Print what we got so far. */
5586 : 1341 : printf (gettext ("\n"
5587 : : " Length: %" PRIu64 "\n"
5588 : : " DWARF version: %" PRIuFAST16 "\n"
5589 : : " Prologue length: %" PRIu64 "\n"
5590 : : " Minimum instruction length: %" PRIuFAST8 "\n"
5591 : : " Maximum operations per instruction: %" PRIuFAST8 "\n"
5592 : : " Initial value if '%s': %" PRIuFAST8 "\n"
5593 : : " Line base: %" PRIdFAST8 "\n"
5594 : : " Line range: %" PRIuFAST8 "\n"
5595 : : " Opcode base: %" PRIuFAST8 "\n"
5596 : : "\n"
5597 : : "Opcodes:\n"),
5598 : : (uint64_t) unit_length, version, (uint64_t) header_length,
5599 : : minimum_instr_len, max_ops_per_instr,
5600 : : "is_stmt", default_is_stmt, line_base,
5601 : : line_range, opcode_base);
5602 : :
5603 [ - + ]: 1341 : if (unlikely (linep + opcode_base - 1 >= lineendp))
5604 : : {
5605 : : invalid_unit:
5606 : 0 : error (0, 0,
5607 : 0 : gettext ("invalid data at offset %tu in section [%zu] '%s'"),
5608 : 0 : linep - (const unsigned char *) data->d_buf,
5609 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
5610 : 0 : linep = lineendp;
5611 : 0 : continue;
5612 : : }
5613 : 1341 : int opcode_base_l10 = 1;
5614 : 1341 : unsigned int tmp = opcode_base;
5615 [ + + ]: 2680 : while (tmp > 10)
5616 : : {
5617 : 1339 : tmp /= 10;
5618 : 1339 : ++opcode_base_l10;
5619 : : }
5620 : 1341 : const uint8_t *standard_opcode_lengths = linep - 1;
5621 [ + + ]: 17427 : for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt)
5622 : 16086 : printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n",
5623 : : " [%*" PRIuFAST8 "] %hhu arguments\n",
5624 : : (int) linep[cnt - 1]),
5625 : 16086 : opcode_base_l10, cnt, linep[cnt - 1]);
5626 : 1341 : linep += opcode_base - 1;
5627 [ - + ]: 1341 : if (unlikely (linep >= lineendp))
5628 : : goto invalid_unit;
5629 : :
5630 : 1341 : puts (gettext ("\nDirectory table:"));
5631 [ + + ]: 9529 : while (*linep != 0)
5632 : : {
5633 : 8188 : unsigned char *endp = memchr (linep, '\0', lineendp - linep);
5634 [ - + ]: 8188 : if (unlikely (endp == NULL))
5635 : : goto invalid_unit;
5636 : :
5637 : 8188 : printf (" %s\n", (char *) linep);
5638 : :
5639 : 8188 : linep = endp + 1;
5640 : : }
5641 : : /* Skip the final NUL byte. */
5642 : 1341 : ++linep;
5643 : :
5644 [ - + ]: 1341 : if (unlikely (linep >= lineendp))
5645 : : goto invalid_unit;
5646 : 1341 : puts (gettext ("\nFile name table:\n"
5647 : : " Entry Dir Time Size Name"));
5648 [ + + ]: 21948 : for (unsigned int cnt = 1; *linep != 0; ++cnt)
5649 : : {
5650 : : /* First comes the file name. */
5651 : 20607 : char *fname = (char *) linep;
5652 : 20607 : unsigned char *endp = memchr (fname, '\0', lineendp - linep);
5653 [ - + ]: 20607 : if (unlikely (endp == NULL))
5654 : : goto invalid_unit;
5655 : 20607 : linep = endp + 1;
5656 : :
5657 : : /* Then the index. */
5658 : : unsigned int diridx;
5659 [ - + ]: 20607 : get_uleb128 (diridx, linep);
5660 : :
5661 : : /* Next comes the modification time. */
5662 : : unsigned int mtime;
5663 [ - + ]: 20607 : get_uleb128 (mtime, linep);
5664 : :
5665 : : /* Finally the length of the file. */
5666 : : unsigned int fsize;
5667 [ - + ]: 20607 : get_uleb128 (fsize, linep);
5668 : :
5669 : 20607 : printf (" %-5u %-5u %-9u %-9u %s\n",
5670 : : cnt, diridx, mtime, fsize, fname);
5671 : : }
5672 : : /* Skip the final NUL byte. */
5673 : 1341 : ++linep;
5674 : :
5675 : 1341 : puts (gettext ("\nLine number statements:"));
5676 : 1341 : Dwarf_Word address = 0;
5677 : 1341 : unsigned int op_index = 0;
5678 : 1341 : size_t line = 1;
5679 : 1341 : uint_fast8_t is_stmt = default_is_stmt;
5680 : :
5681 : : /* Default address value, in case we do not find the CU. */
5682 [ + + ]: 1341 : size_t address_size
5683 : 1341 : = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
5684 : :
5685 : : /* Determine the CU this block is for. */
5686 : : Dwarf_Off cuoffset;
5687 : 1341 : Dwarf_Off ncuoffset = 0;
5688 : : size_t hsize;
5689 [ + - ]: 71275 : while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
5690 : : NULL, NULL, NULL) == 0)
5691 : : {
5692 : : Dwarf_Die cudie;
5693 [ - + ]: 71275 : if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
5694 : 0 : continue;
5695 : : Dwarf_Attribute stmt_list;
5696 [ - + ]: 71275 : if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL)
5697 : 0 : continue;
5698 : : Dwarf_Word lineoff;
5699 [ - + ]: 71275 : if (dwarf_formudata (&stmt_list, &lineoff) != 0)
5700 : 0 : continue;
5701 [ + + ]: 71275 : if (lineoff == start_offset)
5702 : : {
5703 : : /* Found the CU. */
5704 : 71275 : address_size = cudie.cu->address_size;
5705 : : break;
5706 : : }
5707 : : }
5708 : :
5709 : : /* Apply the "operation advance" from a special opcode
5710 : : or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */
5711 : : unsigned int op_addr_advance;
5712 : : bool show_op_index;
5713 : 143232 : inline void advance_pc (unsigned int op_advance)
5714 : : {
5715 : 286464 : op_addr_advance = minimum_instr_len * ((op_index + op_advance)
5716 : 143232 : / max_ops_per_instr);
5717 : 143232 : address += op_advance;
5718 [ + - ][ + - ]: 143232 : show_op_index = (op_index > 0 ||
5719 : 143232 : (op_index + op_advance) % max_ops_per_instr > 0);
5720 : 143232 : op_index = (op_index + op_advance) % max_ops_per_instr;
5721 : 143232 : }
5722 : :
5723 [ + + ]: 217751 : while (linep < lineendp)
5724 : : {
5725 : 216410 : size_t offset = linep - (const unsigned char *) data->d_buf;
5726 : : unsigned int u128;
5727 : : int s128;
5728 : :
5729 : : /* Read the opcode. */
5730 : 216410 : unsigned int opcode = *linep++;
5731 : :
5732 : 216410 : printf (" [%6" PRIx64 "]", (uint64_t)offset);
5733 : : /* Is this a special opcode? */
5734 [ + + ]: 216410 : if (likely (opcode >= opcode_base))
5735 : : {
5736 : : /* Yes. Handling this is quite easy since the opcode value
5737 : : is computed with
5738 : :
5739 : : opcode = (desired line increment - line_base)
5740 : : + (line_range * address advance) + opcode_base
5741 : : */
5742 : 107557 : int line_increment = (line_base
5743 : 107557 : + (opcode - opcode_base) % line_range);
5744 : :
5745 : : /* Perform the increments. */
5746 : 107557 : line += line_increment;
5747 : 107557 : advance_pc ((opcode - opcode_base) / line_range);
5748 : :
5749 : 107557 : char *a = format_dwarf_addr (dwflmod, 0, address);
5750 [ - + ]: 107557 : if (show_op_index)
5751 : 0 : printf (gettext ("\
5752 : : special opcode %u: address+%u = %s, op_index = %u, line%+d = %zu\n"),
5753 : : opcode, op_addr_advance, a, op_index,
5754 : : line_increment, line);
5755 : : else
5756 : 107557 : printf (gettext ("\
5757 : : special opcode %u: address+%u = %s, line%+d = %zu\n"),
5758 : : opcode, op_addr_advance, a, line_increment, line);
5759 : 107557 : free (a);
5760 : : }
5761 [ + + ]: 108853 : else if (opcode == 0)
5762 : : {
5763 : : /* This an extended opcode. */
5764 [ - + ]: 16762 : if (unlikely (linep + 2 > lineendp))
5765 : : goto invalid_unit;
5766 : :
5767 : : /* The length. */
5768 : 16762 : unsigned int len = *linep++;
5769 : :
5770 [ - + ]: 16762 : if (unlikely (linep + len > lineendp))
5771 : : goto invalid_unit;
5772 : :
5773 : : /* The sub-opcode. */
5774 : 16762 : opcode = *linep++;
5775 : :
5776 : 16762 : printf (gettext (" extended opcode %u: "), opcode);
5777 : :
5778 [ + + - + : 16762 : switch (opcode)
- ]
5779 : : {
5780 : : case DW_LNE_end_sequence:
5781 : 2299 : puts (gettext (" end of sequence"));
5782 : :
5783 : : /* Reset the registers we care about. */
5784 : 2299 : address = 0;
5785 : 2299 : op_index = 0;
5786 : 2299 : line = 1;
5787 : 2299 : is_stmt = default_is_stmt;
5788 : 2299 : break;
5789 : :
5790 : : case DW_LNE_set_address:
5791 : 2299 : op_index = 0;
5792 [ + + ]: 2299 : if (address_size == 4)
5793 [ - + ][ # # ]: 4 : address = read_4ubyte_unaligned_inc (dbg, linep);
5794 : : else
5795 [ + + ][ - + ]: 2295 : address = read_8ubyte_unaligned_inc (dbg, linep);
5796 : : {
5797 : 2299 : char *a = format_dwarf_addr (dwflmod, 0, address);
5798 : 2299 : printf (gettext (" set address to %s\n"), a);
5799 : 2299 : free (a);
5800 : : }
5801 : 2299 : break;
5802 : :
5803 : : case DW_LNE_define_file:
5804 : : {
5805 : 0 : char *fname = (char *) linep;
5806 : 0 : unsigned char *endp = memchr (linep, '\0',
5807 : 0 : lineendp - linep);
5808 [ # # ]: 0 : if (unlikely (endp == NULL))
5809 : : goto invalid_unit;
5810 : 0 : linep = endp + 1;
5811 : :
5812 : : unsigned int diridx;
5813 [ # # ]: 0 : get_uleb128 (diridx, linep);
5814 : : Dwarf_Word mtime;
5815 [ # # ]: 0 : get_uleb128 (mtime, linep);
5816 : : Dwarf_Word filelength;
5817 [ # # ]: 0 : get_uleb128 (filelength, linep);
5818 : :
5819 : 0 : printf (gettext ("\
5820 : : define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
5821 : : diridx, (uint64_t) mtime, (uint64_t) filelength,
5822 : : fname);
5823 : : }
5824 : 0 : break;
5825 : :
5826 : : case DW_LNE_set_discriminator:
5827 : : /* Takes one ULEB128 parameter, the discriminator. */
5828 [ - + ]: 12164 : if (unlikely (standard_opcode_lengths[opcode] != 1))
5829 : : goto invalid_unit;
5830 : :
5831 [ - + ]: 12164 : get_uleb128 (u128, linep);
5832 : 12164 : printf (gettext (" set discriminator to %u\n"), u128);
5833 : 12164 : break;
5834 : :
5835 : : default:
5836 : : /* Unknown, ignore it. */
5837 : 0 : puts (gettext (" unknown opcode"));
5838 : 0 : linep += len - 1;
5839 : 0 : break;
5840 : : }
5841 : : }
5842 [ + - ]: 92091 : else if (opcode <= DW_LNS_set_isa)
5843 : : {
5844 : : /* This is a known standard opcode. */
5845 [ + + + + : 92091 : switch (opcode)
- + - + -
- - - - ]
5846 : : {
5847 : : case DW_LNS_copy:
5848 : : /* Takes no argument. */
5849 : 7985 : puts (gettext (" copy"));
5850 : 7985 : break;
5851 : :
5852 : : case DW_LNS_advance_pc:
5853 : : /* Takes one uleb128 parameter which is added to the
5854 : : address. */
5855 [ + + ]: 12490 : get_uleb128 (u128, linep);
5856 : 12281 : advance_pc (u128);
5857 : : {
5858 : 12281 : char *a = format_dwarf_addr (dwflmod, 0, address);
5859 [ - + ]: 12281 : if (show_op_index)
5860 : 0 : printf (gettext ("\
5861 : : advance address by %u to %s, op_index to %u\n"),
5862 : : op_addr_advance, a, op_index);
5863 : : else
5864 : 12281 : printf (gettext (" advance address by %u to %s\n"),
5865 : : op_addr_advance, a);
5866 : 12281 : free (a);
5867 : : }
5868 : 12281 : break;
5869 : :
5870 : : case DW_LNS_advance_line:
5871 : : /* Takes one sleb128 parameter which is added to the
5872 : : line. */
5873 [ + + ]: 37231 : get_sleb128 (s128, linep);
5874 : 37231 : line += s128;
5875 : 37231 : printf (gettext ("\
5876 : : advance line by constant %d to %" PRId64 "\n"),
5877 : : s128, (int64_t) line);
5878 : 37231 : break;
5879 : :
5880 : : case DW_LNS_set_file:
5881 : : /* Takes one uleb128 parameter which is stored in file. */
5882 [ - + ]: 5331 : get_uleb128 (u128, linep);
5883 : 5331 : printf (gettext (" set file to %" PRIu64 "\n"),
5884 : : (uint64_t) u128);
5885 : 5331 : break;
5886 : :
5887 : : case DW_LNS_set_column:
5888 : : /* Takes one uleb128 parameter which is stored in column. */
5889 [ # # ]: 0 : if (unlikely (standard_opcode_lengths[opcode] != 1))
5890 : : goto invalid_unit;
5891 : :
5892 [ # # ]: 0 : get_uleb128 (u128, linep);
5893 : 0 : printf (gettext (" set column to %" PRIu64 "\n"),
5894 : : (uint64_t) u128);
5895 : 0 : break;
5896 : :
5897 : : case DW_LNS_negate_stmt:
5898 : : /* Takes no argument. */
5899 : 5869 : is_stmt = 1 - is_stmt;
5900 : 5869 : printf (gettext (" set '%s' to %" PRIuFAST8 "\n"),
5901 : : "is_stmt", is_stmt);
5902 : 5869 : break;
5903 : :
5904 : : case DW_LNS_set_basic_block:
5905 : : /* Takes no argument. */
5906 : 0 : puts (gettext (" set basic block flag"));
5907 : 0 : break;
5908 : :
5909 : : case DW_LNS_const_add_pc:
5910 : : /* Takes no argument. */
5911 : 23394 : advance_pc ((255 - opcode_base) / line_range);
5912 : : {
5913 : 23394 : char *a = format_dwarf_addr (dwflmod, 0, address);
5914 [ - + ]: 23394 : if (show_op_index)
5915 : 0 : printf (gettext ("\
5916 : : advance address by constant %u to %s, op_index to %u\n"),
5917 : : op_addr_advance, a, op_index);
5918 : : else
5919 : 23394 : printf (gettext ("\
5920 : : advance address by constant %u to %s\n"),
5921 : : op_addr_advance, a);
5922 : 23394 : free (a);
5923 : : }
5924 : 23394 : break;
5925 : :
5926 : : case DW_LNS_fixed_advance_pc:
5927 : : /* Takes one 16 bit parameter which is added to the
5928 : : address. */
5929 [ # # ]: 0 : if (unlikely (standard_opcode_lengths[opcode] != 1))
5930 : : goto invalid_unit;
5931 : :
5932 [ # # ][ # # ]: 0 : u128 = read_2ubyte_unaligned_inc (dbg, linep);
5933 : 0 : address += u128;
5934 : 0 : op_index = 0;
5935 : : {
5936 : 0 : char *a = format_dwarf_addr (dwflmod, 0, address);
5937 : 0 : printf (gettext ("\
5938 : : advance address by fixed value %u to %s\n"),
5939 : : u128, a);
5940 : 0 : free (a);
5941 : : }
5942 : 0 : break;
5943 : :
5944 : : case DW_LNS_set_prologue_end:
5945 : : /* Takes no argument. */
5946 : 0 : puts (gettext (" set prologue end flag"));
5947 : 0 : break;
5948 : :
5949 : : case DW_LNS_set_epilogue_begin:
5950 : : /* Takes no argument. */
5951 : 0 : puts (gettext (" set epilogue begin flag"));
5952 : 0 : break;
5953 : :
5954 : : case DW_LNS_set_isa:
5955 : : /* Takes one uleb128 parameter which is stored in isa. */
5956 [ # # ]: 0 : if (unlikely (standard_opcode_lengths[opcode] != 1))
5957 : : goto invalid_unit;
5958 : :
5959 [ # # ]: 0 : get_uleb128 (u128, linep);
5960 : 0 : printf (gettext (" set isa to %u\n"), u128);
5961 : 0 : break;
5962 : : }
5963 : : }
5964 : : else
5965 : : {
5966 : : /* This is a new opcode the generator but not we know about.
5967 : : Read the parameters associated with it but then discard
5968 : : everything. Read all the parameters for this opcode. */
5969 : 0 : printf (ngettext (" unknown opcode with %" PRIu8 " parameter:",
5970 : : " unknown opcode with %" PRIu8 " parameters:",
5971 : : standard_opcode_lengths[opcode]),
5972 : 0 : standard_opcode_lengths[opcode]);
5973 [ # # ]: 0 : for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
5974 : : {
5975 [ # # ]: 0 : get_uleb128 (u128, linep);
5976 [ # # ]: 0 : if (n != standard_opcode_lengths[opcode])
5977 : 0 : putc_unlocked (',', stdout);
5978 : 0 : printf (" %u", u128);
5979 : : }
5980 : :
5981 : : /* Next round, ignore this opcode. */
5982 : 216410 : continue;
5983 : : }
5984 : : }
5985 : : }
5986 : :
5987 : : /* There must only be one data block. */
5988 [ - + ]: 38 : assert (elf_getdata (scn, data) == NULL);
5989 : : }
5990 : :
5991 : :
5992 : : static void
5993 : 30 : print_debug_loc_section (Dwfl_Module *dwflmod,
5994 : : Ebl *ebl, GElf_Ehdr *ehdr,
5995 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5996 : : {
5997 : 30 : Elf_Data *data = elf_rawdata (scn, NULL);
5998 : :
5999 [ - + ]: 30 : if (unlikely (data == NULL))
6000 : : {
6001 : 0 : error (0, 0, gettext ("cannot get .debug_loc content: %s"),
6002 : : elf_errmsg (-1));
6003 : 30 : return;
6004 : : }
6005 : :
6006 : 30 : printf (gettext ("\
6007 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6008 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6009 : : (uint64_t) shdr->sh_offset);
6010 : :
6011 : 30 : sort_listptr (&known_loclistptr, "loclistptr");
6012 : 30 : size_t listptr_idx = 0;
6013 : :
6014 [ + - ]: 30 : uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
6015 : 30 : uint_fast8_t offset_size = 4;
6016 : :
6017 : 30 : bool first = true;
6018 : 30 : unsigned char *readp = data->d_buf;
6019 : 30 : unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
6020 [ + + ]: 170556 : while (readp < endp)
6021 : : {
6022 : 170526 : ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
6023 : :
6024 [ + + ][ - + ]: 170526 : if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
6025 : : &address_size, &offset_size,
6026 : : offset, &readp, endp))
6027 : 0 : continue;
6028 : :
6029 [ - + ]: 170526 : if (unlikely (data->d_size - offset < address_size * 2))
6030 : : {
6031 : 0 : printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
6032 : 0 : break;
6033 : : }
6034 : :
6035 : : Dwarf_Addr begin;
6036 : : Dwarf_Addr end;
6037 [ + - ]: 170526 : if (address_size == 8)
6038 : : {
6039 [ - + ][ # # ]: 170526 : begin = read_8ubyte_unaligned_inc (dbg, readp);
6040 [ - + ][ # # ]: 170526 : end = read_8ubyte_unaligned_inc (dbg, readp);
6041 : : }
6042 : : else
6043 : : {
6044 [ # # ][ # # ]: 0 : begin = read_4ubyte_unaligned_inc (dbg, readp);
6045 [ # # ][ # # ]: 0 : end = read_4ubyte_unaligned_inc (dbg, readp);
6046 [ # # ]: 0 : if (begin == (Dwarf_Addr) (uint32_t) -1)
6047 : 0 : begin = (Dwarf_Addr) -1l;
6048 : : }
6049 : :
6050 [ - + ]: 170526 : if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
6051 : : {
6052 : 0 : char *b = format_dwarf_addr (dwflmod, address_size, end);
6053 : 0 : printf (gettext (" [%6tx] base address %s\n"), offset, b);
6054 : 0 : free (b);
6055 : : }
6056 [ + + ]: 170526 : else if (begin == 0 && end == 0) /* End of list entry. */
6057 : : {
6058 [ - + ]: 35277 : if (first)
6059 : 0 : printf (gettext (" [%6tx] empty list\n"), offset);
6060 : : first = true;
6061 : : }
6062 : : else
6063 : : {
6064 : : /* We have a location expression entry. */
6065 [ - + ][ # # ]: 135249 : uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
6066 : :
6067 : 135249 : char *b = format_dwarf_addr (dwflmod, address_size, begin);
6068 : 135249 : char *e = format_dwarf_addr (dwflmod, address_size, end);
6069 : :
6070 [ + + ]: 135249 : if (first) /* First entry in a list. */
6071 : 35277 : printf (gettext (" [%6tx] %s..%s"), offset, b, e);
6072 : : else
6073 : 99972 : printf (gettext (" %s..%s"), b, e);
6074 : :
6075 : 135249 : free (b);
6076 : 135249 : free (e);
6077 : :
6078 [ - + ]: 135249 : if (endp - readp <= (ptrdiff_t) len)
6079 : : {
6080 : 0 : fputs (gettext (" <INVALID DATA>\n"), stdout);
6081 : 0 : break;
6082 : : }
6083 : :
6084 : 135249 : print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
6085 : : 3 /*XXX*/, address_size, offset_size, len, readp);
6086 : :
6087 : 135249 : first = false;
6088 : 170526 : readp += len;
6089 : : }
6090 : : }
6091 : : }
6092 : :
6093 : : struct mac_culist
6094 : : {
6095 : : Dwarf_Die die;
6096 : : Dwarf_Off offset;
6097 : : Dwarf_Files *files;
6098 : : struct mac_culist *next;
6099 : : };
6100 : :
6101 : :
6102 : : static int
6103 : 0 : mac_compare (const void *p1, const void *p2)
6104 : : {
6105 : 0 : struct mac_culist *m1 = (struct mac_culist *) p1;
6106 : 0 : struct mac_culist *m2 = (struct mac_culist *) p2;
6107 : :
6108 [ # # ]: 0 : if (m1->offset < m2->offset)
6109 : : return -1;
6110 [ # # ]: 0 : if (m1->offset > m2->offset)
6111 : : return 1;
6112 : 0 : return 0;
6113 : : }
6114 : :
6115 : :
6116 : : static void
6117 : 0 : print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6118 : : Ebl *ebl, GElf_Ehdr *ehdr,
6119 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6120 : : {
6121 : 0 : printf (gettext ("\
6122 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6123 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6124 : : (uint64_t) shdr->sh_offset);
6125 : 0 : putc_unlocked ('\n', stdout);
6126 : :
6127 : : /* There is no function in libdw to iterate over the raw content of
6128 : : the section but it is easy enough to do. */
6129 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
6130 [ # # ][ # # ]: 0 : if (unlikely (data == NULL || data->d_buf == NULL))
6131 : : {
6132 : 0 : error (0, 0, gettext ("cannot get macro information section data: %s"),
6133 : : elf_errmsg (-1));
6134 : : return;
6135 : : }
6136 : :
6137 : : /* Get the source file information for all CUs. */
6138 : : Dwarf_Off offset;
6139 : 0 : Dwarf_Off ncu = 0;
6140 : : size_t hsize;
6141 : 0 : struct mac_culist *culist = NULL;
6142 : 0 : size_t nculist = 0;
6143 [ # # ]: 0 : while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
6144 : : {
6145 : : Dwarf_Die cudie;
6146 [ # # ]: 0 : if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
6147 : 0 : continue;
6148 : :
6149 : : Dwarf_Attribute attr;
6150 [ # # ]: 0 : if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL)
6151 : 0 : continue;
6152 : :
6153 : : Dwarf_Word macoff;
6154 [ # # ]: 0 : if (dwarf_formudata (&attr, &macoff) != 0)
6155 : 0 : continue;
6156 : :
6157 : 0 : struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
6158 : 0 : newp->die = cudie;
6159 : 0 : newp->offset = macoff;
6160 : 0 : newp->files = NULL;
6161 : 0 : newp->next = culist;
6162 : 0 : culist = newp;
6163 : 0 : ++nculist;
6164 : : }
6165 : :
6166 : : /* Convert the list into an array for easier consumption. */
6167 : 0 : struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1)
6168 : : * sizeof (*cus));
6169 : : /* Add sentinel. */
6170 : 0 : cus[nculist].offset = data->d_size;
6171 [ # # ]: 0 : if (nculist > 0)
6172 : : {
6173 [ # # ]: 0 : for (size_t cnt = nculist - 1; culist != NULL; --cnt)
6174 : : {
6175 [ # # ]: 0 : assert (cnt < nculist);
6176 : 0 : cus[cnt] = *culist;
6177 : 0 : culist = culist->next;
6178 : : }
6179 : :
6180 : : /* Sort the array according to the offset in the .debug_macinfo
6181 : : section. Note we keep the sentinel at the end. */
6182 : 0 : qsort (cus, nculist, sizeof (*cus), mac_compare);
6183 : : }
6184 : :
6185 : 0 : const unsigned char *readp = (const unsigned char *) data->d_buf;
6186 : 0 : const unsigned char *readendp = readp + data->d_size;
6187 : 0 : int level = 1;
6188 : :
6189 [ # # ]: 0 : while (readp < readendp)
6190 : : {
6191 : 0 : unsigned int opcode = *readp++;
6192 : : unsigned int u128;
6193 : : unsigned int u128_2;
6194 : : const unsigned char *endp;
6195 : :
6196 [ # # # # ]: 0 : switch (opcode)
6197 : : {
6198 : : case DW_MACINFO_define:
6199 : : case DW_MACINFO_undef:
6200 : : case DW_MACINFO_vendor_ext:
6201 : : /* For the first two opcodes the parameters are
6202 : : line, string
6203 : : For the latter
6204 : : number, string.
6205 : : We can treat these cases together. */
6206 [ # # ]: 0 : get_uleb128 (u128, readp);
6207 : :
6208 : 0 : endp = memchr (readp, '\0', readendp - readp);
6209 [ # # ]: 0 : if (unlikely (endp == NULL))
6210 : : {
6211 : 0 : printf (gettext ("\
6212 : : %*s*** non-terminated string at end of section"),
6213 : : level, "");
6214 : : return;
6215 : : }
6216 : :
6217 [ # # ]: 0 : if (opcode == DW_MACINFO_define)
6218 : 0 : printf ("%*s#define %s, line %u\n",
6219 : : level, "", (char *) readp, u128);
6220 [ # # ]: 0 : else if (opcode == DW_MACINFO_undef)
6221 : 0 : printf ("%*s#undef %s, line %u\n",
6222 : : level, "", (char *) readp, u128);
6223 : : else
6224 : 0 : printf (" #vendor-ext %s, number %u\n", (char *) readp, u128);
6225 : :
6226 : 0 : readp = endp + 1;
6227 : 0 : break;
6228 : :
6229 : : case DW_MACINFO_start_file:
6230 : : /* The two parameters are line and file index, in this order. */
6231 [ # # ]: 0 : get_uleb128 (u128, readp);
6232 [ # # ]: 0 : get_uleb128 (u128_2, readp);
6233 : :
6234 : : /* Find the CU DIE for this file. */
6235 : 0 : size_t macoff = readp - (const unsigned char *) data->d_buf;
6236 : 0 : const char *fname = "???";
6237 [ # # ]: 0 : if (macoff >= cus[0].offset)
6238 : : {
6239 [ # # ]: 0 : while (macoff >= cus[1].offset)
6240 : 0 : ++cus;
6241 : :
6242 [ # # ]: 0 : if (cus[0].files == NULL
6243 [ # # ]: 0 : && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0)
6244 : 0 : cus[0].files = (Dwarf_Files *) -1l;
6245 : :
6246 [ # # ]: 0 : if (cus[0].files != (Dwarf_Files *) -1l)
6247 : 0 : fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL)
6248 [ # # ]: 0 : ?: "???");
6249 : : }
6250 : :
6251 : 0 : printf ("%*sstart_file %u, [%u] %s\n",
6252 : : level, "", u128, u128_2, fname);
6253 : 0 : ++level;
6254 : 0 : break;
6255 : :
6256 : : case DW_MACINFO_end_file:
6257 : 0 : --level;
6258 : 0 : printf ("%*send_file\n", level, "");
6259 : : /* Nothing more to do. */
6260 : 0 : break;
6261 : :
6262 : : default:
6263 : : // XXX gcc seems to generate files with a trailing zero.
6264 [ # # ][ # # ]: 0 : if (unlikely (opcode != 0 || readp != readendp))
6265 : 0 : printf ("%*s*** invalid opcode %u\n", level, "", opcode);
6266 : : break;
6267 : : }
6268 : : }
6269 : : }
6270 : :
6271 : :
6272 : : static void
6273 : 1 : print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6274 : : Ebl *ebl, GElf_Ehdr *ehdr,
6275 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6276 : : {
6277 : 1 : printf (gettext ("\
6278 : : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6279 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6280 : : (uint64_t) shdr->sh_offset);
6281 : 1 : putc_unlocked ('\n', stdout);
6282 : :
6283 : 1 : Elf_Data *data = elf_getdata (scn, NULL);
6284 [ + - ][ - + ]: 1 : if (unlikely (data == NULL || data->d_buf == NULL))
6285 : : {
6286 : 0 : error (0, 0, gettext ("cannot get macro information section data: %s"),
6287 : : elf_errmsg (-1));
6288 : : return;
6289 : : }
6290 : :
6291 : : /* Get the source file information for all CUs. Uses same
6292 : : datastructure as macinfo. But uses offset field to directly
6293 : : match .debug_line offset. And just stored in a list. */
6294 : : Dwarf_Off offset;
6295 : 1 : Dwarf_Off ncu = 0;
6296 : : size_t hsize;
6297 : 1 : struct mac_culist *culist = NULL;
6298 : 1 : size_t nculist = 0;
6299 [ + + ]: 3 : while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
6300 : : {
6301 : : Dwarf_Die cudie;
6302 [ - + ]: 2 : if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
6303 : 0 : continue;
6304 : :
6305 : : Dwarf_Attribute attr;
6306 [ - + ]: 2 : if (dwarf_attr (&cudie, DW_AT_stmt_list, &attr) == NULL)
6307 : 0 : continue;
6308 : :
6309 : : Dwarf_Word lineoff;
6310 [ - + ]: 2 : if (dwarf_formudata (&attr, &lineoff) != 0)
6311 : 0 : continue;
6312 : :
6313 : 2 : struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
6314 : 2 : newp->die = cudie;
6315 : 2 : newp->offset = lineoff;
6316 : 2 : newp->files = NULL;
6317 : 2 : newp->next = culist;
6318 : 2 : culist = newp;
6319 : 2 : ++nculist;
6320 : : }
6321 : :
6322 : 1 : const unsigned char *readp = (const unsigned char *) data->d_buf;
6323 : 1 : const unsigned char *readendp = readp + data->d_size;
6324 : :
6325 [ + + ]: 5 : while (readp < readendp)
6326 : : {
6327 : 4 : printf (gettext (" Offset: 0x%" PRIx64 "\n"),
6328 : 4 : (uint64_t) (readp - (const unsigned char *) data->d_buf));
6329 : :
6330 : : // Header, 2 byte version, 1 byte flag, optional .debug_line offset,
6331 : : // optional vendor extension macro entry table.
6332 [ - + ]: 4 : if (readp + 2 > readendp)
6333 : : {
6334 : : invalid_data:
6335 : 0 : error (0, 0, gettext ("invalid data"));
6336 : : return;
6337 : : }
6338 [ - + ][ # # ]: 4 : const uint16_t vers = read_2ubyte_unaligned_inc (dbg, readp);
6339 : 4 : printf (gettext (" Version: %" PRIu16 "\n"), vers);
6340 : :
6341 : : // Version 4 is the GNU extension for DWARF4. DWARF5 will use version
6342 : : // 5 when it gets standardized.
6343 [ - + ]: 4 : if (vers != 4)
6344 : : {
6345 : 0 : printf (gettext (" unknown version, cannot parse section\n"));
6346 : : return;
6347 : : }
6348 : :
6349 [ - + ]: 4 : if (readp + 1 > readendp)
6350 : : goto invalid_data;
6351 : 4 : const unsigned char flag = *readp++;
6352 : 4 : printf (gettext (" Flag: 0x%" PRIx8 "\n"), flag);
6353 : :
6354 [ + - ]: 4 : unsigned int offset_len = (flag & 0x01) ? 8 : 4;
6355 : 4 : printf (gettext (" Offset length: %" PRIu8 "\n"), offset_len);
6356 : 4 : Dwarf_Off line_offset = -1;
6357 [ + + ]: 4 : if (flag & 0x02)
6358 : : {
6359 [ - + ]: 2 : if (offset_len == 8)
6360 [ # # ][ # # ]: 0 : line_offset = read_8ubyte_unaligned_inc (dbg, readp);
6361 : : else
6362 [ - + ][ # # ]: 2 : line_offset = read_4ubyte_unaligned_inc (dbg, readp);
6363 : 2 : printf (gettext (" .debug_line offset: 0x%" PRIx64 "\n"),
6364 : : line_offset);
6365 : : }
6366 : :
6367 : : const unsigned char *vendor[DW_MACRO_GNU_hi_user - DW_MACRO_GNU_lo_user];
6368 [ - + ]: 4 : if (flag & 0x04)
6369 : : {
6370 : : // 1 byte length, for each item, 1 byte opcode, uleb128 number
6371 : : // of arguments, for each argument 1 byte form code.
6372 [ # # ]: 0 : if (readp + 1 > readendp)
6373 : : goto invalid_data;
6374 : 0 : unsigned int tlen = *readp++;
6375 : 0 : printf (gettext (" extension opcode table, %" PRIu8 " items:\n"),
6376 : : tlen);
6377 [ # # ]: 0 : for (unsigned int i = 0; i < tlen; i++)
6378 : : {
6379 [ # # ]: 0 : if (readp + 1 > readendp)
6380 : : goto invalid_data;
6381 : 0 : unsigned int opcode = *readp++;
6382 : 0 : printf (gettext (" [%" PRIx8 "]"), opcode);
6383 [ # # ]: 0 : if (opcode < DW_MACRO_GNU_lo_user
6384 : 0 : || opcode > DW_MACRO_GNU_hi_user)
6385 : : goto invalid_data;
6386 : : // Record the start of description for this vendor opcode.
6387 : : // uleb128 nr args, 1 byte per arg form.
6388 : 0 : vendor[opcode - DW_MACRO_GNU_lo_user] = readp;
6389 [ # # ]: 0 : if (readp + 1 > readendp)
6390 : : goto invalid_data;
6391 : 0 : unsigned int args = *readp++;
6392 [ # # ]: 0 : if (args > 0)
6393 : : {
6394 : 0 : printf (gettext (" %" PRIu8 " arguments:"), args);
6395 [ # # ]: 0 : while (args > 0)
6396 : : {
6397 [ # # ]: 0 : if (readp + 1 > readendp)
6398 : : goto invalid_data;
6399 : 0 : unsigned int form = *readp++;
6400 : 0 : printf (" %s", dwarf_form_string (form));
6401 [ # # ]: 0 : if (form != DW_FORM_data1
6402 : 0 : && form != DW_FORM_data2
6403 : : && form != DW_FORM_data4
6404 [ # # ]: 0 : && form != DW_FORM_data8
6405 : 0 : && form != DW_FORM_sdata
6406 [ # # ]: 0 : && form != DW_FORM_udata
6407 : : && form != DW_FORM_block
6408 [ # # ]: 0 : && form != DW_FORM_block1
6409 : : && form != DW_FORM_block2
6410 [ # # ]: 0 : && form != DW_FORM_block4
6411 : 0 : && form != DW_FORM_flag
6412 [ # # ]: 0 : && form != DW_FORM_string
6413 : 0 : && form != DW_FORM_strp
6414 [ # # ]: 0 : && form != DW_FORM_sec_offset)
6415 : : goto invalid_data;
6416 : 0 : args--;
6417 [ # # ]: 0 : if (args > 0)
6418 : : putchar_unlocked (',');
6419 : : }
6420 : : }
6421 : : else
6422 : 0 : printf (gettext (" no arguments."));
6423 : : putchar_unlocked ('\n');
6424 : : }
6425 : : }
6426 : : putchar_unlocked ('\n');
6427 : :
6428 : 4 : int level = 1;
6429 [ - + ]: 4 : if (readp + 1 > readendp)
6430 : : goto invalid_data;
6431 : 4 : unsigned int opcode = *readp++;
6432 [ + + ]: 255 : while (opcode != 0)
6433 : : {
6434 : : unsigned int u128;
6435 : : unsigned int u128_2;
6436 : : const unsigned char *endp;
6437 : : uint64_t off;
6438 : :
6439 [ + + + - : 251 : switch (opcode)
+ + + - ]
6440 : : {
6441 : : case DW_MACRO_GNU_start_file:
6442 [ - + ]: 4 : get_uleb128 (u128, readp);
6443 [ - + ]: 4 : get_uleb128 (u128_2, readp);
6444 : :
6445 : : /* Find the CU DIE that matches this line offset. */
6446 : 4 : const char *fname = "???";
6447 [ + - ]: 4 : if (line_offset != (Dwarf_Off) -1)
6448 : : {
6449 : : struct mac_culist *cu = culist;
6450 [ + - ][ + + ]: 6 : while (cu != NULL && line_offset != cu->offset)
6451 : 2 : cu = cu->next;
6452 [ + - ]: 4 : if (cu != NULL)
6453 : : {
6454 [ + + ]: 4 : if (cu->files == NULL
6455 [ - + ]: 2 : && dwarf_getsrcfiles (&cu->die, &cu->files,
6456 : : NULL) != 0)
6457 : 0 : cu->files = (Dwarf_Files *) -1l;
6458 : :
6459 [ + - ]: 4 : if (cu->files != (Dwarf_Files *) -1l)
6460 : 8 : fname = (dwarf_filesrc (cu->files, u128_2,
6461 [ + - ]: 4 : NULL, NULL) ?: "???");
6462 : : }
6463 : : }
6464 : 4 : printf ("%*sstart_file %u, [%u] %s\n",
6465 : : level, "", u128, u128_2, fname);
6466 : 4 : ++level;
6467 : 4 : break;
6468 : :
6469 : : case DW_MACRO_GNU_end_file:
6470 : 4 : --level;
6471 : 4 : printf ("%*send_file\n", level, "");
6472 : 4 : break;
6473 : :
6474 : : case DW_MACRO_GNU_define:
6475 [ - + ]: 1 : get_uleb128 (u128, readp);
6476 : 1 : endp = memchr (readp, '\0', readendp - readp);
6477 [ - + ]: 1 : if (endp == NULL)
6478 : : goto invalid_data;
6479 : 1 : printf ("%*s#define %s, line %u\n",
6480 : : level, "", readp, u128);
6481 : 1 : readp = endp + 1;
6482 : 1 : break;
6483 : :
6484 : : case DW_MACRO_GNU_undef:
6485 [ # # ]: 0 : get_uleb128 (u128, readp);
6486 : 0 : endp = memchr (readp, '\0', readendp - readp);
6487 [ # # ]: 0 : if (endp == NULL)
6488 : : goto invalid_data;
6489 : 0 : printf ("%*s#undef %s, line %u\n",
6490 : : level, "", readp, u128);
6491 : 0 : readp = endp + 1;
6492 : 0 : break;
6493 : :
6494 : : case DW_MACRO_GNU_define_indirect:
6495 [ - + ]: 237 : get_uleb128 (u128, readp);
6496 [ - + ]: 237 : if (readp + offset_len > readendp)
6497 : : goto invalid_data;
6498 [ - + ]: 237 : if (offset_len == 8)
6499 [ # # ][ # # ]: 0 : off = read_8ubyte_unaligned_inc (dbg, readp);
6500 : : else
6501 [ - + ][ # # ]: 237 : off = read_4ubyte_unaligned_inc (dbg, readp);
6502 : 237 : printf ("%*s#define %s, line %u (indirect)\n",
6503 : : level, "", dwarf_getstring (dbg, off, NULL), u128);
6504 : 237 : break;
6505 : :
6506 : : case DW_MACRO_GNU_undef_indirect:
6507 [ - + ]: 1 : get_uleb128 (u128, readp);
6508 [ - + ]: 1 : if (readp + offset_len > readendp)
6509 : : goto invalid_data;
6510 [ - + ]: 1 : if (offset_len == 8)
6511 [ # # ][ # # ]: 0 : off = read_8ubyte_unaligned_inc (dbg, readp);
6512 : : else
6513 [ - + ][ # # ]: 1 : off = read_4ubyte_unaligned_inc (dbg, readp);
6514 : 1 : printf ("%*s#undef %s, line %u (indirect)\n",
6515 : : level, "", dwarf_getstring (dbg, off, NULL), u128);
6516 : 1 : break;
6517 : :
6518 : : case DW_MACRO_GNU_transparent_include:
6519 [ - + ]: 4 : if (readp + offset_len > readendp)
6520 : : goto invalid_data;
6521 [ - + ]: 4 : if (offset_len == 8)
6522 [ # # ][ # # ]: 0 : off = read_8ubyte_unaligned_inc (dbg, readp);
6523 : : else
6524 [ - + ][ # # ]: 4 : off = read_4ubyte_unaligned_inc (dbg, readp);
6525 : 4 : printf ("%*s#include offset 0x%" PRIx64 "\n",
6526 : : level, "", off);
6527 : 4 : break;
6528 : :
6529 : : default:
6530 : 0 : printf ("%*svendor opcode 0x%" PRIx8, level, "", opcode);
6531 [ # # ]: 0 : if (opcode < DW_MACRO_GNU_lo_user
6532 : : || opcode > DW_MACRO_GNU_lo_user
6533 [ # # ]: 0 : || vendor[opcode - DW_MACRO_GNU_lo_user] == NULL)
6534 : : goto invalid_data;
6535 : :
6536 : : const unsigned char *op_desc;
6537 : 0 : op_desc = vendor[opcode - DW_MACRO_GNU_lo_user];
6538 : :
6539 : : // Just skip the arguments, we cannot really interpret them,
6540 : : // but print as much as we can.
6541 : 0 : unsigned int args = *op_desc++;
6542 [ # # ]: 0 : while (args > 0)
6543 : : {
6544 : 0 : unsigned int form = *op_desc++;
6545 : : Dwarf_Word val;
6546 [ # # # # : 0 : switch (form)
# # # # #
# # # # #
# ]
6547 : : {
6548 : : case DW_FORM_data1:
6549 [ # # ]: 0 : if (readp + 1 > readendp)
6550 : : goto invalid_data;
6551 : 0 : val = *readp++;
6552 : 0 : printf (" %" PRIx8, (unsigned int) val);
6553 : 0 : break;
6554 : :
6555 : : case DW_FORM_data2:
6556 [ # # ]: 0 : if (readp + 2 > readendp)
6557 : : goto invalid_data;
6558 [ # # ][ # # ]: 0 : val = read_2ubyte_unaligned_inc (dbg, readp);
6559 : 0 : printf(" %" PRIx16, (unsigned int) val);
6560 : 0 : break;
6561 : :
6562 : : case DW_FORM_data4:
6563 [ # # ]: 0 : if (readp + 4 > readendp)
6564 : : goto invalid_data;
6565 [ # # ][ # # ]: 0 : val = read_4ubyte_unaligned_inc (dbg, readp);
6566 : 0 : printf (" %" PRIx32, (unsigned int) val);
6567 : 0 : break;
6568 : :
6569 : : case DW_FORM_data8:
6570 [ # # ]: 0 : if (readp + 8 > readendp)
6571 : : goto invalid_data;
6572 [ # # ][ # # ]: 0 : val = read_8ubyte_unaligned_inc (dbg, readp);
6573 : 0 : printf (" %" PRIx64, val);
6574 : 0 : break;
6575 : :
6576 : : case DW_FORM_sdata:
6577 [ # # ]: 0 : get_sleb128 (val, readp);
6578 : 0 : printf (" %" PRIx64, val);
6579 : 0 : break;
6580 : :
6581 : : case DW_FORM_udata:
6582 [ # # ]: 0 : get_uleb128 (val, readp);
6583 : 0 : printf (" %" PRIx64, val);
6584 : 0 : break;
6585 : :
6586 : : case DW_FORM_block:
6587 [ # # ]: 0 : get_uleb128 (val, readp);
6588 : 0 : printf (" block[%" PRIu64 "]", val);
6589 [ # # ]: 0 : if (readp + val > readendp)
6590 : : goto invalid_data;
6591 : 0 : readp += val;
6592 : 0 : break;
6593 : :
6594 : : case DW_FORM_block1:
6595 [ # # ]: 0 : if (readp + 1 > readendp)
6596 : : goto invalid_data;
6597 : 0 : val = *readp++;
6598 : 0 : printf (" block[%" PRIu64 "]", val);
6599 [ # # ]: 0 : if (readp + val > readendp)
6600 : : goto invalid_data;
6601 : : break;
6602 : :
6603 : : case DW_FORM_block2:
6604 [ # # ]: 0 : if (readp + 2 > readendp)
6605 : : goto invalid_data;
6606 [ # # ][ # # ]: 0 : val = read_2ubyte_unaligned_inc (dbg, readp);
6607 : 0 : printf (" block[%" PRIu64 "]", val);
6608 [ # # ]: 0 : if (readp + val > readendp)
6609 : : goto invalid_data;
6610 : : break;
6611 : :
6612 : : case DW_FORM_block4:
6613 [ # # ]: 0 : if (readp + 2 > readendp)
6614 : : goto invalid_data;
6615 [ # # ][ # # ]: 0 : val =read_4ubyte_unaligned_inc (dbg, readp);
6616 : 0 : printf (" block[%" PRIu64 "]", val);
6617 [ # # ]: 0 : if (readp + val > readendp)
6618 : : goto invalid_data;
6619 : : break;
6620 : :
6621 : : case DW_FORM_flag:
6622 [ # # ]: 0 : if (readp + 1 > readendp)
6623 : : goto invalid_data;
6624 : 0 : val = *readp++;
6625 [ # # ]: 0 : printf (" %s", nl_langinfo (val != 0 ? YESSTR : NOSTR));
6626 : 0 : break;
6627 : :
6628 : : case DW_FORM_string:
6629 : 0 : endp = memchr (readp, '\0', readendp - readp);
6630 [ # # ]: 0 : if (endp == NULL)
6631 : : goto invalid_data;
6632 : 0 : printf (" %s", readp);
6633 : 0 : readp = endp + 1;
6634 : 0 : break;
6635 : :
6636 : : case DW_FORM_strp:
6637 [ # # ]: 0 : if (readp + offset_len > readendp)
6638 : : goto invalid_data;
6639 [ # # ]: 0 : if (offset_len == 8)
6640 [ # # ][ # # ]: 0 : val = read_8ubyte_unaligned_inc (dbg, readp);
6641 : : else
6642 [ # # ][ # # ]: 0 : val = read_4ubyte_unaligned_inc (dbg, readp);
6643 : 0 : printf (" %s", dwarf_getstring (dbg, val, NULL));
6644 : 0 : break;
6645 : :
6646 : : case DW_FORM_sec_offset:
6647 [ # # ]: 0 : if (readp + offset_len > readendp)
6648 : : goto invalid_data;
6649 [ # # ]: 0 : if (offset_len == 8)
6650 [ # # ][ # # ]: 0 : val = read_8ubyte_unaligned_inc (dbg, readp);
6651 : : else
6652 [ # # ][ # # ]: 0 : val = read_4ubyte_unaligned_inc (dbg, readp);
6653 : 0 : printf (" %" PRIx64, val);
6654 : 0 : break;
6655 : :
6656 : : default:
6657 : 0 : error (0, 0, gettext ("vendor opcode not verified?"));
6658 : : return;
6659 : : }
6660 : :
6661 : 0 : args--;
6662 [ # # ]: 0 : if (args > 0)
6663 : : putchar_unlocked (',');
6664 : : }
6665 : : putchar_unlocked ('\n');
6666 : : }
6667 : :
6668 [ - + ]: 251 : if (readp + 1 > readendp)
6669 : : goto invalid_data;
6670 : 251 : opcode = *readp++;
6671 [ + + ]: 251 : if (opcode == 0)
6672 : : putchar_unlocked ('\n');
6673 : : }
6674 : : }
6675 : : }
6676 : :
6677 : :
6678 : : /* Callback for printing global names. */
6679 : : static int
6680 : 34 : print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
6681 : : void *arg)
6682 : : {
6683 : 34 : int *np = (int *) arg;
6684 : :
6685 : 34 : printf (gettext (" [%5d] DIE offset: %6" PRId64
6686 : : ", CU DIE offset: %6" PRId64 ", name: %s\n"),
6687 : 34 : (*np)++, global->die_offset, global->cu_offset, global->name);
6688 : :
6689 : 34 : return 0;
6690 : : }
6691 : :
6692 : :
6693 : : /* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
6694 : : static void
6695 : 8 : print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6696 : : Ebl *ebl, GElf_Ehdr *ehdr,
6697 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6698 : : {
6699 : 8 : printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6700 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6701 : : (uint64_t) shdr->sh_offset);
6702 : :
6703 : 8 : int n = 0;
6704 : 8 : (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
6705 : 8 : }
6706 : :
6707 : : /* Print the content of the DWARF string section '.debug_str'. */
6708 : : static void
6709 : 38 : print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6710 : : Ebl *ebl, GElf_Ehdr *ehdr,
6711 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6712 : : {
6713 : 76 : const size_t sh_size = (dbg->sectiondata[IDX_debug_str] ?
6714 [ + - ]: 38 : dbg->sectiondata[IDX_debug_str]->d_size : 0);
6715 : :
6716 : : /* Compute floor(log16(shdr->sh_size)). */
6717 : 38 : GElf_Addr tmp = sh_size;
6718 : 38 : int digits = 1;
6719 [ + + ]: 148 : while (tmp >= 16)
6720 : : {
6721 : 110 : ++digits;
6722 : 110 : tmp >>= 4;
6723 : : }
6724 : 38 : digits = MAX (4, digits);
6725 : :
6726 : 38 : printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
6727 : : " %*s String\n"),
6728 : : elf_ndxscn (scn),
6729 : : section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset,
6730 : : /* TRANS: the debugstr| prefix makes the string unique. */
6731 [ + - ]: 38 : digits + 2, sgettext ("debugstr|Offset"));
6732 : :
6733 : 38 : Dwarf_Off offset = 0;
6734 [ + + ]: 63043 : while (offset < sh_size)
6735 : : {
6736 : : size_t len;
6737 : 63005 : const char *str = dwarf_getstring (dbg, offset, &len);
6738 [ - + ]: 63005 : if (unlikely (str == NULL))
6739 : : {
6740 : 0 : printf (gettext (" *** error while reading strings: %s\n"),
6741 : : dwarf_errmsg (-1));
6742 : : break;
6743 : : }
6744 : :
6745 : 63005 : printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str);
6746 : :
6747 : 63005 : offset += len + 1;
6748 : : }
6749 : 38 : }
6750 : :
6751 : :
6752 : : /* Print the content of the call frame search table section
6753 : : '.eh_frame_hdr'. */
6754 : : static void
6755 : 26 : print_debug_frame_hdr_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6756 : : Ebl *ebl __attribute__ ((unused)),
6757 : : GElf_Ehdr *ehdr __attribute__ ((unused)),
6758 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6759 : : {
6760 : 26 : printf (gettext ("\
6761 : : \nCall frame search table section [%2zu] '.eh_frame_hdr':\n"),
6762 : : elf_ndxscn (scn));
6763 : :
6764 : 26 : Elf_Data *data = elf_rawdata (scn, NULL);
6765 : :
6766 [ - + ]: 26 : if (unlikely (data == NULL))
6767 : : {
6768 : 0 : error (0, 0, gettext ("cannot get %s content: %s"),
6769 : : ".eh_frame_hdr", elf_errmsg (-1));
6770 : : return;
6771 : : }
6772 : :
6773 : 26 : const unsigned char *readp = data->d_buf;
6774 : 26 : const unsigned char *const dataend = ((unsigned char *) data->d_buf
6775 : 26 : + data->d_size);
6776 : :
6777 [ - + ]: 26 : if (unlikely (readp + 4 > dataend))
6778 : : {
6779 : : invalid_data:
6780 : 0 : error (0, 0, gettext ("invalid data"));
6781 : : return;
6782 : : }
6783 : :
6784 : 26 : unsigned int version = *readp++;
6785 : 26 : unsigned int eh_frame_ptr_enc = *readp++;
6786 : 26 : unsigned int fde_count_enc = *readp++;
6787 : 26 : unsigned int table_enc = *readp++;
6788 : :
6789 : 26 : printf (" version: %u\n"
6790 : : " eh_frame_ptr_enc: %#x ",
6791 : : version, eh_frame_ptr_enc);
6792 : 26 : print_encoding_base ("", eh_frame_ptr_enc);
6793 : 26 : printf (" fde_count_enc: %#x ", fde_count_enc);
6794 : 26 : print_encoding_base ("", fde_count_enc);
6795 : 26 : printf (" table_enc: %#x ", table_enc);
6796 : 26 : print_encoding_base ("", table_enc);
6797 : :
6798 : 26 : uint64_t eh_frame_ptr = 0;
6799 [ + - ]: 26 : if (eh_frame_ptr_enc != DW_EH_PE_omit)
6800 : : {
6801 : 26 : readp = read_encoded (eh_frame_ptr_enc, readp, dataend, &eh_frame_ptr,
6802 : : dbg);
6803 [ - + ]: 26 : if (unlikely (readp == NULL))
6804 : : goto invalid_data;
6805 : :
6806 : 26 : printf (" eh_frame_ptr: %#" PRIx64, eh_frame_ptr);
6807 [ + - ]: 26 : if ((eh_frame_ptr_enc & 0x70) == DW_EH_PE_pcrel)
6808 : 26 : printf (" (offset: %#" PRIx64 ")",
6809 : : /* +4 because of the 4 byte header of the section. */
6810 : 26 : (uint64_t) shdr->sh_offset + 4 + eh_frame_ptr);
6811 : :
6812 : : putchar_unlocked ('\n');
6813 : : }
6814 : :
6815 : 26 : uint64_t fde_count = 0;
6816 [ + - ]: 26 : if (fde_count_enc != DW_EH_PE_omit)
6817 : : {
6818 : 26 : readp = read_encoded (fde_count_enc, readp, dataend, &fde_count, dbg);
6819 [ - + ]: 26 : if (unlikely (readp == NULL))
6820 : : goto invalid_data;
6821 : :
6822 : 26 : printf (" fde_count: %" PRIu64 "\n", fde_count);
6823 : : }
6824 : :
6825 [ + - ][ + - ]: 26 : if (fde_count == 0 || table_enc == DW_EH_PE_omit)
6826 : : return;
6827 : :
6828 : 26 : puts (" Table:");
6829 : :
6830 : : /* Optimize for the most common case. */
6831 [ + - ]: 26 : if (table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
6832 [ + - ][ + + ]: 4391 : while (fde_count > 0 && readp + 8 <= dataend)
6833 : : {
6834 [ - + ][ # # ]: 4365 : int32_t initial_location = read_4sbyte_unaligned_inc (dbg, readp);
6835 : 8730 : uint64_t initial_offset = ((uint64_t) shdr->sh_offset
6836 : 4365 : + (int64_t) initial_location);
6837 [ - + ][ # # ]: 4365 : int32_t address = read_4sbyte_unaligned_inc (dbg, readp);
6838 : : // XXX Possibly print symbol name or section offset for initial_offset
6839 : 4365 : printf (" %#" PRIx32 " (offset: %#6" PRIx64 ") -> %#" PRIx32
6840 : : " fde=[%6" PRIx64 "]\n",
6841 : : initial_location, initial_offset,
6842 : 4365 : address, address - (eh_frame_ptr + 4));
6843 : : }
6844 : : else
6845 : : while (0 && readp < dataend)
6846 : : {
6847 : :
6848 : : }
6849 : : }
6850 : :
6851 : :
6852 : : /* Print the content of the exception handling table section
6853 : : '.eh_frame_hdr'. */
6854 : : static void
6855 : 0 : print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
6856 : : Ebl *ebl __attribute__ ((unused)),
6857 : : GElf_Ehdr *ehdr __attribute__ ((unused)),
6858 : : Elf_Scn *scn,
6859 : : GElf_Shdr *shdr __attribute__ ((unused)),
6860 : : Dwarf *dbg __attribute__ ((unused)))
6861 : : {
6862 : 0 : printf (gettext ("\
6863 : : \nException handling table section [%2zu] '.gcc_except_table':\n"),
6864 : : elf_ndxscn (scn));
6865 : :
6866 : 0 : Elf_Data *data = elf_rawdata (scn, NULL);
6867 : :
6868 [ # # ]: 0 : if (unlikely (data == NULL))
6869 : : {
6870 : 0 : error (0, 0, gettext ("cannot get %s content: %s"),
6871 : : ".gcc_except_table", elf_errmsg (-1));
6872 : : return;
6873 : : }
6874 : :
6875 : 0 : const unsigned char *readp = data->d_buf;
6876 : 0 : const unsigned char *const dataend = readp + data->d_size;
6877 : :
6878 [ # # ]: 0 : if (unlikely (readp + 1 > dataend))
6879 : : {
6880 : : invalid_data:
6881 : 0 : error (0, 0, gettext ("invalid data"));
6882 : : return;
6883 : : }
6884 : 0 : unsigned int lpstart_encoding = *readp++;
6885 : 0 : printf (gettext (" LPStart encoding: %#x "), lpstart_encoding);
6886 : 0 : print_encoding_base ("", lpstart_encoding);
6887 [ # # ]: 0 : if (lpstart_encoding != DW_EH_PE_omit)
6888 : : {
6889 : : uint64_t lpstart;
6890 : 0 : readp = read_encoded (lpstart_encoding, readp, dataend, &lpstart, dbg);
6891 : 0 : printf (" LPStart: %#" PRIx64 "\n", lpstart);
6892 : : }
6893 : :
6894 [ # # ]: 0 : if (unlikely (readp + 1 > dataend))
6895 : : goto invalid_data;
6896 : 0 : unsigned int ttype_encoding = *readp++;
6897 : 0 : printf (gettext (" TType encoding: %#x "), ttype_encoding);
6898 : 0 : print_encoding_base ("", ttype_encoding);
6899 : 0 : const unsigned char *ttype_base = NULL;
6900 [ # # ]: 0 : if (ttype_encoding != DW_EH_PE_omit)
6901 : : {
6902 : : unsigned int ttype_base_offset;
6903 [ # # ]: 0 : get_uleb128 (ttype_base_offset, readp);
6904 : 0 : printf (" TType base offset: %#x\n", ttype_base_offset);
6905 : 0 : ttype_base = readp + ttype_base_offset;
6906 : : }
6907 : :
6908 [ # # ]: 0 : if (unlikely (readp + 1 > dataend))
6909 : : goto invalid_data;
6910 : 0 : unsigned int call_site_encoding = *readp++;
6911 : 0 : printf (gettext (" Call site encoding: %#x "), call_site_encoding);
6912 : 0 : print_encoding_base ("", call_site_encoding);
6913 : : unsigned int call_site_table_len;
6914 [ # # ]: 0 : get_uleb128 (call_site_table_len, readp);
6915 : :
6916 : 0 : const unsigned char *const action_table = readp + call_site_table_len;
6917 [ # # ]: 0 : if (unlikely (action_table > dataend))
6918 : : goto invalid_data;
6919 : : unsigned int u = 0;
6920 : : unsigned int max_action = 0;
6921 [ # # ]: 0 : while (readp < action_table)
6922 : : {
6923 [ # # ]: 0 : if (u == 0)
6924 : 0 : puts (gettext ("\n Call site table:"));
6925 : :
6926 : : uint64_t call_site_start;
6927 : 0 : readp = read_encoded (call_site_encoding, readp, dataend,
6928 : : &call_site_start, dbg);
6929 : : uint64_t call_site_length;
6930 : 0 : readp = read_encoded (call_site_encoding, readp, dataend,
6931 : : &call_site_length, dbg);
6932 : : uint64_t landing_pad;
6933 : 0 : readp = read_encoded (call_site_encoding, readp, dataend,
6934 : : &landing_pad, dbg);
6935 : : unsigned int action;
6936 [ # # ]: 0 : get_uleb128 (action, readp);
6937 : 0 : max_action = MAX (action, max_action);
6938 : 0 : printf (gettext (" [%4u] Call site start: %#" PRIx64 "\n"
6939 : : " Call site length: %" PRIu64 "\n"
6940 : : " Landing pad: %#" PRIx64 "\n"
6941 : : " Action: %u\n"),
6942 : : u++, call_site_start, call_site_length, landing_pad, action);
6943 : : }
6944 [ # # ]: 0 : assert (readp == action_table);
6945 : :
6946 : 0 : unsigned int max_ar_filter = 0;
6947 [ # # ]: 0 : if (max_action > 0)
6948 : : {
6949 : 0 : puts ("\n Action table:");
6950 : :
6951 : 0 : const unsigned char *const action_table_end
6952 : 0 : = action_table + max_action + 1;
6953 : :
6954 : 0 : u = 0;
6955 : : do
6956 : : {
6957 : : int ar_filter;
6958 [ # # ]: 0 : get_sleb128 (ar_filter, readp);
6959 [ # # ]: 0 : if (ar_filter > 0 && (unsigned int) ar_filter > max_ar_filter)
6960 : 0 : max_ar_filter = ar_filter;
6961 : : int ar_disp;
6962 [ # # ]: 0 : get_sleb128 (ar_disp, readp);
6963 : :
6964 : 0 : printf (" [%4u] ar_filter: % d\n"
6965 : : " ar_disp: % -5d",
6966 : : u, ar_filter, ar_disp);
6967 [ # # ]: 0 : if (abs (ar_disp) & 1)
6968 : 0 : printf (" -> [%4u]\n", u + (ar_disp + 1) / 2);
6969 [ # # ]: 0 : else if (ar_disp != 0)
6970 : 0 : puts (" -> ???");
6971 : : else
6972 : : putchar_unlocked ('\n');
6973 : 0 : ++u;
6974 : : }
6975 [ # # ]: 0 : while (readp < action_table_end);
6976 : : }
6977 : :
6978 [ # # ]: 0 : if (max_ar_filter > 0)
6979 : : {
6980 : 0 : puts ("\n TType table:");
6981 : :
6982 : : // XXX Not *4, size of encoding;
6983 [ # # # # ]: 0 : switch (ttype_encoding & 7)
6984 : : {
6985 : : case DW_EH_PE_udata2:
6986 : : case DW_EH_PE_sdata2:
6987 : 0 : readp = ttype_base - max_ar_filter * 2;
6988 : 0 : break;
6989 : : case DW_EH_PE_udata4:
6990 : : case DW_EH_PE_sdata4:
6991 : 0 : readp = ttype_base - max_ar_filter * 4;
6992 : 0 : break;
6993 : : case DW_EH_PE_udata8:
6994 : : case DW_EH_PE_sdata8:
6995 : 0 : readp = ttype_base - max_ar_filter * 8;
6996 : 0 : break;
6997 : : default:
6998 : 0 : error (1, 0, gettext ("invalid TType encoding"));
6999 : : }
7000 : :
7001 : : do
7002 : : {
7003 : : uint64_t ttype;
7004 : 0 : readp = read_encoded (ttype_encoding, readp, ttype_base, &ttype,
7005 : : dbg);
7006 : 0 : printf (" [%4u] %#" PRIx64 "\n", max_ar_filter--, ttype);
7007 : : }
7008 [ # # ]: 0 : while (readp < ttype_base);
7009 : : }
7010 : : }
7011 : :
7012 : : /* Print the content of the '.gdb_index' section.
7013 : : http://sourceware.org/gdb/current/onlinedocs/gdb/Index-Section-Format.html
7014 : : */
7015 : : static void
7016 : 2 : print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
7017 : : Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7018 : : {
7019 : 2 : printf (gettext ("\nGDB section [%2zu] '%s' at offset %#" PRIx64
7020 : : " contains %" PRId64 " bytes :\n"),
7021 : : elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
7022 : : (uint64_t) shdr->sh_offset, (uint64_t) shdr->sh_size);
7023 : :
7024 : 2 : Elf_Data *data = elf_rawdata (scn, NULL);
7025 : :
7026 [ - + ]: 2 : if (unlikely (data == NULL))
7027 : : {
7028 : 0 : error (0, 0, gettext ("cannot get %s content: %s"),
7029 : : ".gdb_index", elf_errmsg (-1));
7030 : : return;
7031 : : }
7032 : :
7033 : : // .gdb_index is always in little endian.
7034 : 2 : Dwarf dummy_dbg = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB };
7035 : 2 : dbg = &dummy_dbg;
7036 : :
7037 : 2 : const unsigned char *readp = data->d_buf;
7038 : 2 : const unsigned char *const dataend = readp + data->d_size;
7039 : :
7040 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7041 : : {
7042 : : invalid_data:
7043 : 0 : error (0, 0, gettext ("invalid data"));
7044 : : return;
7045 : : }
7046 : :
7047 [ - + ][ # # ]: 2 : int32_t vers = read_4ubyte_unaligned (dbg, readp);
7048 : 2 : printf (gettext (" Version: %" PRId32 "\n"), vers);
7049 : :
7050 : : // The only difference between version 4 and version 5 is the
7051 : : // hash used for generating the table. Version 6 contains symbols
7052 : : // for inlined functions, older versions didn't.
7053 [ - + ]: 2 : if (vers < 4 || vers > 7)
7054 : : {
7055 : 0 : printf (gettext (" unknown version, cannot parse section\n"));
7056 : : return;
7057 : : }
7058 : :
7059 : 2 : readp += 4;
7060 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7061 : : goto invalid_data;
7062 : :
7063 [ - + ][ # # ]: 2 : uint32_t cu_off = read_4ubyte_unaligned (dbg, readp);
7064 : 2 : printf (gettext (" CU offset: %#" PRIx32 "\n"), cu_off);
7065 : :
7066 : 2 : readp += 4;
7067 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7068 : : goto invalid_data;
7069 : :
7070 [ - + ][ # # ]: 2 : uint32_t tu_off = read_4ubyte_unaligned (dbg, readp);
7071 : 2 : printf (gettext (" TU offset: %#" PRIx32 "\n"), tu_off);
7072 : :
7073 : 2 : readp += 4;
7074 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7075 : : goto invalid_data;
7076 : :
7077 [ - + ][ # # ]: 2 : uint32_t addr_off = read_4ubyte_unaligned (dbg, readp);
7078 : 2 : printf (gettext (" address offset: %#" PRIx32 "\n"), addr_off);
7079 : :
7080 : 2 : readp += 4;
7081 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7082 : : goto invalid_data;
7083 : :
7084 [ - + ][ # # ]: 2 : uint32_t sym_off = read_4ubyte_unaligned (dbg, readp);
7085 : 2 : printf (gettext (" symbol offset: %#" PRIx32 "\n"), sym_off);
7086 : :
7087 : 2 : readp += 4;
7088 [ - + ]: 2 : if (unlikely (readp + 4 > dataend))
7089 : : goto invalid_data;
7090 : :
7091 [ - + ][ # # ]: 2 : uint32_t const_off = read_4ubyte_unaligned (dbg, readp);
7092 : 2 : printf (gettext (" constant offset: %#" PRIx32 "\n"), const_off);
7093 : :
7094 : 2 : readp = data->d_buf + cu_off;
7095 : :
7096 : 2 : const unsigned char *nextp = data->d_buf + tu_off;
7097 : 2 : size_t cu_nr = (nextp - readp) / 16;
7098 : :
7099 : 2 : printf (gettext ("\n CU list at offset %#" PRIx32
7100 : : " contains %zu entries:\n"),
7101 : : cu_off, cu_nr);
7102 : :
7103 : 2 : size_t n = 0;
7104 [ + - ][ + + ]: 6 : while (readp + 16 <= dataend && n < cu_nr)
7105 : : {
7106 [ - + ][ # # ]: 4 : uint64_t off = read_8ubyte_unaligned (dbg, readp);
7107 : 4 : readp += 8;
7108 : :
7109 [ - + ][ # # ]: 4 : uint64_t len = read_8ubyte_unaligned (dbg, readp);
7110 : 4 : readp += 8;
7111 : :
7112 : 4 : printf (" [%4zu] start: %0#8" PRIx64
7113 : : ", length: %5" PRIu64 "\n", n, off, len);
7114 : 4 : n++;
7115 : : }
7116 : :
7117 : 2 : readp = data->d_buf + tu_off;
7118 : 2 : nextp = data->d_buf + addr_off;
7119 : 2 : size_t tu_nr = (nextp - readp) / 24;
7120 : :
7121 : 2 : printf (gettext ("\n TU list at offset %#" PRIx32
7122 : : " contains %zu entries:\n"),
7123 : : tu_off, tu_nr);
7124 : :
7125 : 2 : n = 0;
7126 [ + - ][ + + ]: 4 : while (readp + 24 <= dataend && n < tu_nr)
7127 : : {
7128 [ - + ][ # # ]: 2 : uint64_t off = read_8ubyte_unaligned (dbg, readp);
7129 : 2 : readp += 8;
7130 : :
7131 [ - + ][ # # ]: 2 : uint64_t type = read_8ubyte_unaligned (dbg, readp);
7132 : 2 : readp += 8;
7133 : :
7134 [ - + ][ # # ]: 2 : uint64_t sig = read_8ubyte_unaligned (dbg, readp);
7135 : 2 : readp += 8;
7136 : :
7137 : 2 : printf (" [%4zu] CU offset: %5" PRId64
7138 : : ", type offset: %5" PRId64
7139 : : ", signature: %0#8" PRIx64 "\n", n, off, type, sig);
7140 : 2 : n++;
7141 : : }
7142 : :
7143 : 2 : readp = data->d_buf + addr_off;
7144 : 2 : nextp = data->d_buf + sym_off;
7145 : 2 : size_t addr_nr = (nextp - readp) / 20;
7146 : :
7147 : 2 : printf (gettext ("\n Address list at offset %#" PRIx32
7148 : : " contains %zu entries:\n"),
7149 : : addr_off, addr_nr);
7150 : :
7151 : 2 : n = 0;
7152 [ + - ][ + + ]: 6 : while (readp + 20 <= dataend && n < addr_nr)
7153 : : {
7154 [ - + ][ # # ]: 4 : uint64_t low = read_8ubyte_unaligned (dbg, readp);
7155 : 4 : readp += 8;
7156 : :
7157 [ - + ][ # # ]: 4 : uint64_t high = read_8ubyte_unaligned (dbg, readp);
7158 : 4 : readp += 8;
7159 : :
7160 [ - + ][ # # ]: 4 : uint32_t idx = read_4ubyte_unaligned (dbg, readp);
7161 : 4 : readp += 4;
7162 : :
7163 : 4 : char *l = format_dwarf_addr (dwflmod, 8, low);
7164 : 4 : char *h = format_dwarf_addr (dwflmod, 8, high - 1);
7165 : 4 : printf (" [%4zu] %s..%s, CU index: %5" PRId32 "\n",
7166 : : n, l, h, idx);
7167 : 4 : n++;
7168 : : }
7169 : :
7170 : 2 : readp = data->d_buf + sym_off;
7171 : 2 : nextp = data->d_buf + const_off;
7172 : 2 : size_t sym_nr = (nextp - readp) / 8;
7173 : :
7174 : 2 : printf (gettext ("\n Symbol table at offset %#" PRIx32
7175 : : " contains %zu slots:\n"),
7176 : : addr_off, sym_nr);
7177 : :
7178 : 2 : n = 0;
7179 [ + - ][ + + ]: 2050 : while (readp + 8 <= dataend && n < sym_nr)
7180 : : {
7181 [ - + ][ # # ]: 2048 : uint32_t name = read_4ubyte_unaligned (dbg, readp);
7182 : 2048 : readp += 4;
7183 : :
7184 [ - + ][ # # ]: 2048 : uint32_t vector = read_4ubyte_unaligned (dbg, readp);
7185 : 2048 : readp += 4;
7186 : :
7187 [ + + ]: 2048 : if (name != 0 || vector != 0)
7188 : : {
7189 : 14 : const unsigned char *sym = data->d_buf + const_off + name;
7190 [ - + ]: 14 : if (unlikely (sym > dataend))
7191 : : goto invalid_data;
7192 : :
7193 : 14 : printf (" [%4zu] symbol: %s, CUs: ", n, sym);
7194 : :
7195 : 14 : const unsigned char *readcus = data->d_buf + const_off + vector;
7196 [ - + ]: 14 : if (unlikely (readcus + 8 > dataend))
7197 : : goto invalid_data;
7198 : :
7199 [ - + ][ # # ]: 14 : uint32_t cus = read_4ubyte_unaligned (dbg, readcus);
7200 [ + + ]: 30 : while (cus--)
7201 : : {
7202 : : uint32_t cu_kind, cu, kind;
7203 : : bool is_static;
7204 : 16 : readcus += 4;
7205 [ - + ][ # # ]: 16 : cu_kind = read_4ubyte_unaligned (dbg, readcus);
7206 : 16 : cu = cu_kind & ((1 << 24) - 1);
7207 : 16 : kind = (cu_kind >> 28) & 7;
7208 : 16 : is_static = cu_kind & (1 << 31);
7209 [ + + ]: 16 : if (cu > cu_nr - 1)
7210 : 2 : printf ("%" PRId32 "T", cu - (uint32_t) cu_nr);
7211 : : else
7212 : 14 : printf ("%" PRId32, cu);
7213 [ + + ]: 16 : if (kind != 0)
7214 : : {
7215 : 8 : printf (" (");
7216 [ + + + - : 8 : switch (kind)
- ]
7217 : : {
7218 : : case 1:
7219 : 3 : printf ("type");
7220 : 3 : break;
7221 : : case 2:
7222 : 2 : printf ("var");
7223 : 2 : break;
7224 : : case 3:
7225 : 3 : printf ("func");
7226 : 3 : break;
7227 : : case 4:
7228 : 0 : printf ("other");
7229 : 0 : break;
7230 : : default:
7231 : 0 : printf ("unknown-0x%" PRIx32, kind);
7232 : 0 : break;
7233 : : }
7234 [ + + ]: 8 : printf (":%c)", (is_static ? 'S' : 'G'));
7235 : : }
7236 [ + + ]: 16 : if (cus > 0)
7237 : 16 : printf (", ");
7238 : : }
7239 : 14 : printf ("\n");
7240 : : }
7241 : 2048 : n++;
7242 : : }
7243 : : }
7244 : :
7245 : : static void
7246 : 57 : print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
7247 : : {
7248 : : /* Before we start the real work get a debug context descriptor. */
7249 : : Dwarf_Addr dwbias;
7250 : 57 : Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
7251 : 171 : Dwarf dummy_dbg =
7252 : : {
7253 : 57 : .elf = ebl->elf,
7254 : 57 : .other_byte_order = MY_ELFDATA != ehdr->e_ident[EI_DATA]
7255 : : };
7256 [ + + ]: 57 : if (dbg == NULL)
7257 : : {
7258 [ - + ]: 12 : if ((print_debug_sections & ~section_exception) != 0)
7259 : 0 : error (0, 0, gettext ("cannot get debug context descriptor: %s"),
7260 : : dwfl_errmsg (-1));
7261 [ - + ]: 12 : if ((print_debug_sections & section_exception) == 0)
7262 : 57 : return;
7263 : : dbg = &dummy_dbg;
7264 : : }
7265 : :
7266 : : /* Get the section header string table index. */
7267 : : size_t shstrndx;
7268 [ + - ]: 45 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
7269 : : error (EXIT_FAILURE, 0,
7270 : 0 : gettext ("cannot get section header string table index"));
7271 : :
7272 : : /* Look through all the sections for the debugging sections to print. */
7273 : : Elf_Scn *scn = NULL;
7274 [ + + ]: 1628 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
7275 : : {
7276 : : GElf_Shdr shdr_mem;
7277 : 1583 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
7278 : :
7279 [ + - ][ + + ]: 1583 : if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
7280 : : {
7281 : : static const struct
7282 : : {
7283 : : const char *name;
7284 : : enum section_e bitmask;
7285 : : void (*fp) (Dwfl_Module *, Ebl *,
7286 : : GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
7287 : : } debug_sections[] =
7288 : : {
7289 : : #define NEW_SECTION(name) \
7290 : : { ".debug_" #name, section_##name, print_debug_##name##_section }
7291 : : NEW_SECTION (abbrev),
7292 : : NEW_SECTION (aranges),
7293 : : NEW_SECTION (frame),
7294 : : NEW_SECTION (info),
7295 : : NEW_SECTION (types),
7296 : : NEW_SECTION (line),
7297 : : NEW_SECTION (loc),
7298 : : NEW_SECTION (pubnames),
7299 : : NEW_SECTION (str),
7300 : : NEW_SECTION (macinfo),
7301 : : NEW_SECTION (macro),
7302 : : NEW_SECTION (ranges),
7303 : : { ".eh_frame", section_frame | section_exception,
7304 : : print_debug_frame_section },
7305 : : { ".eh_frame_hdr", section_frame | section_exception,
7306 : : print_debug_frame_hdr_section },
7307 : : { ".gcc_except_table", section_frame | section_exception,
7308 : : print_debug_exception_table },
7309 : : { ".gdb_index", section_gdb_index, print_gdb_index_section }
7310 : : };
7311 : 757 : const int ndebug_sections = (sizeof (debug_sections)
7312 : : / sizeof (debug_sections[0]));
7313 : 757 : const char *name = elf_strptr (ebl->elf, shstrndx,
7314 : 757 : shdr->sh_name);
7315 : : int n;
7316 : :
7317 [ + + ]: 10310 : for (n = 0; n < ndebug_sections; ++n)
7318 [ + + ]: 8727 : if (strcmp (name, debug_sections[n].name) == 0
7319 : : #if USE_ZLIB
7320 [ + - ][ - + ]: 8354 : || (name[0] == '.' && name[1] == 'z'
7321 [ # # ]: 0 : && debug_sections[n].name[1] == 'd'
7322 [ # # ]: 0 : && strcmp (&name[2], &debug_sections[n].name[1]) == 0)
7323 : : #endif
7324 : : )
7325 : : {
7326 [ + + ]: 373 : if ((print_debug_sections | implicit_debug_sections)
7327 : 373 : & debug_sections[n].bitmask)
7328 : 324 : debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
7329 : : break;
7330 : : }
7331 : : }
7332 : : }
7333 : :
7334 : 45 : reset_listptr (&known_loclistptr);
7335 : 57 : reset_listptr (&known_rangelistptr);
7336 : : }
7337 : :
7338 : :
7339 : : #define ITEM_INDENT 4
7340 : : #define WRAP_COLUMN 75
7341 : :
7342 : : /* Print "NAME: FORMAT", wrapping when output text would make the line
7343 : : exceed WRAP_COLUMN. Unpadded numbers look better for the core items
7344 : : but this function is also used for registers which should be printed
7345 : : aligned. Fortunately registers output uses fixed fields width (such
7346 : : as %11d) for the alignment.
7347 : :
7348 : : Line breaks should not depend on the particular values although that
7349 : : may happen in some cases of the core items. */
7350 : :
7351 : : static unsigned int
7352 : : __attribute__ ((format (printf, 6, 7)))
7353 : 171 : print_core_item (unsigned int colno, char sep, unsigned int wrap,
7354 : : size_t name_width, const char *name, const char *format, ...)
7355 : : {
7356 : 171 : size_t len = strlen (name);
7357 [ + + ]: 171 : if (name_width < len)
7358 : 62 : name_width = len;
7359 : :
7360 : : char *out;
7361 : : va_list ap;
7362 : 171 : va_start (ap, format);
7363 : 171 : int out_len = vasprintf (&out, format, ap);
7364 : 171 : va_end (ap);
7365 [ - + ]: 171 : if (out_len == -1)
7366 : 0 : error (EXIT_FAILURE, 0, _("memory exhausted"));
7367 : :
7368 : 171 : size_t n = name_width + sizeof ": " - 1 + out_len;
7369 : :
7370 [ + + ]: 171 : if (colno == 0)
7371 : : {
7372 : 10 : printf ("%*s", ITEM_INDENT, "");
7373 : 10 : colno = ITEM_INDENT + n;
7374 : : }
7375 [ + + ]: 161 : else if (colno + 2 + n < wrap)
7376 : : {
7377 : 101 : printf ("%c ", sep);
7378 : 101 : colno += 2 + n;
7379 : : }
7380 : : else
7381 : : {
7382 : 60 : printf ("\n%*s", ITEM_INDENT, "");
7383 : 60 : colno = ITEM_INDENT + n;
7384 : : }
7385 : :
7386 : 171 : printf ("%s: %*s%s", name, (int) (name_width - len), "", out);
7387 : :
7388 : 171 : free (out);
7389 : :
7390 : 171 : return colno;
7391 : : }
7392 : :
7393 : : static const void *
7394 : 132 : convert (Elf *core, Elf_Type type, uint_fast16_t count,
7395 : : void *value, const void *data, size_t size)
7396 : : {
7397 : 264 : Elf_Data valuedata =
7398 : : {
7399 : : .d_type = type,
7400 : : .d_buf = value,
7401 [ + + ]: 132 : .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT),
7402 : : .d_version = EV_CURRENT,
7403 : : };
7404 : 132 : Elf_Data indata =
7405 : : {
7406 : : .d_type = type,
7407 : : .d_buf = (void *) data,
7408 : : .d_size = valuedata.d_size,
7409 : : .d_version = EV_CURRENT,
7410 : : };
7411 : :
7412 : 264 : Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
7413 [ + + ]: 132 : ? elf32_xlatetom : elf64_xlatetom)
7414 : 132 : (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
7415 [ - + ]: 132 : if (d == NULL)
7416 : 0 : error (EXIT_FAILURE, 0,
7417 : 0 : gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
7418 : :
7419 : 132 : return data + indata.d_size;
7420 : : }
7421 : :
7422 : : typedef uint8_t GElf_Byte;
7423 : :
7424 : : static unsigned int
7425 : 63 : handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
7426 : : unsigned int colno, size_t *repeated_size)
7427 : : {
7428 [ + + ]: 63 : uint_fast16_t count = item->count ?: 1;
7429 : :
7430 : : #define TYPES \
7431 : : DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8); \
7432 : : DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16); \
7433 : : DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32); \
7434 : : DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32); \
7435 : : DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64); \
7436 : : DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
7437 : :
7438 : : #define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
7439 : 63 : union { TYPES; } value;
7440 : : #undef DO_TYPE
7441 : :
7442 : 63 : void *data = &value;
7443 : 63 : size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
7444 : 63 : size_t convsize = size;
7445 [ + + ]: 63 : if (repeated_size != NULL)
7446 : : {
7447 [ + - ][ - + ]: 1 : if (*repeated_size > size && (item->format == 'b' || item->format == 'B'))
7448 : : {
7449 : 0 : data = alloca (*repeated_size);
7450 : 0 : count *= *repeated_size / size;
7451 : 0 : convsize = count * size;
7452 : 0 : *repeated_size -= convsize;
7453 : : }
7454 [ + - ][ - + ]: 1 : else if (item->count != 0 || item->format != '\n')
7455 : 0 : *repeated_size -= size;
7456 : : }
7457 : :
7458 : 63 : convert (core, item->type, count, data, desc + item->offset, convsize);
7459 : :
7460 : 63 : Elf_Type type = item->type;
7461 [ - + ]: 63 : if (type == ELF_T_ADDR)
7462 [ # # ]: 0 : type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD;
7463 : :
7464 [ + + + + : 63 : switch (item->format)
+ + + - ]
7465 : : {
7466 : : case 'd':
7467 [ - + ]: 39 : assert (count == 1);
7468 [ + + - + : 39 : switch (type)
- + - ]
7469 : : {
7470 : : #define DO_TYPE(NAME, Name, hex, dec) \
7471 : : case ELF_T_##NAME: \
7472 : : colno = print_core_item (colno, ',', WRAP_COLUMN, \
7473 : : 0, item->name, dec, value.Name[0]); \
7474 : : break
7475 : 39 : TYPES;
7476 : : #undef DO_TYPE
7477 : : default:
7478 : 0 : abort ();
7479 : : }
7480 : : break;
7481 : :
7482 : : case 'x':
7483 [ - + ]: 2 : assert (count == 1);
7484 [ - - + - : 2 : switch (type)
- - - ]
7485 : : {
7486 : : #define DO_TYPE(NAME, Name, hex, dec) \
7487 : : case ELF_T_##NAME: \
7488 : : colno = print_core_item (colno, ',', WRAP_COLUMN, \
7489 : : 0, item->name, hex, value.Name[0]); \
7490 : : break
7491 : 2 : TYPES;
7492 : : #undef DO_TYPE
7493 : : default:
7494 : 0 : abort ();
7495 : : }
7496 : : break;
7497 : :
7498 : : case 'b':
7499 : : case 'B':
7500 [ - + ]: 6 : assert (size % sizeof (unsigned int) == 0);
7501 : 6 : unsigned int nbits = count * size * 8;
7502 : 6 : unsigned int pop = 0;
7503 [ + + ]: 16 : for (const unsigned int *i = data; (void *) i < data + count * size; ++i)
7504 : 10 : pop += __builtin_popcount (*i);
7505 : 6 : bool negate = pop > nbits / 2;
7506 : 6 : const unsigned int bias = item->format == 'b';
7507 : :
7508 : : {
7509 [ - + ]: 6 : char printed[(negate ? nbits - pop : pop) * 16];
7510 : 6 : char *p = printed;
7511 : 6 : *p = '\0';
7512 : :
7513 : : if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int))
7514 : : {
7515 : : assert (size == sizeof (unsigned int) * 2);
7516 : : for (unsigned int *i = data;
7517 : : (void *) i < data + count * size; i += 2)
7518 : : {
7519 : : unsigned int w = i[1];
7520 : : i[1] = i[0];
7521 : : i[0] = w;
7522 : : }
7523 : : }
7524 : :
7525 : 6 : unsigned int lastbit = 0;
7526 : 6 : unsigned int run = 0;
7527 [ + + ]: 16 : for (const unsigned int *i = data;
7528 : 10 : (void *) i < data + count * size; ++i)
7529 : : {
7530 : 10 : unsigned int bit = ((void *) i - data) * 8;
7531 [ - + ]: 10 : unsigned int w = negate ? ~*i : *i;
7532 [ - + ]: 10 : while (w != 0)
7533 : : {
7534 : 0 : int n = ffs (w);
7535 : 0 : w >>= n;
7536 : 0 : bit += n;
7537 : :
7538 [ # # ][ # # ]: 0 : if (lastbit != 0 && lastbit + 1 == bit)
7539 : 0 : ++run;
7540 : : else
7541 : : {
7542 [ # # ]: 0 : if (lastbit == 0)
7543 : 0 : p += sprintf (p, "%u", bit - bias);
7544 [ # # ]: 0 : else if (run == 0)
7545 : 0 : p += sprintf (p, ",%u", bit - bias);
7546 : : else
7547 : 0 : p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias);
7548 : : run = 0;
7549 : : }
7550 : :
7551 : 0 : lastbit = bit;
7552 : : }
7553 : : }
7554 [ - + ][ # # ]: 6 : if (lastbit > 0 && run > 0 && lastbit + 1 != nbits)
7555 : 0 : p += sprintf (p, "-%u", lastbit - bias);
7556 : :
7557 [ + - ]: 6 : colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
7558 : : negate ? "~<%s>" : "<%s>", printed);
7559 : : }
7560 : 6 : break;
7561 : :
7562 : : case 'T':
7563 : : case (char) ('T'|0x80):
7564 [ - + ]: 12 : assert (count == 2);
7565 : : Dwarf_Word sec;
7566 : : Dwarf_Word usec;
7567 [ - - + - : 12 : switch (type)
+ - - ]
7568 : : {
7569 : : #define DO_TYPE(NAME, Name, hex, dec) \
7570 : : case ELF_T_##NAME: \
7571 : : sec = value.Name[0]; \
7572 : : usec = value.Name[1]; \
7573 : : break
7574 : 12 : TYPES;
7575 : : #undef DO_TYPE
7576 : : default:
7577 : 0 : abort ();
7578 : : }
7579 [ - + ]: 12 : if (unlikely (item->format == (char) ('T'|0x80)))
7580 : : {
7581 : : /* This is a hack for an ill-considered 64-bit ABI where
7582 : : tv_usec is actually a 32-bit field with 32 bits of padding
7583 : : rounding out struct timeval. We've already converted it as
7584 : : a 64-bit field. For little-endian, this just means the
7585 : : high half is the padding; it's presumably zero, but should
7586 : : be ignored anyway. For big-endian, it means the 32-bit
7587 : : field went into the high half of USEC. */
7588 : : GElf_Ehdr ehdr_mem;
7589 : 0 : GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
7590 [ # # ]: 0 : if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
7591 : 0 : usec >>= 32;
7592 : : else
7593 : 0 : usec &= UINT32_MAX;
7594 : : }
7595 : 12 : colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
7596 : : "%" PRIu64 ".%.6" PRIu64, sec, usec);
7597 : 12 : break;
7598 : :
7599 : : case 'c':
7600 [ - + ]: 1 : assert (count == 1);
7601 : 1 : colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
7602 : 1 : "%c", value.Byte[0]);
7603 : 1 : break;
7604 : :
7605 : : case 's':
7606 : 2 : colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
7607 : 2 : "%.*s", (int) count, value.Byte);
7608 : 2 : break;
7609 : :
7610 : : case '\n':
7611 : : /* This is a list of strings separated by '\n'. */
7612 [ - + ]: 1 : assert (item->count == 0);
7613 [ - + ]: 1 : assert (repeated_size != NULL);
7614 [ - + ]: 1 : assert (item->name == NULL);
7615 [ + - ]: 1 : if (unlikely (item->offset >= *repeated_size))
7616 : : break;
7617 : :
7618 : 1 : const char *s = desc + item->offset;
7619 : 1 : size = *repeated_size - item->offset;
7620 : 1 : *repeated_size = 0;
7621 [ + - ]: 48 : while (size > 0)
7622 : : {
7623 : 48 : const char *eol = memchr (s, '\n', size);
7624 : 48 : int len = size;
7625 [ + + ]: 48 : if (eol != NULL)
7626 : 47 : len = eol - s;
7627 : 48 : printf ("%*s%.*s\n", ITEM_INDENT, "", len, s);
7628 [ + + ]: 48 : if (eol == NULL)
7629 : : break;
7630 : 47 : size -= eol + 1 - s;
7631 : 47 : s = eol + 1;
7632 : : }
7633 : :
7634 : : colno = WRAP_COLUMN;
7635 : : break;
7636 : :
7637 : : default:
7638 : 0 : error (0, 0, "XXX not handling format '%c' for %s",
7639 : : item->format, item->name);
7640 : : break;
7641 : : }
7642 : :
7643 : : #undef TYPES
7644 : :
7645 : 63 : return colno;
7646 : : }
7647 : :
7648 : :
7649 : : /* Sort items by group, and by layout offset within each group. */
7650 : : static int
7651 : 148 : compare_core_items (const void *a, const void *b)
7652 : : {
7653 : 148 : const Ebl_Core_Item *const *p1 = a;
7654 : 148 : const Ebl_Core_Item *const *p2 = b;
7655 : 148 : const Ebl_Core_Item *item1 = *p1;
7656 : 148 : const Ebl_Core_Item *item2 = *p2;
7657 : :
7658 : 148 : return ((item1->group == item2->group ? 0
7659 [ + + ]: 148 : : strcmp (item1->group, item2->group))
7660 [ + + ]: 148 : ?: (int) item1->offset - (int) item2->offset);
7661 : : }
7662 : :
7663 : : /* Sort item groups by layout offset of the first item in the group. */
7664 : : static int
7665 : 33 : compare_core_item_groups (const void *a, const void *b)
7666 : : {
7667 : 33 : const Ebl_Core_Item *const *const *p1 = a;
7668 : 33 : const Ebl_Core_Item *const *const *p2 = b;
7669 : 33 : const Ebl_Core_Item *const *group1 = *p1;
7670 : 33 : const Ebl_Core_Item *const *group2 = *p2;
7671 : 33 : const Ebl_Core_Item *item1 = *group1;
7672 : 33 : const Ebl_Core_Item *item2 = *group2;
7673 : :
7674 : 33 : return (int) item1->offset - (int) item2->offset;
7675 : : }
7676 : :
7677 : : static unsigned int
7678 : 7 : handle_core_items (Elf *core, const void *desc, size_t descsz,
7679 : : const Ebl_Core_Item *items, size_t nitems)
7680 : : {
7681 [ + + ]: 7 : if (nitems == 0)
7682 : : return 0;
7683 : :
7684 : : /* Sort to collect the groups together. */
7685 : 6 : const Ebl_Core_Item *sorted_items[nitems];
7686 [ + + ]: 69 : for (size_t i = 0; i < nitems; ++i)
7687 : 63 : sorted_items[i] = &items[i];
7688 : 6 : qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
7689 : :
7690 : : /* Collect the unique groups and sort them. */
7691 : 6 : const Ebl_Core_Item **groups[nitems];
7692 : 6 : groups[0] = &sorted_items[0];
7693 : 6 : size_t ngroups = 1;
7694 [ + + ]: 63 : for (size_t i = 1; i < nitems; ++i)
7695 [ + + ]: 57 : if (sorted_items[i]->group != sorted_items[i - 1]->group
7696 [ + - ]: 17 : && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
7697 : 17 : groups[ngroups++] = &sorted_items[i];
7698 : 6 : qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
7699 : :
7700 : : /* Write out all the groups. */
7701 : 6 : unsigned int colno = 0;
7702 : :
7703 : 6 : const void *last = desc;
7704 [ + + ]: 6 : if (nitems == 1)
7705 : : {
7706 : 2 : size_t size = descsz;
7707 : : /* If this note contains registers as well as items, don't pass
7708 : : &size to express that we don't wish to repeat. */
7709 [ + + ]: 2 : colno = handle_core_item (core, sorted_items[0], desc, colno,
7710 : : size != 0 ? &size : NULL);
7711 : :
7712 [ + - ]: 2 : if (size == 0)
7713 : : return colno;
7714 : 0 : desc += descsz - size;
7715 : 4 : descsz = size;
7716 : : }
7717 : :
7718 : : do
7719 : : {
7720 [ + + ]: 25 : for (size_t i = 0; i < ngroups; ++i)
7721 : : {
7722 [ + + ]: 82 : for (const Ebl_Core_Item **item = groups[i];
7723 : 82 : (item < &sorted_items[nitems]
7724 [ + + ]: 78 : && ((*item)->group == groups[i][0]->group
7725 [ - + ]: 17 : || !strcmp ((*item)->group, groups[i][0]->group)));
7726 : 61 : ++item)
7727 : 61 : colno = handle_core_item (core, *item, desc, colno, NULL);
7728 : :
7729 : : /* Force a line break at the end of the group. */
7730 : 21 : colno = WRAP_COLUMN;
7731 : : }
7732 : :
7733 [ + + ]: 4 : if (descsz == 0)
7734 : : break;
7735 : :
7736 : : /* This set of items consumed a certain amount of the note's data.
7737 : : If there is more data there, we have another unit of the same size.
7738 : : Loop to print that out too. */
7739 : 1 : const Ebl_Core_Item *item = &items[nitems - 1];
7740 [ + - ]: 1 : size_t eltsz = item->offset + gelf_fsize (core, item->type,
7741 : 1 : item->count ?: 1, EV_CURRENT);
7742 : :
7743 : 1 : int reps = -1;
7744 : : do
7745 : : {
7746 : 1 : ++reps;
7747 : 1 : desc += eltsz;
7748 : 1 : descsz -= eltsz;
7749 : : }
7750 [ - + ][ # # ]: 1 : while (descsz >= eltsz && !memcmp (desc, last, eltsz));
7751 : :
7752 [ - + ]: 1 : if (reps == 1)
7753 : : {
7754 : : /* For just one repeat, print it unabridged twice. */
7755 : 0 : desc -= eltsz;
7756 : 0 : descsz += eltsz;
7757 : : }
7758 [ - + ]: 1 : else if (reps > 1)
7759 : 0 : printf (gettext ("\n%*s... <repeats %u more times> ..."),
7760 : : ITEM_INDENT, "", reps);
7761 : :
7762 : 1 : last = desc;
7763 : : }
7764 [ - + ]: 7 : while (descsz > 0);
7765 : :
7766 : : return colno;
7767 : : }
7768 : :
7769 : : static unsigned int
7770 : : handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
7771 : : unsigned int colno)
7772 : : {
7773 : 0 : desc += regloc->offset;
7774 : :
7775 : 0 : abort (); /* XXX */
7776 : : return colno;
7777 : : }
7778 : :
7779 : :
7780 : : static unsigned int
7781 : 50 : handle_core_register (Ebl *ebl, Elf *core, int maxregname,
7782 : : const Ebl_Register_Location *regloc, const void *desc,
7783 : : unsigned int colno)
7784 : : {
7785 [ - + ]: 50 : if (regloc->bits % 8 != 0)
7786 : : return handle_bit_registers (regloc, desc, colno);
7787 : :
7788 : 50 : desc += regloc->offset;
7789 : :
7790 [ + + ]: 159 : for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
7791 : : {
7792 : : char name[REGNAMESZ];
7793 : : int bits;
7794 : : int type;
7795 : 109 : register_info (ebl, reg, regloc, name, &bits, &type);
7796 : :
7797 : : #define TYPES \
7798 : : BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8); \
7799 : : BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16); \
7800 : : BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32); \
7801 : : BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64)
7802 : :
7803 : : #define BITS(bits, xtype, sfmt, ufmt) \
7804 : : uint##bits##_t b##bits; int##bits##_t b##bits##s
7805 : : union { TYPES; uint64_t b128[2]; } value;
7806 : : #undef BITS
7807 : :
7808 [ + + ]: 109 : switch (type)
7809 : : {
7810 : : case DW_ATE_unsigned:
7811 : : case DW_ATE_signed:
7812 : : case DW_ATE_address:
7813 [ - + + + : 69 : switch (bits)
- - ]
7814 : : {
7815 : : #define BITS(bits, xtype, sfmt, ufmt) \
7816 : : case bits: \
7817 : : desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0); \
7818 : : if (type == DW_ATE_signed) \
7819 : : colno = print_core_item (colno, ' ', WRAP_COLUMN, \
7820 : : maxregname, name, \
7821 : : sfmt, value.b##bits##s); \
7822 : : else \
7823 : : colno = print_core_item (colno, ' ', WRAP_COLUMN, \
7824 : : maxregname, name, \
7825 : : ufmt, value.b##bits); \
7826 : : break
7827 : :
7828 [ # # ][ - + ]: 69 : TYPES;
[ + + ][ + + ]
7829 : :
7830 : : case 128:
7831 [ # # ]: 0 : assert (type == DW_ATE_unsigned);
7832 : 0 : desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0);
7833 : 0 : int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
7834 : 0 : colno = print_core_item (colno, ' ', WRAP_COLUMN,
7835 : : maxregname, name,
7836 : : "0x%.16" PRIx64 "%.16" PRIx64,
7837 : 0 : value.b128[!be], value.b128[be]);
7838 : 0 : break;
7839 : :
7840 : : default:
7841 : 0 : abort ();
7842 : : #undef BITS
7843 : : }
7844 : : break;
7845 : :
7846 : : default:
7847 : : /* Print each byte in hex, the whole thing in native byte order. */
7848 [ - + ]: 40 : assert (bits % 8 == 0);
7849 : 40 : const uint8_t *bytes = desc;
7850 : 40 : desc += bits / 8;
7851 : 40 : char hex[bits / 4 + 1];
7852 : 40 : hex[bits / 4] = '\0';
7853 : 40 : int incr = 1;
7854 [ + - ]: 40 : if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
7855 : : {
7856 : 40 : bytes += bits / 8 - 1;
7857 : 40 : incr = -1;
7858 : : }
7859 : 40 : size_t idx = 0;
7860 [ + + ]: 392 : for (char *h = hex; bits > 0; bits -= 8, idx += incr)
7861 : : {
7862 : 352 : *h++ = "0123456789abcdef"[bytes[idx] >> 4];
7863 : 352 : *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
7864 : : }
7865 : 40 : colno = print_core_item (colno, ' ', WRAP_COLUMN,
7866 : : maxregname, name, "0x%s", hex);
7867 : : break;
7868 : : }
7869 : 109 : desc += regloc->pad;
7870 : :
7871 : : #undef TYPES
7872 : : }
7873 : :
7874 : : return colno;
7875 : : }
7876 : :
7877 : :
7878 : : struct register_info
7879 : : {
7880 : : const Ebl_Register_Location *regloc;
7881 : : const char *set;
7882 : : char name[REGNAMESZ];
7883 : : int regno;
7884 : : int bits;
7885 : : int type;
7886 : : };
7887 : :
7888 : : static int
7889 : : register_bitpos (const struct register_info *r)
7890 : : {
7891 : 1184 : return (r->regloc->offset * 8
7892 : 592 : + ((r->regno - r->regloc->regno)
7893 : 592 : * (r->regloc->bits + r->regloc->pad * 8)));
7894 : : }
7895 : :
7896 : : static int
7897 : 306 : compare_sets_by_info (const struct register_info *r1,
7898 : : const struct register_info *r2)
7899 : : {
7900 : 306 : return ((int) r2->bits - (int) r1->bits
7901 [ + + ]: 306 : ?: register_bitpos (r1) - register_bitpos (r2));
7902 : : }
7903 : :
7904 : : /* Sort registers by set, and by size and layout offset within each set. */
7905 : : static int
7906 : 2496 : compare_registers (const void *a, const void *b)
7907 : : {
7908 : 2496 : const struct register_info *r1 = a;
7909 : 2496 : const struct register_info *r2 = b;
7910 : :
7911 : : /* Unused elements sort last. */
7912 [ + + ]: 2496 : if (r1->regloc == NULL)
7913 : 2136 : return r2->regloc == NULL ? 0 : 1;
7914 [ + + ]: 360 : if (r2->regloc == NULL)
7915 : : return -1;
7916 : :
7917 [ + + ]: 2804 : return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
7918 [ + + ]: 308 : ?: compare_sets_by_info (r1, r2));
7919 : : }
7920 : :
7921 : : /* Sort register sets by layout offset of the first register in the set. */
7922 : : static int
7923 : 4 : compare_register_sets (const void *a, const void *b)
7924 : : {
7925 : 4 : const struct register_info *const *p1 = a;
7926 : 4 : const struct register_info *const *p2 = b;
7927 : 4 : return compare_sets_by_info (*p1, *p2);
7928 : : }
7929 : :
7930 : : static unsigned int
7931 : 7 : handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
7932 : : const Ebl_Register_Location *reglocs, size_t nregloc)
7933 : : {
7934 [ + + ]: 7 : if (nregloc == 0)
7935 : : return 0;
7936 : :
7937 : 5 : ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
7938 [ - + ]: 5 : if (maxnreg <= 0)
7939 : : {
7940 [ # # ]: 0 : for (size_t i = 0; i < nregloc; ++i)
7941 [ # # ]: 0 : if (maxnreg < reglocs[i].regno + reglocs[i].count)
7942 : 0 : maxnreg = reglocs[i].regno + reglocs[i].count;
7943 [ # # ]: 0 : assert (maxnreg > 0);
7944 : : }
7945 : :
7946 : 5 : struct register_info regs[maxnreg];
7947 : 5 : memset (regs, 0, sizeof regs);
7948 : :
7949 : : /* Sort to collect the sets together. */
7950 : 5 : int maxreg = 0;
7951 [ + + ]: 55 : for (size_t i = 0; i < nregloc; ++i)
7952 [ + + ]: 159 : for (int reg = reglocs[i].regno;
7953 : 159 : reg < reglocs[i].regno + reglocs[i].count;
7954 : 109 : ++reg)
7955 : : {
7956 [ - + ]: 109 : assert (reg < maxnreg);
7957 [ + + ]: 109 : if (reg > maxreg)
7958 : 68 : maxreg = reg;
7959 : 109 : struct register_info *info = ®s[reg];
7960 : 109 : info->regloc = ®locs[i];
7961 : 109 : info->regno = reg;
7962 : 109 : info->set = register_info (ebl, reg, ®locs[i],
7963 : 109 : info->name, &info->bits, &info->type);
7964 : : }
7965 : 5 : qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
7966 : :
7967 : : /* Collect the unique sets and sort them. */
7968 : 222 : inline bool same_set (const struct register_info *a,
7969 : : const struct register_info *b)
7970 : : {
7971 [ + - ]: 444 : return (a < ®s[maxnreg] && a->regloc != NULL
7972 [ + - ][ + + ]: 222 : && b < ®s[maxnreg] && b->regloc != NULL
7973 [ + + ]: 217 : && a->bits == b->bits
7974 [ + - ][ + + ]: 444 : && (a->set == b->set || !strcmp (a->set, b->set)));
[ + - ]
7975 : : }
7976 : 5 : struct register_info *sets[maxreg + 1];
7977 : 5 : sets[0] = ®s[0];
7978 : 5 : size_t nsets = 1;
7979 [ + + ]: 641 : for (int i = 1; i <= maxreg; ++i)
7980 [ + + ][ + + ]: 636 : if (regs[i].regloc != NULL && !same_set (®s[i], ®s[i - 1]))
7981 : 4 : sets[nsets++] = ®s[i];
7982 : 5 : qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
7983 : :
7984 : : /* Write out all the sets. */
7985 : 5 : unsigned int colno = 0;
7986 [ + + ]: 16 : for (size_t i = 0; i < nsets; ++i)
7987 : : {
7988 : : /* Find the longest name of a register in this set. */
7989 : 9 : size_t maxname = 0;
7990 : : const struct register_info *end;
7991 [ + + ]: 118 : for (end = sets[i]; same_set (sets[i], end); ++end)
7992 : : {
7993 : 109 : size_t len = strlen (end->name);
7994 [ + + ]: 109 : if (len > maxname)
7995 : 14 : maxname = len;
7996 : : }
7997 : :
7998 [ + + ]: 59 : for (const struct register_info *reg = sets[i];
7999 : : reg < end;
8000 [ + - ]: 50 : reg += reg->regloc->count ?: 1)
8001 : 50 : colno = handle_core_register (ebl, core, maxname,
8002 : : reg->regloc, desc, colno);
8003 : :
8004 : : /* Force a line break at the end of the group. */
8005 : 9 : colno = WRAP_COLUMN;
8006 : : }
8007 : :
8008 : : return colno;
8009 : : }
8010 : :
8011 : : static void
8012 : 1 : handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
8013 : : {
8014 : 1 : Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV);
8015 [ - + ]: 1 : if (data == NULL)
8016 : : elf_error:
8017 : 0 : error (EXIT_FAILURE, 0,
8018 : 0 : gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
8019 : :
8020 : 1 : const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT);
8021 [ + + ]: 19 : for (size_t i = 0; i < nauxv; ++i)
8022 : : {
8023 : : GElf_auxv_t av_mem;
8024 : 18 : GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem);
8025 [ + - ]: 18 : if (av == NULL)
8026 : : goto elf_error;
8027 : :
8028 : : const char *name;
8029 : : const char *fmt;
8030 [ - + ]: 18 : if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
8031 : : {
8032 : : /* Unknown type. */
8033 [ # # ]: 0 : if (av->a_un.a_val == 0)
8034 : 0 : printf (" %" PRIu64 "\n", av->a_type);
8035 : : else
8036 : 0 : printf (" %" PRIu64 ": %#" PRIx64 "\n",
8037 : : av->a_type, av->a_un.a_val);
8038 : : }
8039 : : else
8040 [ + + + - : 18 : switch (fmt[0])
+ - ]
8041 : : {
8042 : : case '\0': /* Normally zero. */
8043 [ + - ]: 1 : if (av->a_un.a_val == 0)
8044 : : {
8045 : 1 : printf (" %s\n", name);
8046 : 1 : break;
8047 : : }
8048 : : /* Fall through */
8049 : : case 'x': /* hex */
8050 : : case 'p': /* address */
8051 : : case 's': /* address of string */
8052 : 7 : printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val);
8053 : 7 : break;
8054 : : case 'u':
8055 : 9 : printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val);
8056 : 9 : break;
8057 : : case 'd':
8058 : 0 : printf (" %s: %" PRId64 "\n", name, av->a_un.a_val);
8059 : 0 : break;
8060 : :
8061 : : case 'b':
8062 : 1 : printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val);
8063 : 1 : GElf_Xword bit = 1;
8064 : 1 : const char *pfx = "<";
8065 [ + + ]: 11 : for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
8066 : : {
8067 [ + + ]: 10 : if (av->a_un.a_val & bit)
8068 : : {
8069 : 6 : printf ("%s%s", pfx, p);
8070 : 6 : pfx = " ";
8071 : : }
8072 : 10 : bit <<= 1;
8073 : : }
8074 : 1 : printf (">\n");
8075 : 1 : break;
8076 : :
8077 : : default:
8078 : 0 : abort ();
8079 : : }
8080 : : }
8081 : 1 : }
8082 : :
8083 : : static void
8084 : 7 : handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr,
8085 : : const char *name, const void *desc)
8086 : : {
8087 : : GElf_Word regs_offset;
8088 : : size_t nregloc;
8089 : : const Ebl_Register_Location *reglocs;
8090 : : size_t nitems;
8091 : : const Ebl_Core_Item *items;
8092 : :
8093 [ + - ]: 7 : if (! ebl_core_note (ebl, nhdr, name,
8094 : : ®s_offset, &nregloc, ®locs, &nitems, &items))
8095 : 7 : return;
8096 : :
8097 : : /* Pass 0 for DESCSZ when there are registers in the note,
8098 : : so that the ITEMS array does not describe the whole thing.
8099 : : For non-register notes, the actual descsz might be a multiple
8100 : : of the unit size, not just exactly the unit size. */
8101 [ + + ]: 7 : unsigned int colno = handle_core_items (ebl->elf, desc,
8102 : 9 : nregloc == 0 ? nhdr->n_descsz : 0,
8103 : : items, nitems);
8104 [ + + ]: 7 : if (colno != 0)
8105 : : putchar_unlocked ('\n');
8106 : :
8107 : 7 : colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
8108 : : reglocs, nregloc);
8109 [ + + ]: 7 : if (colno != 0)
8110 : : putchar_unlocked ('\n');
8111 : : }
8112 : :
8113 : : static void
8114 : 49 : handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
8115 : : GElf_Off start, Elf_Data *data)
8116 : : {
8117 : 49 : fputs_unlocked (gettext (" Owner Data size Type\n"), stdout);
8118 : :
8119 [ + - ]: 49 : if (data == NULL)
8120 : : goto bad_note;
8121 : :
8122 : : size_t offset = 0;
8123 : : GElf_Nhdr nhdr;
8124 : : size_t name_offset;
8125 : : size_t desc_offset;
8126 [ + + ]: 105 : while (offset < data->d_size
8127 [ + - ]: 56 : && (offset = gelf_getnote (data, offset,
8128 : : &nhdr, &name_offset, &desc_offset)) > 0)
8129 : : {
8130 : 56 : const char *name = data->d_buf + name_offset;
8131 : 56 : const char *desc = data->d_buf + desc_offset;
8132 : :
8133 : : char buf[100];
8134 : : char buf2[100];
8135 [ + + ]: 56 : printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
8136 : 56 : (int) nhdr.n_namesz, name, nhdr.n_descsz,
8137 : 56 : ehdr->e_type == ET_CORE
8138 : 8 : ? ebl_core_note_type_name (ebl, nhdr.n_type,
8139 : : buf, sizeof (buf))
8140 : 48 : : ebl_object_note_type_name (ebl, name, nhdr.n_type,
8141 : : buf2, sizeof (buf2)));
8142 : :
8143 : : /* Filter out invalid entries. */
8144 : : if (memchr (name, '\0', nhdr.n_namesz) != NULL
8145 : : /* XXX For now help broken Linux kernels. */
8146 : : || 1)
8147 : : {
8148 [ + + ]: 56 : if (ehdr->e_type == ET_CORE)
8149 : : {
8150 [ + + ]: 8 : if (nhdr.n_type == NT_AUXV
8151 [ + - ]: 1 : && (nhdr.n_namesz == 4 /* Broken old Linux kernels. */
8152 [ + - ][ + - ]: 1 : || (nhdr.n_namesz == 5 && name[4] == '\0'))
8153 [ + - ]: 1 : && !memcmp (name, "CORE", 4))
8154 : 1 : handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz,
8155 : : start + desc_offset);
8156 : : else
8157 : 7 : handle_core_note (ebl, &nhdr, name, desc);
8158 : : }
8159 : : else
8160 : 56 : ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
8161 : : }
8162 : : }
8163 : :
8164 [ - + ]: 49 : if (offset == data->d_size)
8165 : 49 : return;
8166 : :
8167 : : bad_note:
8168 : 0 : error (EXIT_FAILURE, 0,
8169 : 0 : gettext ("cannot get content of note section: %s"),
8170 : : elf_errmsg (-1));
8171 : : }
8172 : :
8173 : : static void
8174 : 39 : handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
8175 : : {
8176 : : /* If we have section headers, just look for SHT_NOTE sections.
8177 : : In a debuginfo file, the program headers are not reliable. */
8178 [ + + ]: 39 : if (shnum != 0)
8179 : : {
8180 : : /* Get the section header string table index. */
8181 : : size_t shstrndx;
8182 [ + - ]: 37 : if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
8183 : : error (EXIT_FAILURE, 0,
8184 : 0 : gettext ("cannot get section header string table index"));
8185 : :
8186 : : Elf_Scn *scn = NULL;
8187 [ + + ]: 1180 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
8188 : : {
8189 : : GElf_Shdr shdr_mem;
8190 : 1143 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
8191 : :
8192 [ + - ][ + + ]: 1143 : if (shdr == NULL || shdr->sh_type != SHT_NOTE)
8193 : : /* Not what we are looking for. */
8194 : 1096 : continue;
8195 : :
8196 : 47 : printf (gettext ("\
8197 : : \nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
8198 : : elf_ndxscn (scn),
8199 : 47 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
8200 : : shdr->sh_size, shdr->sh_offset);
8201 : :
8202 : 1143 : handle_notes_data (ebl, ehdr, shdr->sh_offset,
8203 : : elf_getdata (scn, NULL));
8204 : : }
8205 : 39 : return;
8206 : : }
8207 : :
8208 : : /* We have to look through the program header to find the note
8209 : : sections. There can be more than one. */
8210 [ + + ]: 25 : for (size_t cnt = 0; cnt < phnum; ++cnt)
8211 : : {
8212 : : GElf_Phdr mem;
8213 : 23 : GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
8214 : :
8215 [ + - ][ + + ]: 23 : if (phdr == NULL || phdr->p_type != PT_NOTE)
8216 : : /* Not what we are looking for. */
8217 : 21 : continue;
8218 : :
8219 : 2 : printf (gettext ("\
8220 : : \nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
8221 : : phdr->p_filesz, phdr->p_offset);
8222 : :
8223 : 2 : handle_notes_data (ebl, ehdr, phdr->p_offset,
8224 : : elf_getdata_rawchunk (ebl->elf,
8225 : 2 : phdr->p_offset, phdr->p_filesz,
8226 : : ELF_T_NHDR));
8227 : : }
8228 : : }
8229 : :
8230 : :
8231 : : static void
8232 : 1 : hex_dump (const uint8_t *data, size_t len)
8233 : : {
8234 : 1 : size_t pos = 0;
8235 [ + + ]: 2 : while (pos < len)
8236 : : {
8237 : 1 : printf (" 0x%08Zx ", pos);
8238 : :
8239 : 1 : const size_t chunk = MIN (len - pos, 16);
8240 : :
8241 [ + + ]: 2 : for (size_t i = 0; i < chunk; ++i)
8242 [ - + ]: 1 : if (i % 4 == 3)
8243 : 0 : printf ("%02x ", data[pos + i]);
8244 : : else
8245 : 1 : printf ("%02x", data[pos + i]);
8246 : :
8247 [ + - ]: 1 : if (chunk < 16)
8248 : 1 : printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
8249 : :
8250 [ + + ]: 2 : for (size_t i = 0; i < chunk; ++i)
8251 : : {
8252 : 1 : unsigned char b = data[pos + i];
8253 [ - + ]: 1 : printf ("%c", isprint (b) ? b : '.');
8254 : : }
8255 : :
8256 : : putchar ('\n');
8257 : 1 : pos += chunk;
8258 : : }
8259 : 1 : }
8260 : :
8261 : : static void
8262 : 1 : dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
8263 : : {
8264 [ + - ][ - + ]: 1 : if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
8265 : 0 : printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
8266 : : elf_ndxscn (scn), name);
8267 : : else
8268 : : {
8269 : 1 : Elf_Data *data = elf_rawdata (scn, NULL);
8270 [ - + ]: 1 : if (data == NULL)
8271 : 0 : error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
8272 : : elf_ndxscn (scn), name, elf_errmsg (-1));
8273 : : else
8274 : : {
8275 : 1 : printf (gettext ("\nHex dump of section [%Zu] '%s', %" PRIu64
8276 : : " bytes at offset %#0" PRIx64 ":\n"),
8277 : : elf_ndxscn (scn), name,
8278 : : shdr->sh_size, shdr->sh_offset);
8279 : 1 : hex_dump (data->d_buf, data->d_size);
8280 : : }
8281 : : }
8282 : 1 : }
8283 : :
8284 : : static void
8285 : 96 : print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
8286 : : {
8287 [ + - ][ - + ]: 96 : if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
8288 : 0 : printf (gettext ("\nSection [%Zu] '%s' has no strings to dump.\n"),
8289 : : elf_ndxscn (scn), name);
8290 : : else
8291 : : {
8292 : 96 : Elf_Data *data = elf_rawdata (scn, NULL);
8293 [ - + ]: 96 : if (data == NULL)
8294 : 0 : error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
8295 : : elf_ndxscn (scn), name, elf_errmsg (-1));
8296 : : else
8297 : : {
8298 : 96 : printf (gettext ("\nString section [%Zu] '%s' contains %" PRIu64
8299 : : " bytes at offset %#0" PRIx64 ":\n"),
8300 : : elf_ndxscn (scn), name,
8301 : : shdr->sh_size, shdr->sh_offset);
8302 : :
8303 : 96 : const char *start = data->d_buf;
8304 : 96 : const char *const limit = start + data->d_size;
8305 : : do
8306 : : {
8307 : 20723 : const char *end = memchr (start, '\0', limit - start);
8308 : 20723 : const size_t pos = start - (const char *) data->d_buf;
8309 [ - + ]: 20723 : if (unlikely (end == NULL))
8310 : : {
8311 : 0 : printf (" [%6Zx]- %.*s\n",
8312 : : pos, (int) (limit - start), start);
8313 : 0 : break;
8314 : : }
8315 : 20723 : printf (" [%6Zx] %s\n", pos, start);
8316 : 20723 : start = end + 1;
8317 [ + + ]: 20723 : } while (start < limit);
8318 : : }
8319 : : }
8320 : 96 : }
8321 : :
8322 : : static void
8323 : 37 : for_each_section_argument (Elf *elf, const struct section_argument *list,
8324 : : void (*dump) (Elf_Scn *scn, const GElf_Shdr *shdr,
8325 : : const char *name))
8326 : : {
8327 : : /* Get the section header string table index. */
8328 : : size_t shstrndx;
8329 [ + - ]: 37 : if (elf_getshdrstrndx (elf, &shstrndx) < 0)
8330 : : error (EXIT_FAILURE, 0,
8331 : 0 : gettext ("cannot get section header string table index"));
8332 : :
8333 [ + + ]: 146 : for (const struct section_argument *a = list; a != NULL; a = a->next)
8334 : : {
8335 : : Elf_Scn *scn;
8336 : : GElf_Shdr shdr_mem;
8337 : 109 : const char *name = NULL;
8338 : :
8339 : 109 : char *endp = NULL;
8340 : 109 : unsigned long int shndx = strtoul (a->arg, &endp, 0);
8341 [ + - ][ # # ]: 109 : if (endp != a->arg && *endp == '\0')
8342 : : {
8343 : 0 : scn = elf_getscn (elf, shndx);
8344 [ # # ]: 0 : if (scn == NULL)
8345 : : {
8346 : 0 : error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
8347 : 0 : continue;
8348 : : }
8349 : :
8350 [ # # ]: 0 : if (gelf_getshdr (scn, &shdr_mem) == NULL)
8351 : 0 : error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
8352 : : elf_errmsg (-1));
8353 : 0 : name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
8354 : : }
8355 : : else
8356 : : {
8357 : : /* Need to look up the section by name. */
8358 : : scn = NULL;
8359 : : bool found = false;
8360 [ + + ]: 3484 : while ((scn = elf_nextscn (elf, scn)) != NULL)
8361 : : {
8362 [ - + ]: 3375 : if (gelf_getshdr (scn, &shdr_mem) == NULL)
8363 : 0 : continue;
8364 : 3375 : name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
8365 [ - + ]: 3375 : if (name == NULL)
8366 : 0 : continue;
8367 [ + + ]: 3375 : if (!strcmp (name, a->arg))
8368 : : {
8369 : 97 : found = true;
8370 : 3375 : (*dump) (scn, &shdr_mem, name);
8371 : : }
8372 : : }
8373 : :
8374 [ + + ][ - + ]: 109 : if (unlikely (!found) && !a->implicit)
8375 : 0 : error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
8376 : : }
8377 : : }
8378 : 37 : }
8379 : :
8380 : : static void
8381 : 1 : dump_data (Ebl *ebl)
8382 : : {
8383 : 1 : for_each_section_argument (ebl->elf, dump_data_sections, &dump_data_section);
8384 : 1 : }
8385 : :
8386 : : static void
8387 : 36 : dump_strings (Ebl *ebl)
8388 : : {
8389 : 36 : for_each_section_argument (ebl->elf, string_sections, &print_string_section);
8390 : 36 : }
8391 : :
8392 : : static void
8393 : 0 : print_strings (Ebl *ebl)
8394 : : {
8395 : : /* Get the section header string table index. */
8396 : : size_t shstrndx;
8397 [ # # ]: 0 : if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
8398 : : error (EXIT_FAILURE, 0,
8399 : 0 : gettext ("cannot get section header string table index"));
8400 : :
8401 : : Elf_Scn *scn;
8402 : : GElf_Shdr shdr_mem;
8403 : : const char *name;
8404 : : scn = NULL;
8405 [ # # ]: 0 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
8406 : : {
8407 [ # # ]: 0 : if (gelf_getshdr (scn, &shdr_mem) == NULL)
8408 : 0 : continue;
8409 : :
8410 [ # # ]: 0 : if (shdr_mem.sh_type != SHT_PROGBITS
8411 [ # # ]: 0 : || !(shdr_mem.sh_flags & SHF_STRINGS))
8412 : 0 : continue;
8413 : :
8414 : 0 : name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
8415 [ # # ]: 0 : if (name == NULL)
8416 : 0 : continue;
8417 : :
8418 : 0 : print_string_section (scn, &shdr_mem, name);
8419 : : }
8420 : 0 : }
8421 : :
8422 : : static void
8423 : 2 : dump_archive_index (Elf *elf, const char *fname)
8424 : : {
8425 : : size_t narsym;
8426 : 2 : const Elf_Arsym *arsym = elf_getarsym (elf, &narsym);
8427 [ - + ]: 2 : if (arsym == NULL)
8428 : : {
8429 : 0 : int result = elf_errno ();
8430 [ # # ]: 0 : if (unlikely (result != ELF_E_NO_INDEX))
8431 : 0 : error (EXIT_FAILURE, 0,
8432 : 0 : gettext ("cannot get symbol index of archive '%s': %s"),
8433 : : fname, elf_errmsg (result));
8434 : : else
8435 : 0 : printf (gettext ("\nArchive '%s' has no symbol index\n"), fname);
8436 : 2 : return;
8437 : : }
8438 : :
8439 : 2 : printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"),
8440 : : fname, narsym);
8441 : :
8442 : 2 : size_t as_off = 0;
8443 [ + + ]: 11 : for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s)
8444 : : {
8445 [ + + ]: 9 : if (s->as_off != as_off)
8446 : : {
8447 : 6 : as_off = s->as_off;
8448 : :
8449 : : Elf *subelf;
8450 [ + - ]: 6 : if (unlikely (elf_rand (elf, as_off) == 0)
8451 [ - + ]: 6 : || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
8452 : : == NULL))
8453 : : #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)
8454 : : while (1)
8455 : : #endif
8456 : 0 : error (EXIT_FAILURE, 0,
8457 : 0 : gettext ("cannot extract member at offset %Zu in '%s': %s"),
8458 : : as_off, fname, elf_errmsg (-1));
8459 : :
8460 : 6 : const Elf_Arhdr *h = elf_getarhdr (subelf);
8461 : :
8462 : 6 : printf (gettext ("Archive member '%s' contains:\n"), h->ar_name);
8463 : :
8464 : 6 : elf_end (subelf);
8465 : : }
8466 : :
8467 : 9 : printf ("\t%s\n", s->as_name);
8468 : : }
8469 : : }
8470 : :
8471 : 92990 : #include "debugpred.h"
|