blob: df0a874d679b21c7c22069d4d9c5802ab77e3723 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Print information from ELF file in human-readable form.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 1999-2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004 Written by Ulrich Drepper <drepper@redhat.com>, 1999.
5
Elliott Hughes03333822015-02-18 22:19:45 -08006 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.
Ben Cheng25b3c042013-11-20 14:45:36 -080010
Elliott Hughes03333822015-02-18 22:19:45 -080011 elfutils is distributed in the hope that it will be useful, but
Ben Cheng25b3c042013-11-20 14:45:36 -080012 WITHOUT ANY WARRANTY; without even the implied warranty of
Elliott Hughes03333822015-02-18 22:19:45 -080013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
Ben Cheng25b3c042013-11-20 14:45:36 -080015
Elliott Hughes03333822015-02-18 22:19:45 -080016 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080018
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>
Elliott Hughes03333822015-02-18 22:19:45 -080045#include <signal.h>
Ben Cheng25b3c042013-11-20 14:45:36 -080046
47#include <system.h>
48#include "../libelf/libelfP.h"
49#include "../libelf/common.h"
50#include "../libebl/libeblP.h"
51#include "../libdw/libdwP.h"
52#include "../libdwfl/libdwflP.h"
53#include "../libdw/memory-access.h"
54
Elliott Hughes03333822015-02-18 22:19:45 -080055#include "../libdw/known-dwarf.h"
56
Ben Cheng25b3c042013-11-20 14:45:36 -080057
58/* Name and version of program. */
59static void print_version (FILE *stream, struct argp_state *state);
60ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
61
62/* Bug report address. */
63ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
64
Elliott Hughes03333822015-02-18 22:19:45 -080065/* argp key value for --elf-section, non-ascii. */
66#define ELF_INPUT_SECTION 256
67
Ben Cheng25b3c042013-11-20 14:45:36 -080068/* Definitions of arguments for argp functions. */
69static const struct argp_option options[] =
70{
Elliott Hughes03333822015-02-18 22:19:45 -080071 { NULL, 0, NULL, 0, N_("ELF input selection:"), 0 },
72 { "elf-section", ELF_INPUT_SECTION, "SECTION", OPTION_ARG_OPTIONAL,
73 N_("Use the named SECTION (default .gnu_debugdata) as (compressed) ELF "
74 "input data"), 0 },
Ben Cheng25b3c042013-11-20 14:45:36 -080075 { NULL, 0, NULL, 0, N_("ELF output selection:"), 0 },
76 { "all", 'a', NULL, 0,
77 N_("All these plus -p .strtab -p .dynstr -p .comment"), 0 },
78 { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 },
79 { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 },
80 { "histogram", 'I', NULL, 0,
81 N_("Display histogram of bucket list lengths"), 0 },
82 { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
83 { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
84 { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
85 { "section-headers", 'S', NULL, 0, N_("Display the sections' headers"), 0 },
86 { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
87 { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
88 { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
89 { "notes", 'n', NULL, 0, N_("Display the ELF notes"), 0 },
90 { "arch-specific", 'A', NULL, 0,
91 N_("Display architecture specific information, if any"), 0 },
92 { "exception", 'e', NULL, 0,
93 N_("Display sections for exception handling"), 0 },
94
95 { NULL, 0, NULL, 0, N_("Additional output selection:"), 0 },
96 { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
97 N_("Display DWARF section content. SECTION can be one of abbrev, "
Elliott Hughes03333822015-02-18 22:19:45 -080098 "aranges, decodedaranges, frame, gdb_index, info, loc, line, "
99 "decodedline, ranges, pubnames, str, macinfo, macro or exception"), 0 },
Ben Cheng25b3c042013-11-20 14:45:36 -0800100 { "hex-dump", 'x', "SECTION", 0,
101 N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
102 { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL,
103 N_("Print string contents of sections"), 0 },
104 { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
105 { "archive-index", 'c', NULL, 0,
106 N_("Display the symbol index of an archive"), 0 },
107
108 { NULL, 0, NULL, 0, N_("Output control:"), 0 },
109 { "numeric-addresses", 'N', NULL, 0,
110 N_("Do not find symbol names for addresses in DWARF data"), 0 },
Elliott Hughes03333822015-02-18 22:19:45 -0800111 { "unresolved-address-offsets", 'U', NULL, 0,
112 N_("Display just offsets instead of resolving values to addresses in DWARF data"), 0 },
Ben Cheng25b3c042013-11-20 14:45:36 -0800113 { "wide", 'W', NULL, 0,
114 N_("Ignored for compatibility (lines always wide)"), 0 },
115 { NULL, 0, NULL, 0, NULL, 0 }
116};
117
118/* Short description of program. */
119static const char doc[] = N_("\
120Print information from ELF file in human-readable form.");
121
122/* Strings for arguments in help texts. */
123static const char args_doc[] = N_("FILE...");
124
125/* Prototype for option handler. */
126static error_t parse_opt (int key, char *arg, struct argp_state *state);
127
128/* Data structure to communicate with argp functions. */
129static struct argp argp =
130{
131 options, parse_opt, args_doc, doc, NULL, NULL, NULL
132};
133
Elliott Hughes03333822015-02-18 22:19:45 -0800134/* If non-null, the section from which we should read to (compressed) ELF. */
135static const char *elf_input_section = NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -0800136
137/* Flags set by the option controlling the output. */
138
139/* True if dynamic segment should be printed. */
140static bool print_dynamic_table;
141
142/* True if the file header should be printed. */
143static bool print_file_header;
144
145/* True if the program headers should be printed. */
146static bool print_program_header;
147
148/* True if relocations should be printed. */
149static bool print_relocations;
150
151/* True if the section headers should be printed. */
152static bool print_section_header;
153
154/* True if the symbol table should be printed. */
155static bool print_symbol_table;
156
157/* True if the version information should be printed. */
158static bool print_version_info;
159
160/* True if section groups should be printed. */
161static bool print_section_groups;
162
163/* True if bucket list length histogram should be printed. */
164static bool print_histogram;
165
166/* True if the architecture specific data should be printed. */
167static bool print_arch;
168
169/* True if note section content should be printed. */
170static bool print_notes;
171
172/* True if SHF_STRINGS section content should be printed. */
173static bool print_string_sections;
174
175/* True if archive index should be printed. */
176static bool print_archive_index;
177
178/* True if any of the control options except print_archive_index is set. */
179static bool any_control_option;
180
181/* True if we should print addresses from DWARF in symbolic form. */
182static bool print_address_names = true;
183
Elliott Hughes03333822015-02-18 22:19:45 -0800184/* True if we should print raw values instead of relativized addresses. */
185static bool print_unresolved_addresses = false;
186
187/* True if we should print the .debug_aranges section using libdw. */
188static bool decodedaranges = false;
189
190/* True if we should print the .debug_aranges section using libdw. */
191static bool decodedline = false;
192
Ben Cheng25b3c042013-11-20 14:45:36 -0800193/* Select printing of debugging sections. */
194static enum section_e
195{
196 section_abbrev = 1, /* .debug_abbrev */
197 section_aranges = 2, /* .debug_aranges */
198 section_frame = 4, /* .debug_frame or .eh_frame & al. */
199 section_info = 8, /* .debug_info, .debug_types */
200 section_types = section_info,
201 section_line = 16, /* .debug_line */
202 section_loc = 32, /* .debug_loc */
203 section_pubnames = 64, /* .debug_pubnames */
204 section_str = 128, /* .debug_str */
205 section_macinfo = 256, /* .debug_macinfo */
206 section_ranges = 512, /* .debug_ranges */
207 section_exception = 1024, /* .eh_frame & al. */
208 section_gdb_index = 2048, /* .gdb_index */
Elliott Hughes03333822015-02-18 22:19:45 -0800209 section_macro = 4096, /* .debug_macro */
Ben Cheng25b3c042013-11-20 14:45:36 -0800210 section_all = (section_abbrev | section_aranges | section_frame
211 | section_info | section_line | section_loc
212 | section_pubnames | section_str | section_macinfo
Elliott Hughes03333822015-02-18 22:19:45 -0800213 | section_ranges | section_exception | section_gdb_index
214 | section_macro)
Ben Cheng25b3c042013-11-20 14:45:36 -0800215} print_debug_sections, implicit_debug_sections;
216
217/* Select hex dumping of sections. */
218static struct section_argument *dump_data_sections;
219static struct section_argument **dump_data_sections_tail = &dump_data_sections;
220
221/* Select string dumping of sections. */
222static struct section_argument *string_sections;
223static struct section_argument **string_sections_tail = &string_sections;
224
225struct section_argument
226{
227 struct section_argument *next;
228 const char *arg;
229 bool implicit;
230};
231
232/* Numbers of sections and program headers in the file. */
233static size_t shnum;
234static size_t phnum;
235
236
237/* Declarations of local functions. */
238static void process_file (int fd, const char *fname, bool only_one);
239static void process_elf_file (Dwfl_Module *dwflmod, int fd);
240static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
241static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
242static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
243static void print_scngrp (Ebl *ebl);
244static void print_dynamic (Ebl *ebl);
245static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
246static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
247 GElf_Shdr *shdr);
248static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
249 GElf_Shdr *shdr);
250static void print_symtab (Ebl *ebl, int type);
251static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
252static void print_verinfo (Ebl *ebl);
253static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
254static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
255static void handle_versym (Ebl *ebl, Elf_Scn *scn,
256 GElf_Shdr *shdr);
257static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
258static void handle_hash (Ebl *ebl);
259static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
260static void print_liblist (Ebl *ebl);
261static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr);
262static void dump_data (Ebl *ebl);
263static void dump_strings (Ebl *ebl);
264static void print_strings (Ebl *ebl);
265static void dump_archive_index (Elf *, const char *);
266
267
268int
269main (int argc, char *argv[])
270{
271 /* Set locale. */
272 setlocale (LC_ALL, "");
273
274 /* Initialize the message catalog. */
275 textdomain (PACKAGE_TARNAME);
276
277 /* Parse and process arguments. */
278 int remaining;
279 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
280
281 /* Before we start tell the ELF library which version we are using. */
282 elf_version (EV_CURRENT);
283
284 /* Now process all the files given at the command line. */
285 bool only_one = remaining + 1 == argc;
286 do
287 {
288 /* Open the file. */
289 int fd = open (argv[remaining], O_RDONLY);
290 if (fd == -1)
291 {
292 error (0, errno, gettext ("cannot open input file"));
293 continue;
294 }
295
296 process_file (fd, argv[remaining], only_one);
297
298 close (fd);
299 }
300 while (++remaining < argc);
301
302 return error_message_count != 0;
303}
304
305
306/* Handle program arguments. */
307static error_t
308parse_opt (int key, char *arg,
309 struct argp_state *state __attribute__ ((unused)))
310{
311 void add_dump_section (const char *name, bool implicit)
312 {
313 struct section_argument *a = xmalloc (sizeof *a);
314 a->arg = name;
315 a->next = NULL;
316 a->implicit = implicit;
317 struct section_argument ***tailp
318 = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
319 **tailp = a;
320 *tailp = &a->next;
321 }
322
323 switch (key)
324 {
325 case 'a':
326 print_file_header = true;
327 print_program_header = true;
328 print_relocations = true;
329 print_section_header = true;
330 print_symbol_table = true;
331 print_version_info = true;
332 print_dynamic_table = true;
333 print_section_groups = true;
334 print_histogram = true;
335 print_arch = true;
336 print_notes = true;
337 implicit_debug_sections |= section_exception;
338 add_dump_section (".strtab", true);
339 add_dump_section (".dynstr", true);
340 add_dump_section (".comment", true);
341 any_control_option = true;
342 break;
343 case 'A':
344 print_arch = true;
345 any_control_option = true;
346 break;
347 case 'd':
348 print_dynamic_table = true;
349 any_control_option = true;
350 break;
351 case 'e':
352 print_debug_sections |= section_exception;
353 any_control_option = true;
354 break;
355 case 'g':
356 print_section_groups = true;
357 any_control_option = true;
358 break;
359 case 'h':
360 print_file_header = true;
361 any_control_option = true;
362 break;
363 case 'I':
364 print_histogram = true;
365 any_control_option = true;
366 break;
367 case 'l':
368 print_program_header = true;
369 any_control_option = true;
370 break;
371 case 'n':
372 print_notes = true;
373 any_control_option = true;
374 break;
375 case 'r':
376 print_relocations = true;
377 any_control_option = true;
378 break;
379 case 'S':
380 print_section_header = true;
381 any_control_option = true;
382 break;
383 case 's':
384 print_symbol_table = true;
385 any_control_option = true;
386 break;
387 case 'V':
388 print_version_info = true;
389 any_control_option = true;
390 break;
391 case 'c':
392 print_archive_index = true;
393 break;
394 case 'w':
395 if (arg == NULL)
396 print_debug_sections = section_all;
397 else if (strcmp (arg, "abbrev") == 0)
398 print_debug_sections |= section_abbrev;
399 else if (strcmp (arg, "aranges") == 0)
400 print_debug_sections |= section_aranges;
Elliott Hughes03333822015-02-18 22:19:45 -0800401 else if (strcmp (arg, "decodedaranges") == 0)
402 {
403 print_debug_sections |= section_aranges;
404 decodedaranges = true;
405 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800406 else if (strcmp (arg, "ranges") == 0)
407 {
408 print_debug_sections |= section_ranges;
409 implicit_debug_sections |= section_info;
410 }
411 else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0)
412 print_debug_sections |= section_frame;
413 else if (strcmp (arg, "info") == 0)
414 print_debug_sections |= section_info;
415 else if (strcmp (arg, "loc") == 0)
416 {
417 print_debug_sections |= section_loc;
418 implicit_debug_sections |= section_info;
419 }
420 else if (strcmp (arg, "line") == 0)
421 print_debug_sections |= section_line;
Elliott Hughes03333822015-02-18 22:19:45 -0800422 else if (strcmp (arg, "decodedline") == 0)
423 {
424 print_debug_sections |= section_line;
425 decodedline = true;
426 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800427 else if (strcmp (arg, "pubnames") == 0)
428 print_debug_sections |= section_pubnames;
429 else if (strcmp (arg, "str") == 0)
430 print_debug_sections |= section_str;
431 else if (strcmp (arg, "macinfo") == 0)
432 print_debug_sections |= section_macinfo;
Elliott Hughes03333822015-02-18 22:19:45 -0800433 else if (strcmp (arg, "macro") == 0)
434 print_debug_sections |= section_macro;
Ben Cheng25b3c042013-11-20 14:45:36 -0800435 else if (strcmp (arg, "exception") == 0)
436 print_debug_sections |= section_exception;
437 else if (strcmp (arg, "gdb_index") == 0)
438 print_debug_sections |= section_gdb_index;
439 else
440 {
441 fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"),
442 arg);
443 argp_help (&argp, stderr, ARGP_HELP_SEE,
444 program_invocation_short_name);
445 exit (1);
446 }
447 any_control_option = true;
448 break;
449 case 'p':
450 any_control_option = true;
451 if (arg == NULL)
452 {
453 print_string_sections = true;
454 break;
455 }
456 /* Fall through. */
457 case 'x':
458 add_dump_section (arg, false);
459 any_control_option = true;
460 break;
461 case 'N':
462 print_address_names = false;
463 break;
Elliott Hughes03333822015-02-18 22:19:45 -0800464 case 'U':
465 print_unresolved_addresses = true;
466 break;
Ben Cheng25b3c042013-11-20 14:45:36 -0800467 case ARGP_KEY_NO_ARGS:
468 fputs (gettext ("Missing file name.\n"), stderr);
469 goto do_argp_help;
470 case ARGP_KEY_FINI:
471 if (! any_control_option && ! print_archive_index)
472 {
473 fputs (gettext ("No operation specified.\n"), stderr);
474 do_argp_help:
475 argp_help (&argp, stderr, ARGP_HELP_SEE,
476 program_invocation_short_name);
477 exit (EXIT_FAILURE);
478 }
479 break;
480 case 'W': /* Ignored. */
481 break;
Elliott Hughes03333822015-02-18 22:19:45 -0800482 case ELF_INPUT_SECTION:
483 if (arg == NULL)
484 elf_input_section = ".gnu_debugdata";
485 else
486 elf_input_section = arg;
487 break;
Ben Cheng25b3c042013-11-20 14:45:36 -0800488 default:
489 return ARGP_ERR_UNKNOWN;
490 }
491 return 0;
492}
493
494
495/* Print the version information. */
496static void
497print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
498{
499 fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
500 fprintf (stream, gettext ("\
501Copyright (C) %s Red Hat, Inc.\n\
502This is free software; see the source for copying conditions. There is NO\n\
503warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
504"), "2012");
505 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
506}
507
508
Elliott Hughes03333822015-02-18 22:19:45 -0800509/* Create a file descriptor to read the data from the
510 elf_input_section given a file descriptor to an ELF file. */
511static int
512open_input_section (int fd)
513{
514 size_t shnums;
515 size_t cnt;
516 size_t shstrndx;
517 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
518 if (elf == NULL)
519 {
520 error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
521 elf_errmsg (-1));
522 return -1;
523 }
524
525 if (elf_getshdrnum (elf, &shnums) < 0)
526 {
527 error (0, 0, gettext ("cannot determine number of sections: %s"),
528 elf_errmsg (-1));
529 open_error:
530 elf_end (elf);
531 return -1;
532 }
533
534 if (elf_getshdrstrndx (elf, &shstrndx) < 0)
535 {
536 error (0, 0, gettext ("cannot get section header string table index"));
537 goto open_error;
538 }
539
540 for (cnt = 0; cnt < shnums; ++cnt)
541 {
542 Elf_Scn *scn = elf_getscn (elf, cnt);
543 if (scn == NULL)
544 {
545 error (0, 0, gettext ("cannot get section: %s"),
546 elf_errmsg (-1));
547 goto open_error;
548 }
549
550 GElf_Shdr shdr_mem;
551 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
552 if (unlikely (shdr == NULL))
553 {
554 error (0, 0, gettext ("cannot get section header: %s"),
555 elf_errmsg (-1));
556 goto open_error;
557 }
558
559 const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
560 if (sname == NULL)
561 {
562 error (0, 0, gettext ("cannot get section name"));
563 goto open_error;
564 }
565
566 if (strcmp (sname, elf_input_section) == 0)
567 {
568 Elf_Data *data = elf_rawdata (scn, NULL);
569 if (data == NULL)
570 {
571 error (0, 0, gettext ("cannot get %s content: %s"),
572 sname, elf_errmsg (-1));
573 goto open_error;
574 }
575
576 /* Create (and immediately unlink) a temporary file to store
577 section data in to create a file descriptor for it. */
578 const char *tmpdir = getenv ("TMPDIR") ?: P_tmpdir;
579 static const char suffix[] = "/readelfXXXXXX";
580 int tmplen = strlen (tmpdir) + sizeof (suffix);
581 char *tempname = alloca (tmplen);
582 sprintf (tempname, "%s%s", tmpdir, suffix);
583
584 int sfd = mkstemp (tempname);
585 if (sfd == -1)
586 {
587 error (0, 0, gettext ("cannot create temp file '%s'"),
588 tempname);
589 goto open_error;
590 }
591 unlink (tempname);
592
593 ssize_t size = data->d_size;
594 if (write_retry (sfd, data->d_buf, size) != size)
595 {
596 error (0, 0, gettext ("cannot write section data"));
597 goto open_error;
598 }
599
600 if (elf_end (elf) != 0)
601 {
602 error (0, 0, gettext ("error while closing Elf descriptor: %s"),
603 elf_errmsg (-1));
604 return -1;
605 }
606
607 if (lseek (sfd, 0, SEEK_SET) == -1)
608 {
609 error (0, 0, gettext ("error while rewinding file descriptor"));
610 return -1;
611 }
612
613 return sfd;
614 }
615 }
616
617 /* Named section not found. */
618 if (elf_end (elf) != 0)
619 error (0, 0, gettext ("error while closing Elf descriptor: %s"),
620 elf_errmsg (-1));
621 return -1;
622}
623
Ben Cheng25b3c042013-11-20 14:45:36 -0800624/* Check if the file is an archive, and if so dump its index. */
625static void
626check_archive_index (int fd, const char *fname, bool only_one)
627{
628 /* Create an `Elf' descriptor. */
629 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
630 if (elf == NULL)
631 error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
632 elf_errmsg (-1));
633 else
634 {
635 if (elf_kind (elf) == ELF_K_AR)
636 {
637 if (!only_one)
638 printf ("\n%s:\n\n", fname);
639 dump_archive_index (elf, fname);
640 }
641 else
642 error (0, 0,
643 gettext ("'%s' is not an archive, cannot print archive index"),
644 fname);
645
646 /* Now we can close the descriptor. */
647 if (elf_end (elf) != 0)
648 error (0, 0, gettext ("error while closing Elf descriptor: %s"),
649 elf_errmsg (-1));
650 }
651}
652
653/* Trivial callback used for checking if we opened an archive. */
654static int
655count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
656 void **userdata __attribute__ ((unused)),
657 const char *name __attribute__ ((unused)),
658 Dwarf_Addr base __attribute__ ((unused)),
659 void *arg)
660{
661 if (*(bool *) arg)
662 return DWARF_CB_ABORT;
663 *(bool *) arg = true;
664 return DWARF_CB_OK;
665}
666
667struct process_dwflmod_args
668{
669 int fd;
670 bool only_one;
671};
672
673static int
674process_dwflmod (Dwfl_Module *dwflmod,
675 void **userdata __attribute__ ((unused)),
676 const char *name __attribute__ ((unused)),
677 Dwarf_Addr base __attribute__ ((unused)),
678 void *arg)
679{
680 const struct process_dwflmod_args *a = arg;
681
682 /* Print the file name. */
683 if (!a->only_one)
684 {
685 const char *fname;
686 dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
687
688 printf ("\n%s:\n\n", fname);
689 }
690
691 process_elf_file (dwflmod, a->fd);
692
693 return DWARF_CB_OK;
694}
695
Elliott Hughes03333822015-02-18 22:19:45 -0800696/* Stub libdwfl callback, only the ELF handle already open is ever used.
697 Only used for finding the alternate debug file if the Dwarf comes from
698 the main file. We are not interested in separate debuginfo. */
Ben Cheng25b3c042013-11-20 14:45:36 -0800699static int
Elliott Hughes03333822015-02-18 22:19:45 -0800700find_no_debuginfo (Dwfl_Module *mod,
701 void **userdata,
702 const char *modname,
703 Dwarf_Addr base,
704 const char *file_name,
705 const char *debuglink_file,
706 GElf_Word debuglink_crc,
707 char **debuginfo_file_name)
Ben Cheng25b3c042013-11-20 14:45:36 -0800708{
Elliott Hughes03333822015-02-18 22:19:45 -0800709 Dwarf_Addr dwbias;
710 dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
711
712 /* We are only interested if the Dwarf has been setup on the main
713 elf file but is only missing the alternate debug link. If dwbias
714 hasn't even been setup, this is searching for separate debuginfo
715 for the main elf. We don't care in that case. */
716 if (dwbias == (Dwarf_Addr) -1)
717 return -1;
718
719 return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
720 file_name, debuglink_file,
721 debuglink_crc, debuginfo_file_name);
Ben Cheng25b3c042013-11-20 14:45:36 -0800722}
723
724/* Process one input file. */
725static void
726process_file (int fd, const char *fname, bool only_one)
727{
728 if (print_archive_index)
729 check_archive_index (fd, fname, only_one);
730
731 if (!any_control_option)
732 return;
733
Elliott Hughes03333822015-02-18 22:19:45 -0800734 if (elf_input_section != NULL)
735 {
736 /* Replace fname and fd with section content. */
737 char *fnname = alloca (strlen (fname) + strlen (elf_input_section) + 2);
738 sprintf (fnname, "%s:%s", fname, elf_input_section);
739 fd = open_input_section (fd);
740 if (fd == -1)
741 {
742 error (0, 0, gettext ("No such section '%s' in '%s'"),
743 elf_input_section, fname);
744 return;
745 }
746 fname = fnname;
747 }
748
Ben Cheng25b3c042013-11-20 14:45:36 -0800749 /* Duplicate an fd for dwfl_report_offline to swallow. */
750 int dwfl_fd = dup (fd);
751 if (unlikely (dwfl_fd < 0))
752 error (EXIT_FAILURE, errno, "dup");
753
754 /* Use libdwfl in a trivial way to open the libdw handle for us.
755 This takes care of applying relocations to DWARF data in ET_REL files. */
756 static const Dwfl_Callbacks callbacks =
757 {
758 .section_address = dwfl_offline_section_address,
759 .find_debuginfo = find_no_debuginfo
760 };
761 Dwfl *dwfl = dwfl_begin (&callbacks);
762 if (likely (dwfl != NULL))
763 /* Let 0 be the logical address of the file (or first in archive). */
764 dwfl->offline_next_address = 0;
765 if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
766 {
767 struct stat64 st;
768 if (fstat64 (dwfl_fd, &st) != 0)
769 error (0, errno, gettext ("cannot stat input file"));
770 else if (unlikely (st.st_size == 0))
771 error (0, 0, gettext ("input file is empty"));
772 else
773 error (0, 0, gettext ("failed reading '%s': %s"),
774 fname, dwfl_errmsg (-1));
775 close (dwfl_fd); /* Consumed on success, not on failure. */
776 }
777 else
778 {
779 dwfl_report_end (dwfl, NULL, NULL);
780
781 if (only_one)
782 {
783 /* Clear ONLY_ONE if we have multiple modules, from an archive. */
784 bool seen = false;
785 only_one = dwfl_getmodules (dwfl, &count_dwflmod, &seen, 0) == 0;
786 }
787
788 /* Process the one or more modules gleaned from this file. */
789 struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
790 dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
791 }
792 dwfl_end (dwfl);
Elliott Hughes03333822015-02-18 22:19:45 -0800793
794 /* Need to close the replaced fd if we created it. Caller takes
795 care of original. */
796 if (elf_input_section != NULL)
797 close (fd);
Ben Cheng25b3c042013-11-20 14:45:36 -0800798}
799
800
801/* Process one ELF file. */
802static void
803process_elf_file (Dwfl_Module *dwflmod, int fd)
804{
805 GElf_Addr dwflbias;
806 Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
807
808 GElf_Ehdr ehdr_mem;
809 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
810
811 if (ehdr == NULL)
812 {
813 elf_error:
814 error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
815 return;
816 }
817
818 Ebl *ebl = ebl_openbackend (elf);
819 if (unlikely (ebl == NULL))
820 {
821 ebl_error:
822 error (0, errno, gettext ("cannot create EBL handle"));
823 return;
824 }
825
826 /* Determine the number of sections. */
827 if (unlikely (elf_getshdrnum (ebl->elf, &shnum) < 0))
828 error (EXIT_FAILURE, 0,
829 gettext ("cannot determine number of sections: %s"),
830 elf_errmsg (-1));
831
832 /* Determine the number of phdrs. */
833 if (unlikely (elf_getphdrnum (ebl->elf, &phnum) < 0))
834 error (EXIT_FAILURE, 0,
835 gettext ("cannot determine number of program headers: %s"),
836 elf_errmsg (-1));
837
838 /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
839 and may have applied relocation to some sections.
840 So we need to get a fresh Elf handle on the file to display those. */
841 bool print_unrelocated = (print_section_header
842 || print_relocations
843 || dump_data_sections != NULL
844 || print_notes);
845
846 Elf *pure_elf = NULL;
847 Ebl *pure_ebl = ebl;
848 if (ehdr->e_type == ET_REL && print_unrelocated)
849 {
850 /* Read the file afresh. */
851 off64_t aroff = elf_getaroff (elf);
852 pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
853 if (aroff > 0)
854 {
855 /* Archive member. */
856 (void) elf_rand (pure_elf, aroff);
857 Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
858 elf_end (pure_elf);
859 pure_elf = armem;
860 }
861 if (pure_elf == NULL)
862 goto elf_error;
863 pure_ebl = ebl_openbackend (pure_elf);
864 if (pure_ebl == NULL)
865 goto ebl_error;
866 }
867
868 if (print_file_header)
869 print_ehdr (ebl, ehdr);
870 if (print_section_header)
871 print_shdr (pure_ebl, ehdr);
872 if (print_program_header)
873 print_phdr (ebl, ehdr);
874 if (print_section_groups)
875 print_scngrp (ebl);
876 if (print_dynamic_table)
877 print_dynamic (ebl);
878 if (print_relocations)
879 print_relocs (pure_ebl, ehdr);
880 if (print_histogram)
881 handle_hash (ebl);
882 if (print_symbol_table)
883 print_symtab (ebl, SHT_DYNSYM);
884 if (print_version_info)
885 print_verinfo (ebl);
886 if (print_symbol_table)
887 print_symtab (ebl, SHT_SYMTAB);
888 if (print_arch)
889 print_liblist (ebl);
890 if (print_arch)
891 print_attributes (ebl, ehdr);
892 if (dump_data_sections != NULL)
893 dump_data (pure_ebl);
894 if (string_sections != NULL)
895 dump_strings (ebl);
896 if ((print_debug_sections | implicit_debug_sections) != 0)
897 print_debug (dwflmod, ebl, ehdr);
898 if (print_notes)
899 handle_notes (pure_ebl, ehdr);
900 if (print_string_sections)
901 print_strings (ebl);
902
903 ebl_closebackend (ebl);
904
905 if (pure_ebl != ebl)
906 {
907 ebl_closebackend (pure_ebl);
908 elf_end (pure_elf);
909 }
910}
911
912
913/* Print file type. */
914static void
915print_file_type (unsigned short int e_type)
916{
917 if (likely (e_type <= ET_CORE))
918 {
919 static const char *const knowntypes[] =
920 {
921 N_("NONE (None)"),
922 N_("REL (Relocatable file)"),
923 N_("EXEC (Executable file)"),
924 N_("DYN (Shared object file)"),
925 N_("CORE (Core file)")
926 };
927 puts (gettext (knowntypes[e_type]));
928 }
929 else if (e_type >= ET_LOOS && e_type <= ET_HIOS)
930 printf (gettext ("OS Specific: (%x)\n"), e_type);
931 else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */)
932 printf (gettext ("Processor Specific: (%x)\n"), e_type);
933 else
934 puts ("???");
935}
936
937
938/* Print ELF header. */
939static void
940print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
941{
942 fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout);
943 for (size_t cnt = 0; cnt < EI_NIDENT; ++cnt)
944 printf (" %02hhx", ehdr->e_ident[cnt]);
945
946 printf (gettext ("\n Class: %s\n"),
947 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32"
948 : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64"
949 : "\?\?\?");
950
951 printf (gettext (" Data: %s\n"),
952 ehdr->e_ident[EI_DATA] == ELFDATA2LSB
953 ? "2's complement, little endian"
954 : ehdr->e_ident[EI_DATA] == ELFDATA2MSB
955 ? "2's complement, big endian" : "\?\?\?");
956
957 printf (gettext (" Ident Version: %hhd %s\n"),
958 ehdr->e_ident[EI_VERSION],
959 ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)")
960 : "(\?\?\?)");
961
962 char buf[512];
963 printf (gettext (" OS/ABI: %s\n"),
964 ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
965
966 printf (gettext (" ABI Version: %hhd\n"),
967 ehdr->e_ident[EI_ABIVERSION]);
968
969 fputs_unlocked (gettext (" Type: "), stdout);
970 print_file_type (ehdr->e_type);
971
972 printf (gettext (" Machine: %s\n"), ebl->name);
973
974 printf (gettext (" Version: %d %s\n"),
975 ehdr->e_version,
976 ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)");
977
978 printf (gettext (" Entry point address: %#" PRIx64 "\n"),
979 ehdr->e_entry);
980
981 printf (gettext (" Start of program headers: %" PRId64 " %s\n"),
982 ehdr->e_phoff, gettext ("(bytes into file)"));
983
984 printf (gettext (" Start of section headers: %" PRId64 " %s\n"),
985 ehdr->e_shoff, gettext ("(bytes into file)"));
986
987 printf (gettext (" Flags: %s\n"),
988 ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
989
990 printf (gettext (" Size of this header: %" PRId16 " %s\n"),
991 ehdr->e_ehsize, gettext ("(bytes)"));
992
993 printf (gettext (" Size of program header entries: %" PRId16 " %s\n"),
994 ehdr->e_phentsize, gettext ("(bytes)"));
995
996 printf (gettext (" Number of program headers entries: %" PRId16),
997 ehdr->e_phnum);
998 if (ehdr->e_phnum == PN_XNUM)
999 {
1000 GElf_Shdr shdr_mem;
1001 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
1002 if (shdr != NULL)
1003 printf (gettext (" (%" PRIu32 " in [0].sh_info)"),
1004 (uint32_t) shdr->sh_info);
1005 else
1006 fputs_unlocked (gettext (" ([0] not available)"), stdout);
1007 }
1008 fputc_unlocked ('\n', stdout);
1009
1010 printf (gettext (" Size of section header entries: %" PRId16 " %s\n"),
1011 ehdr->e_shentsize, gettext ("(bytes)"));
1012
1013 printf (gettext (" Number of section headers entries: %" PRId16),
1014 ehdr->e_shnum);
1015 if (ehdr->e_shnum == 0)
1016 {
1017 GElf_Shdr shdr_mem;
1018 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
1019 if (shdr != NULL)
1020 printf (gettext (" (%" PRIu32 " in [0].sh_size)"),
1021 (uint32_t) shdr->sh_size);
1022 else
1023 fputs_unlocked (gettext (" ([0] not available)"), stdout);
1024 }
1025 fputc_unlocked ('\n', stdout);
1026
1027 if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
1028 {
1029 GElf_Shdr shdr_mem;
1030 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
1031 if (shdr != NULL)
1032 /* We managed to get the zeroth section. */
1033 snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"),
1034 (uint32_t) shdr->sh_link);
1035 else
1036 {
1037 strncpy (buf, gettext (" ([0] not available)"), sizeof (buf));
1038 buf[sizeof (buf) - 1] = '\0';
1039 }
1040
1041 printf (gettext (" Section header string table index: XINDEX%s\n\n"),
1042 buf);
1043 }
1044 else
1045 printf (gettext (" Section header string table index: %" PRId16 "\n\n"),
1046 ehdr->e_shstrndx);
1047}
1048
1049
1050static const char *
1051get_visibility_type (int value)
1052{
1053 switch (value)
1054 {
1055 case STV_DEFAULT:
1056 return "DEFAULT";
1057 case STV_INTERNAL:
1058 return "INTERNAL";
1059 case STV_HIDDEN:
1060 return "HIDDEN";
1061 case STV_PROTECTED:
1062 return "PROTECTED";
1063 default:
1064 return "???";
1065 }
1066}
1067
1068
1069/* Print the section headers. */
1070static void
1071print_shdr (Ebl *ebl, GElf_Ehdr *ehdr)
1072{
1073 size_t cnt;
1074 size_t shstrndx;
1075
1076 if (! print_file_header)
1077 printf (gettext ("\
1078There are %d section headers, starting at offset %#" PRIx64 ":\n\
1079\n"),
1080 ehdr->e_shnum, ehdr->e_shoff);
1081
1082 /* Get the section header string table index. */
1083 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1084 error (EXIT_FAILURE, 0,
1085 gettext ("cannot get section header string table index"));
1086
1087 puts (gettext ("Section Headers:"));
1088
1089 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1090 puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
1091 else
1092 puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
1093
1094 for (cnt = 0; cnt < shnum; ++cnt)
1095 {
1096 Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
1097
1098 if (unlikely (scn == NULL))
1099 error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
1100 elf_errmsg (-1));
1101
1102 /* Get the section header. */
1103 GElf_Shdr shdr_mem;
1104 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1105 if (unlikely (shdr == NULL))
1106 error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
1107 elf_errmsg (-1));
1108
1109 char flagbuf[20];
1110 char *cp = flagbuf;
1111 if (shdr->sh_flags & SHF_WRITE)
1112 *cp++ = 'W';
1113 if (shdr->sh_flags & SHF_ALLOC)
1114 *cp++ = 'A';
1115 if (shdr->sh_flags & SHF_EXECINSTR)
1116 *cp++ = 'X';
1117 if (shdr->sh_flags & SHF_MERGE)
1118 *cp++ = 'M';
1119 if (shdr->sh_flags & SHF_STRINGS)
1120 *cp++ = 'S';
1121 if (shdr->sh_flags & SHF_INFO_LINK)
1122 *cp++ = 'I';
1123 if (shdr->sh_flags & SHF_LINK_ORDER)
1124 *cp++ = 'L';
1125 if (shdr->sh_flags & SHF_OS_NONCONFORMING)
1126 *cp++ = 'N';
1127 if (shdr->sh_flags & SHF_GROUP)
1128 *cp++ = 'G';
1129 if (shdr->sh_flags & SHF_TLS)
1130 *cp++ = 'T';
1131 if (shdr->sh_flags & SHF_ORDERED)
1132 *cp++ = 'O';
1133 if (shdr->sh_flags & SHF_EXCLUDE)
1134 *cp++ = 'E';
1135 *cp = '\0';
1136
1137 char buf[128];
1138 printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64
1139 " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32
1140 " %2" PRId64 "\n",
1141 cnt,
1142 elf_strptr (ebl->elf, shstrndx, shdr->sh_name)
1143 ?: "<corrupt>",
1144 ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)),
1145 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr,
1146 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset,
1147 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size,
1148 shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info,
1149 shdr->sh_addralign);
1150 }
1151
1152 fputc_unlocked ('\n', stdout);
1153}
1154
1155
1156/* Print the program header. */
1157static void
1158print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
1159{
Elliott Hughes03333822015-02-18 22:19:45 -08001160 if (phnum == 0)
Ben Cheng25b3c042013-11-20 14:45:36 -08001161 /* No program header, this is OK in relocatable objects. */
1162 return;
1163
1164 puts (gettext ("Program Headers:"));
1165 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1166 puts (gettext ("\
1167 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
1168 else
1169 puts (gettext ("\
1170 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
1171
1172 /* Process all program headers. */
1173 bool has_relro = false;
1174 GElf_Addr relro_from = 0;
1175 GElf_Addr relro_to = 0;
1176 for (size_t cnt = 0; cnt < phnum; ++cnt)
1177 {
1178 char buf[128];
1179 GElf_Phdr mem;
1180 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
1181
1182 /* If for some reason the header cannot be returned show this. */
1183 if (unlikely (phdr == NULL))
1184 {
1185 puts (" ???");
1186 continue;
1187 }
1188
1189 printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64
1190 " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n",
1191 ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)),
1192 phdr->p_offset,
1193 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr,
1194 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr,
1195 phdr->p_filesz,
1196 phdr->p_memsz,
1197 phdr->p_flags & PF_R ? 'R' : ' ',
1198 phdr->p_flags & PF_W ? 'W' : ' ',
1199 phdr->p_flags & PF_X ? 'E' : ' ',
1200 phdr->p_align);
1201
1202 if (phdr->p_type == PT_INTERP)
1203 {
Elliott Hughes03333822015-02-18 22:19:45 -08001204 /* If we are sure the file offset is valid then we can show
1205 the user the name of the interpreter. We check whether
1206 there is a section at the file offset. Normally there
1207 would be a section called ".interp". But in separate
1208 .debug files it is a NOBITS section (and so doesn't match
1209 with gelf_offscn). Which probably means the offset is
1210 not valid another reason could be because the ELF file
1211 just doesn't contain any section headers, in that case
1212 just play it safe and don't display anything. */
1213
1214 Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
1215 GElf_Shdr shdr_mem;
1216 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1217
Ben Cheng25b3c042013-11-20 14:45:36 -08001218 size_t maxsize;
1219 char *filedata = elf_rawfile (ebl->elf, &maxsize);
1220
Elliott Hughes03333822015-02-18 22:19:45 -08001221 if (shdr != NULL && shdr->sh_type == SHT_PROGBITS
1222 && filedata != NULL && phdr->p_offset < maxsize
1223 && phdr->p_filesz <= maxsize - phdr->p_offset
1224 && memchr (filedata + phdr->p_offset, '\0',
1225 phdr->p_filesz) != NULL)
Ben Cheng25b3c042013-11-20 14:45:36 -08001226 printf (gettext ("\t[Requesting program interpreter: %s]\n"),
1227 filedata + phdr->p_offset);
1228 }
1229 else if (phdr->p_type == PT_GNU_RELRO)
1230 {
1231 has_relro = true;
1232 relro_from = phdr->p_vaddr;
1233 relro_to = relro_from + phdr->p_memsz;
1234 }
1235 }
1236
1237 if (ehdr->e_shnum == 0)
1238 /* No sections in the file. Punt. */
1239 return;
1240
1241 /* Get the section header string table index. */
1242 size_t shstrndx;
1243 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1244 error (EXIT_FAILURE, 0,
1245 gettext ("cannot get section header string table index"));
1246
1247 puts (gettext ("\n Section to Segment mapping:\n Segment Sections..."));
1248
1249 for (size_t cnt = 0; cnt < phnum; ++cnt)
1250 {
1251 /* Print the segment number. */
1252 printf (" %2.2zu ", cnt);
1253
1254 GElf_Phdr phdr_mem;
1255 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
1256 /* This must not happen. */
1257 if (unlikely (phdr == NULL))
1258 error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
1259 elf_errmsg (-1));
1260
1261 /* Iterate over the sections. */
1262 bool in_relro = false;
1263 bool in_ro = false;
1264 for (size_t inner = 1; inner < shnum; ++inner)
1265 {
1266 Elf_Scn *scn = elf_getscn (ebl->elf, inner);
1267 /* This should not happen. */
1268 if (unlikely (scn == NULL))
1269 error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
1270 elf_errmsg (-1));
1271
1272 /* Get the section header. */
1273 GElf_Shdr shdr_mem;
1274 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1275 if (unlikely (shdr == NULL))
1276 error (EXIT_FAILURE, 0,
1277 gettext ("cannot get section header: %s"),
1278 elf_errmsg (-1));
1279
1280 if (shdr->sh_size > 0
1281 /* Compare allocated sections by VMA, unallocated
1282 sections by file offset. */
1283 && (shdr->sh_flags & SHF_ALLOC
1284 ? (shdr->sh_addr >= phdr->p_vaddr
1285 && (shdr->sh_addr + shdr->sh_size
1286 <= phdr->p_vaddr + phdr->p_memsz))
1287 : (shdr->sh_offset >= phdr->p_offset
1288 && (shdr->sh_offset + shdr->sh_size
1289 <= phdr->p_offset + phdr->p_filesz))))
1290 {
1291 if (has_relro && !in_relro
1292 && shdr->sh_addr >= relro_from
1293 && shdr->sh_addr + shdr->sh_size <= relro_to)
1294 {
1295 fputs_unlocked (" [RELRO:", stdout);
1296 in_relro = true;
1297 }
1298 else if (has_relro && in_relro && shdr->sh_addr >= relro_to)
1299 {
1300 fputs_unlocked ("]", stdout);
1301 in_relro = false;
1302 }
1303 else if (has_relro && in_relro
1304 && shdr->sh_addr + shdr->sh_size > relro_to)
1305 fputs_unlocked ("] <RELRO:", stdout);
1306 else if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
1307 {
1308 if (!in_ro)
1309 {
1310 fputs_unlocked (" [RO:", stdout);
1311 in_ro = true;
1312 }
1313 }
1314 else
1315 {
1316 /* Determine the segment this section is part of. */
1317 size_t cnt2;
1318 GElf_Phdr *phdr2 = NULL;
1319 for (cnt2 = 0; cnt2 < phnum; ++cnt2)
1320 {
1321 GElf_Phdr phdr2_mem;
1322 phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
1323
1324 if (phdr2 != NULL && phdr2->p_type == PT_LOAD
1325 && shdr->sh_addr >= phdr2->p_vaddr
1326 && (shdr->sh_addr + shdr->sh_size
1327 <= phdr2->p_vaddr + phdr2->p_memsz))
1328 break;
1329 }
1330
1331 if (cnt2 < phnum)
1332 {
1333 if ((phdr2->p_flags & PF_W) == 0 && !in_ro)
1334 {
1335 fputs_unlocked (" [RO:", stdout);
1336 in_ro = true;
1337 }
1338 else if ((phdr2->p_flags & PF_W) != 0 && in_ro)
1339 {
1340 fputs_unlocked ("]", stdout);
1341 in_ro = false;
1342 }
1343 }
1344 }
1345
1346 printf (" %s",
1347 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1348
1349 /* Signal that this sectin is only partially covered. */
1350 if (has_relro && in_relro
1351 && shdr->sh_addr + shdr->sh_size > relro_to)
1352 {
1353 fputs_unlocked (">", stdout);
1354 in_relro = false;
1355 }
1356 }
1357 }
1358 if (in_relro || in_ro)
1359 fputs_unlocked ("]", stdout);
1360
1361 /* Finish the line. */
1362 fputc_unlocked ('\n', stdout);
1363 }
1364}
1365
1366
1367static const char *
1368section_name (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
1369{
1370 return elf_strptr (ebl->elf, ehdr->e_shstrndx, shdr->sh_name) ?: "???";
1371}
1372
1373
1374static void
1375handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1376{
1377 /* Get the data of the section. */
1378 Elf_Data *data = elf_getdata (scn, NULL);
1379
1380 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1381 GElf_Shdr symshdr_mem;
1382 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1383 Elf_Data *symdata = elf_getdata (symscn, NULL);
1384
1385 if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL
1386 || symdata == NULL)
1387 return;
1388
1389 /* Get the section header string table index. */
1390 size_t shstrndx;
1391 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1392 error (EXIT_FAILURE, 0,
1393 gettext ("cannot get section header string table index"));
1394
1395 Elf32_Word *grpref = (Elf32_Word *) data->d_buf;
1396
1397 GElf_Sym sym_mem;
Elliott Hughes03333822015-02-18 22:19:45 -08001398 GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
1399
Ben Cheng25b3c042013-11-20 14:45:36 -08001400 printf ((grpref[0] & GRP_COMDAT)
1401 ? ngettext ("\
1402\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n",
1403 "\
1404\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1405 data->d_size / sizeof (Elf32_Word) - 1)
1406 : ngettext ("\
1407\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\
1408\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1409 data->d_size / sizeof (Elf32_Word) - 1),
1410 elf_ndxscn (scn),
1411 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
Elliott Hughes03333822015-02-18 22:19:45 -08001412 (sym == NULL ? NULL
1413 : elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name))
Ben Cheng25b3c042013-11-20 14:45:36 -08001414 ?: gettext ("<INVALID SYMBOL>"),
1415 data->d_size / sizeof (Elf32_Word) - 1);
1416
1417 for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
1418 {
1419 GElf_Shdr grpshdr_mem;
1420 GElf_Shdr *grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
1421 &grpshdr_mem);
1422
1423 const char *str;
1424 printf (" [%2u] %s\n",
1425 grpref[cnt],
1426 grpshdr != NULL
1427 && (str = elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name))
1428 ? str : gettext ("<INVALID SECTION>"));
1429 }
1430}
1431
1432
1433static void
1434print_scngrp (Ebl *ebl)
1435{
1436 /* Find all relocation sections and handle them. */
1437 Elf_Scn *scn = NULL;
1438
1439 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1440 {
1441 /* Handle the section if it is a symbol table. */
1442 GElf_Shdr shdr_mem;
1443 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1444
1445 if (shdr != NULL && shdr->sh_type == SHT_GROUP)
1446 handle_scngrp (ebl, scn, shdr);
1447 }
1448}
1449
1450
1451static const struct flags
1452{
1453 int mask;
1454 const char *str;
1455} dt_flags[] =
1456 {
1457 { DF_ORIGIN, "ORIGIN" },
1458 { DF_SYMBOLIC, "SYMBOLIC" },
1459 { DF_TEXTREL, "TEXTREL" },
1460 { DF_BIND_NOW, "BIND_NOW" },
1461 { DF_STATIC_TLS, "STATIC_TLS" }
1462 };
1463static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]);
1464
1465static const struct flags dt_flags_1[] =
1466 {
1467 { DF_1_NOW, "NOW" },
1468 { DF_1_GLOBAL, "GLOBAL" },
1469 { DF_1_GROUP, "GROUP" },
1470 { DF_1_NODELETE, "NODELETE" },
1471 { DF_1_LOADFLTR, "LOADFLTR" },
1472 { DF_1_INITFIRST, "INITFIRST" },
1473 { DF_1_NOOPEN, "NOOPEN" },
1474 { DF_1_ORIGIN, "ORIGIN" },
1475 { DF_1_DIRECT, "DIRECT" },
1476 { DF_1_TRANS, "TRANS" },
1477 { DF_1_INTERPOSE, "INTERPOSE" },
1478 { DF_1_NODEFLIB, "NODEFLIB" },
1479 { DF_1_NODUMP, "NODUMP" },
1480 { DF_1_CONFALT, "CONFALT" },
1481 { DF_1_ENDFILTEE, "ENDFILTEE" },
1482 { DF_1_DISPRELDNE, "DISPRELDNE" },
1483 { DF_1_DISPRELPND, "DISPRELPND" },
1484 };
1485static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]);
1486
1487static const struct flags dt_feature_1[] =
1488 {
1489 { DTF_1_PARINIT, "PARINIT" },
1490 { DTF_1_CONFEXP, "CONFEXP" }
1491 };
1492static const int ndt_feature_1 = (sizeof (dt_feature_1)
1493 / sizeof (dt_feature_1[0]));
1494
1495static const struct flags dt_posflag_1[] =
1496 {
1497 { DF_P1_LAZYLOAD, "LAZYLOAD" },
1498 { DF_P1_GROUPPERM, "GROUPPERM" }
1499 };
1500static const int ndt_posflag_1 = (sizeof (dt_posflag_1)
1501 / sizeof (dt_posflag_1[0]));
1502
1503
1504static void
1505print_flags (int class, GElf_Xword d_val, const struct flags *flags,
1506 int nflags)
1507{
1508 bool first = true;
1509 int cnt;
1510
1511 for (cnt = 0; cnt < nflags; ++cnt)
1512 if (d_val & flags[cnt].mask)
1513 {
1514 if (!first)
1515 putchar_unlocked (' ');
1516 fputs_unlocked (flags[cnt].str, stdout);
1517 d_val &= ~flags[cnt].mask;
1518 first = false;
1519 }
1520
1521 if (d_val != 0)
1522 {
1523 if (!first)
1524 putchar_unlocked (' ');
1525 printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val);
1526 }
1527
1528 putchar_unlocked ('\n');
1529}
1530
1531
1532static void
1533print_dt_flags (int class, GElf_Xword d_val)
1534{
1535 print_flags (class, d_val, dt_flags, ndt_flags);
1536}
1537
1538
1539static void
1540print_dt_flags_1 (int class, GElf_Xword d_val)
1541{
1542 print_flags (class, d_val, dt_flags_1, ndt_flags_1);
1543}
1544
1545
1546static void
1547print_dt_feature_1 (int class, GElf_Xword d_val)
1548{
1549 print_flags (class, d_val, dt_feature_1, ndt_feature_1);
1550}
1551
1552
1553static void
1554print_dt_posflag_1 (int class, GElf_Xword d_val)
1555{
1556 print_flags (class, d_val, dt_posflag_1, ndt_posflag_1);
1557}
1558
1559
1560static void
1561handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1562{
1563 int class = gelf_getclass (ebl->elf);
Elliott Hughes03333822015-02-18 22:19:45 -08001564 GElf_Shdr glink_mem;
1565 GElf_Shdr *glink;
Ben Cheng25b3c042013-11-20 14:45:36 -08001566 Elf_Data *data;
1567 size_t cnt;
1568 size_t shstrndx;
Elliott Hughes03333822015-02-18 22:19:45 -08001569 size_t sh_entsize;
Ben Cheng25b3c042013-11-20 14:45:36 -08001570
1571 /* Get the data of the section. */
1572 data = elf_getdata (scn, NULL);
1573 if (data == NULL)
1574 return;
1575
1576 /* Get the section header string table index. */
1577 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1578 error (EXIT_FAILURE, 0,
1579 gettext ("cannot get section header string table index"));
1580
Elliott Hughes03333822015-02-18 22:19:45 -08001581 sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT);
1582
1583 glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
1584 if (glink == NULL)
1585 error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
1586 elf_ndxscn (scn));
1587
Ben Cheng25b3c042013-11-20 14:45:36 -08001588 printf (ngettext ("\
1589\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
1590 "\
1591\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
Elliott Hughes03333822015-02-18 22:19:45 -08001592 shdr->sh_size / sh_entsize),
1593 (unsigned long int) (shdr->sh_size / sh_entsize),
Ben Cheng25b3c042013-11-20 14:45:36 -08001594 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
1595 shdr->sh_offset,
1596 (int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08001597 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08001598 fputs_unlocked (gettext (" Type Value\n"), stdout);
1599
Elliott Hughes03333822015-02-18 22:19:45 -08001600 for (cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt)
Ben Cheng25b3c042013-11-20 14:45:36 -08001601 {
1602 GElf_Dyn dynmem;
1603 GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
1604 if (dyn == NULL)
1605 break;
1606
1607 char buf[64];
1608 printf (" %-17s ",
1609 ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));
1610
1611 switch (dyn->d_tag)
1612 {
1613 case DT_NULL:
1614 case DT_DEBUG:
1615 case DT_BIND_NOW:
1616 case DT_TEXTREL:
1617 /* No further output. */
1618 fputc_unlocked ('\n', stdout);
1619 break;
1620
1621 case DT_NEEDED:
1622 printf (gettext ("Shared library: [%s]\n"),
1623 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1624 break;
1625
1626 case DT_SONAME:
1627 printf (gettext ("Library soname: [%s]\n"),
1628 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1629 break;
1630
1631 case DT_RPATH:
1632 printf (gettext ("Library rpath: [%s]\n"),
1633 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1634 break;
1635
1636 case DT_RUNPATH:
1637 printf (gettext ("Library runpath: [%s]\n"),
1638 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1639 break;
1640
1641 case DT_PLTRELSZ:
1642 case DT_RELASZ:
1643 case DT_STRSZ:
1644 case DT_RELSZ:
1645 case DT_RELAENT:
1646 case DT_SYMENT:
1647 case DT_RELENT:
1648 case DT_PLTPADSZ:
1649 case DT_MOVEENT:
1650 case DT_MOVESZ:
1651 case DT_INIT_ARRAYSZ:
1652 case DT_FINI_ARRAYSZ:
1653 case DT_SYMINSZ:
1654 case DT_SYMINENT:
1655 case DT_GNU_CONFLICTSZ:
1656 case DT_GNU_LIBLISTSZ:
1657 printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val);
1658 break;
1659
1660 case DT_VERDEFNUM:
1661 case DT_VERNEEDNUM:
1662 case DT_RELACOUNT:
1663 case DT_RELCOUNT:
1664 printf ("%" PRId64 "\n", dyn->d_un.d_val);
1665 break;
1666
1667 case DT_PLTREL:;
1668 const char *tagname = ebl_dynamic_tag_name (ebl, dyn->d_un.d_val,
1669 NULL, 0);
1670 puts (tagname ?: "???");
1671 break;
1672
1673 case DT_FLAGS:
1674 print_dt_flags (class, dyn->d_un.d_val);
1675 break;
1676
1677 case DT_FLAGS_1:
1678 print_dt_flags_1 (class, dyn->d_un.d_val);
1679 break;
1680
1681 case DT_FEATURE_1:
1682 print_dt_feature_1 (class, dyn->d_un.d_val);
1683 break;
1684
1685 case DT_POSFLAG_1:
1686 print_dt_posflag_1 (class, dyn->d_un.d_val);
1687 break;
1688
1689 default:
1690 printf ("%#0*" PRIx64 "\n",
1691 class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val);
1692 break;
1693 }
1694 }
1695}
1696
1697
1698/* Print the dynamic segment. */
1699static void
1700print_dynamic (Ebl *ebl)
1701{
1702 for (size_t i = 0; i < phnum; ++i)
1703 {
1704 GElf_Phdr phdr_mem;
1705 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
1706
1707 if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
1708 {
1709 Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
1710 GElf_Shdr shdr_mem;
1711 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1712 if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
1713 handle_dynamic (ebl, scn, shdr);
1714 break;
1715 }
1716 }
1717}
1718
1719
1720/* Print relocations. */
1721static void
1722print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
1723{
1724 /* Find all relocation sections and handle them. */
1725 Elf_Scn *scn = NULL;
1726
1727 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1728 {
1729 /* Handle the section if it is a symbol table. */
1730 GElf_Shdr shdr_mem;
1731 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1732
1733 if (likely (shdr != NULL))
1734 {
1735 if (shdr->sh_type == SHT_REL)
1736 handle_relocs_rel (ebl, ehdr, scn, shdr);
1737 else if (shdr->sh_type == SHT_RELA)
1738 handle_relocs_rela (ebl, ehdr, scn, shdr);
1739 }
1740 }
1741}
1742
1743
1744/* Handle a relocation section. */
1745static void
1746handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
1747{
1748 int class = gelf_getclass (ebl->elf);
Elliott Hughes03333822015-02-18 22:19:45 -08001749 size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT);
1750 int nentries = shdr->sh_size / sh_entsize;
Ben Cheng25b3c042013-11-20 14:45:36 -08001751
1752 /* Get the data of the section. */
1753 Elf_Data *data = elf_getdata (scn, NULL);
1754 if (data == NULL)
1755 return;
1756
1757 /* Get the symbol table information. */
1758 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1759 GElf_Shdr symshdr_mem;
1760 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1761 Elf_Data *symdata = elf_getdata (symscn, NULL);
1762
1763 /* Get the section header of the section the relocations are for. */
1764 GElf_Shdr destshdr_mem;
1765 GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1766 &destshdr_mem);
1767
1768 if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
1769 {
1770 printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1771 shdr->sh_offset);
1772 return;
1773 }
1774
1775 /* Search for the optional extended section index table. */
1776 Elf_Data *xndxdata = NULL;
1777 int xndxscnidx = elf_scnshndx (scn);
1778 if (unlikely (xndxscnidx > 0))
1779 xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
1780
1781 /* Get the section header string table index. */
1782 size_t shstrndx;
1783 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1784 error (EXIT_FAILURE, 0,
1785 gettext ("cannot get section header string table index"));
1786
1787 if (shdr->sh_info != 0)
1788 printf (ngettext ("\
1789\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1790 "\
1791\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1792 nentries),
1793 elf_ndxscn (scn),
1794 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1795 (unsigned int) shdr->sh_info,
1796 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1797 shdr->sh_offset,
1798 nentries);
1799 else
1800 /* The .rel.dyn section does not refer to a specific section but
1801 instead of section index zero. Do not try to print a section
1802 name. */
1803 printf (ngettext ("\
1804\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1805 "\
1806\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1807 nentries),
1808 (unsigned int) elf_ndxscn (scn),
1809 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1810 shdr->sh_offset,
1811 nentries);
1812 fputs_unlocked (class == ELFCLASS32
1813 ? gettext ("\
1814 Offset Type Value Name\n")
1815 : gettext ("\
1816 Offset Type Value Name\n"),
1817 stdout);
1818
1819 int is_statically_linked = 0;
1820 for (int cnt = 0; cnt < nentries; ++cnt)
1821 {
1822 GElf_Rel relmem;
1823 GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
1824 if (likely (rel != NULL))
1825 {
1826 char buf[128];
1827 GElf_Sym symmem;
1828 Elf32_Word xndx;
1829 GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
1830 GELF_R_SYM (rel->r_info),
1831 &symmem, &xndx);
1832 if (unlikely (sym == NULL))
1833 {
1834 /* As a special case we have to handle relocations in static
1835 executables. This only happens for IRELATIVE relocations
1836 (so far). There is no symbol table. */
1837 if (is_statically_linked == 0)
1838 {
1839 /* Find the program header and look for a PT_INTERP entry. */
1840 is_statically_linked = -1;
1841 if (ehdr->e_type == ET_EXEC)
1842 {
1843 is_statically_linked = 1;
1844
1845 for (size_t inner = 0; inner < phnum; ++inner)
1846 {
1847 GElf_Phdr phdr_mem;
1848 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
1849 &phdr_mem);
1850 if (phdr != NULL && phdr->p_type == PT_INTERP)
1851 {
1852 is_statically_linked = -1;
1853 break;
1854 }
1855 }
1856 }
1857 }
1858
1859 if (is_statically_linked > 0 && shdr->sh_link == 0)
1860 printf ("\
1861 %#0*" PRIx64 " %-20s %*s %s\n",
1862 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1863 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1864 /* Avoid the leading R_ which isn't carrying any
1865 information. */
1866 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1867 buf, sizeof (buf)) + 2
1868 : gettext ("<INVALID RELOC>"),
1869 class == ELFCLASS32 ? 10 : 18, "",
1870 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1871 else
1872 printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
1873 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1874 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1875 /* Avoid the leading R_ which isn't carrying any
1876 information. */
1877 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1878 buf, sizeof (buf)) + 2
1879 : gettext ("<INVALID RELOC>"),
1880 gettext ("INVALID SYMBOL"),
1881 (long int) GELF_R_SYM (rel->r_info));
1882 }
1883 else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
1884 printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
1885 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1886 likely (ebl_reloc_type_check (ebl,
1887 GELF_R_TYPE (rel->r_info)))
1888 /* Avoid the leading R_ which isn't carrying any
1889 information. */
1890 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1891 buf, sizeof (buf)) + 2
1892 : gettext ("<INVALID RELOC>"),
1893 class == ELFCLASS32 ? 10 : 18, sym->st_value,
1894 elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
1895 else
1896 {
Elliott Hughes03333822015-02-18 22:19:45 -08001897 /* This is a relocation against a STT_SECTION symbol. */
1898 GElf_Shdr secshdr_mem;
1899 GElf_Shdr *secshdr;
1900 secshdr = gelf_getshdr (elf_getscn (ebl->elf,
1901 sym->st_shndx == SHN_XINDEX
1902 ? xndx : sym->st_shndx),
1903 &secshdr_mem);
Ben Cheng25b3c042013-11-20 14:45:36 -08001904
Elliott Hughes03333822015-02-18 22:19:45 -08001905 if (unlikely (secshdr == NULL))
Ben Cheng25b3c042013-11-20 14:45:36 -08001906 printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
1907 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1908 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1909 /* Avoid the leading R_ which isn't carrying any
1910 information. */
1911 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1912 buf, sizeof (buf)) + 2
1913 : gettext ("<INVALID RELOC>"),
1914 gettext ("INVALID SECTION"),
1915 (long int) (sym->st_shndx == SHN_XINDEX
1916 ? xndx : sym->st_shndx));
1917 else
1918 printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
1919 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1920 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1921 /* Avoid the leading R_ which isn't carrying any
1922 information. */
1923 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1924 buf, sizeof (buf)) + 2
1925 : gettext ("<INVALID RELOC>"),
1926 class == ELFCLASS32 ? 10 : 18, sym->st_value,
Elliott Hughes03333822015-02-18 22:19:45 -08001927 elf_strptr (ebl->elf, shstrndx, secshdr->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08001928 }
1929 }
1930 }
1931}
1932
1933
1934/* Handle a relocation section. */
1935static void
1936handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
1937{
1938 int class = gelf_getclass (ebl->elf);
Elliott Hughes03333822015-02-18 22:19:45 -08001939 size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT);
1940 int nentries = shdr->sh_size / sh_entsize;
Ben Cheng25b3c042013-11-20 14:45:36 -08001941
1942 /* Get the data of the section. */
1943 Elf_Data *data = elf_getdata (scn, NULL);
1944 if (data == NULL)
1945 return;
1946
1947 /* Get the symbol table information. */
1948 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1949 GElf_Shdr symshdr_mem;
1950 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1951 Elf_Data *symdata = elf_getdata (symscn, NULL);
1952
1953 /* Get the section header of the section the relocations are for. */
1954 GElf_Shdr destshdr_mem;
1955 GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1956 &destshdr_mem);
1957
1958 if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
1959 {
1960 printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1961 shdr->sh_offset);
1962 return;
1963 }
1964
1965 /* Search for the optional extended section index table. */
1966 Elf_Data *xndxdata = NULL;
1967 int xndxscnidx = elf_scnshndx (scn);
1968 if (unlikely (xndxscnidx > 0))
1969 xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
1970
1971 /* Get the section header string table index. */
1972 size_t shstrndx;
1973 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
1974 error (EXIT_FAILURE, 0,
1975 gettext ("cannot get section header string table index"));
1976
Elliott Hughes03333822015-02-18 22:19:45 -08001977 if (shdr->sh_info != 0)
1978 printf (ngettext ("\
Ben Cheng25b3c042013-11-20 14:45:36 -08001979\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1980 "\
1981\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1982 nentries),
1983 elf_ndxscn (scn),
1984 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1985 (unsigned int) shdr->sh_info,
1986 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1987 shdr->sh_offset,
1988 nentries);
Elliott Hughes03333822015-02-18 22:19:45 -08001989 else
1990 /* The .rela.dyn section does not refer to a specific section but
1991 instead of section index zero. Do not try to print a section
1992 name. */
1993 printf (ngettext ("\
1994\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1995 "\
1996\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1997 nentries),
1998 (unsigned int) elf_ndxscn (scn),
1999 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2000 shdr->sh_offset,
2001 nentries);
Ben Cheng25b3c042013-11-20 14:45:36 -08002002 fputs_unlocked (class == ELFCLASS32
2003 ? gettext ("\
2004 Offset Type Value Addend Name\n")
2005 : gettext ("\
2006 Offset Type Value Addend Name\n"),
2007 stdout);
2008
2009 int is_statically_linked = 0;
2010 for (int cnt = 0; cnt < nentries; ++cnt)
2011 {
2012 GElf_Rela relmem;
2013 GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
2014 if (likely (rel != NULL))
2015 {
2016 char buf[64];
2017 GElf_Sym symmem;
2018 Elf32_Word xndx;
2019 GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
2020 GELF_R_SYM (rel->r_info),
2021 &symmem, &xndx);
2022
2023 if (unlikely (sym == NULL))
2024 {
2025 /* As a special case we have to handle relocations in static
2026 executables. This only happens for IRELATIVE relocations
2027 (so far). There is no symbol table. */
2028 if (is_statically_linked == 0)
2029 {
2030 /* Find the program header and look for a PT_INTERP entry. */
2031 is_statically_linked = -1;
2032 if (ehdr->e_type == ET_EXEC)
2033 {
2034 is_statically_linked = 1;
2035
2036 for (size_t inner = 0; inner < phnum; ++inner)
2037 {
2038 GElf_Phdr phdr_mem;
2039 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
2040 &phdr_mem);
2041 if (phdr != NULL && phdr->p_type == PT_INTERP)
2042 {
2043 is_statically_linked = -1;
2044 break;
2045 }
2046 }
2047 }
2048 }
2049
2050 if (is_statically_linked > 0 && shdr->sh_link == 0)
2051 printf ("\
2052 %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " %s\n",
2053 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
2054 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
2055 /* Avoid the leading R_ which isn't carrying any
2056 information. */
2057 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
2058 buf, sizeof (buf)) + 2
2059 : gettext ("<INVALID RELOC>"),
2060 class == ELFCLASS32 ? 10 : 18, "",
2061 rel->r_addend,
2062 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
2063 else
2064 printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
2065 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
2066 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
2067 /* Avoid the leading R_ which isn't carrying any
2068 information. */
2069 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
2070 buf, sizeof (buf)) + 2
2071 : gettext ("<INVALID RELOC>"),
2072 gettext ("INVALID SYMBOL"),
2073 (long int) GELF_R_SYM (rel->r_info));
2074 }
2075 else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
2076 printf ("\
2077 %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
2078 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
2079 likely (ebl_reloc_type_check (ebl,
2080 GELF_R_TYPE (rel->r_info)))
2081 /* Avoid the leading R_ which isn't carrying any
2082 information. */
2083 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
2084 buf, sizeof (buf)) + 2
2085 : gettext ("<INVALID RELOC>"),
2086 class == ELFCLASS32 ? 10 : 18, sym->st_value,
2087 rel->r_addend,
2088 elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
2089 else
2090 {
Elliott Hughes03333822015-02-18 22:19:45 -08002091 /* This is a relocation against a STT_SECTION symbol. */
2092 GElf_Shdr secshdr_mem;
2093 GElf_Shdr *secshdr;
2094 secshdr = gelf_getshdr (elf_getscn (ebl->elf,
2095 sym->st_shndx == SHN_XINDEX
2096 ? xndx : sym->st_shndx),
2097 &secshdr_mem);
Ben Cheng25b3c042013-11-20 14:45:36 -08002098
Elliott Hughes03333822015-02-18 22:19:45 -08002099 if (unlikely (secshdr == NULL))
Ben Cheng25b3c042013-11-20 14:45:36 -08002100 printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
2101 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
2102 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
2103 /* Avoid the leading R_ which isn't carrying any
2104 information. */
2105 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
2106 buf, sizeof (buf)) + 2
2107 : gettext ("<INVALID RELOC>"),
2108 gettext ("INVALID SECTION"),
2109 (long int) (sym->st_shndx == SHN_XINDEX
2110 ? xndx : sym->st_shndx));
2111 else
2112 printf ("\
2113 %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
2114 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
2115 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
2116 /* Avoid the leading R_ which isn't carrying any
2117 information. */
2118 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
2119 buf, sizeof (buf)) + 2
2120 : gettext ("<INVALID RELOC>"),
2121 class == ELFCLASS32 ? 10 : 18, sym->st_value,
2122 rel->r_addend,
Elliott Hughes03333822015-02-18 22:19:45 -08002123 elf_strptr (ebl->elf, shstrndx, secshdr->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002124 }
2125 }
2126 }
2127}
2128
2129
2130/* Print the program header. */
2131static void
2132print_symtab (Ebl *ebl, int type)
2133{
2134 /* Find the symbol table(s). For this we have to search through the
2135 section table. */
2136 Elf_Scn *scn = NULL;
2137
2138 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2139 {
2140 /* Handle the section if it is a symbol table. */
2141 GElf_Shdr shdr_mem;
2142 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2143
2144 if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
2145 handle_symtab (ebl, scn, shdr);
2146 }
2147}
2148
2149
2150static void
2151handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2152{
2153 Elf_Data *versym_data = NULL;
2154 Elf_Data *verneed_data = NULL;
2155 Elf_Data *verdef_data = NULL;
2156 Elf_Data *xndx_data = NULL;
2157 int class = gelf_getclass (ebl->elf);
2158 Elf32_Word verneed_stridx = 0;
2159 Elf32_Word verdef_stridx = 0;
2160
2161 /* Get the data of the section. */
2162 Elf_Data *data = elf_getdata (scn, NULL);
2163 if (data == NULL)
2164 return;
2165
2166 /* Find out whether we have other sections we might need. */
2167 Elf_Scn *runscn = NULL;
2168 while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL)
2169 {
2170 GElf_Shdr runshdr_mem;
2171 GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
2172
2173 if (likely (runshdr != NULL))
2174 {
2175 if (runshdr->sh_type == SHT_GNU_versym
2176 && runshdr->sh_link == elf_ndxscn (scn))
2177 /* Bingo, found the version information. Now get the data. */
2178 versym_data = elf_getdata (runscn, NULL);
2179 else if (runshdr->sh_type == SHT_GNU_verneed)
2180 {
2181 /* This is the information about the needed versions. */
2182 verneed_data = elf_getdata (runscn, NULL);
2183 verneed_stridx = runshdr->sh_link;
2184 }
2185 else if (runshdr->sh_type == SHT_GNU_verdef)
2186 {
2187 /* This is the information about the defined versions. */
2188 verdef_data = elf_getdata (runscn, NULL);
2189 verdef_stridx = runshdr->sh_link;
2190 }
2191 else if (runshdr->sh_type == SHT_SYMTAB_SHNDX
2192 && runshdr->sh_link == elf_ndxscn (scn))
2193 /* Extended section index. */
2194 xndx_data = elf_getdata (runscn, NULL);
2195 }
2196 }
2197
2198 /* Get the section header string table index. */
2199 size_t shstrndx;
2200 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2201 error (EXIT_FAILURE, 0,
2202 gettext ("cannot get section header string table index"));
2203
Elliott Hughes03333822015-02-18 22:19:45 -08002204 GElf_Shdr glink_mem;
2205 GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2206 &glink_mem);
2207 if (glink == NULL)
2208 error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
2209 elf_ndxscn (scn));
2210
Ben Cheng25b3c042013-11-20 14:45:36 -08002211 /* Now we can compute the number of entries in the section. */
2212 unsigned int nsyms = data->d_size / (class == ELFCLASS32
2213 ? sizeof (Elf32_Sym)
2214 : sizeof (Elf64_Sym));
2215
2216 printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n",
2217 "\nSymbol table [%2u] '%s' contains %u entries:\n",
2218 nsyms),
2219 (unsigned int) elf_ndxscn (scn),
2220 elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms);
Ben Cheng25b3c042013-11-20 14:45:36 -08002221 printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n",
2222 " %lu local symbols String table: [%2u] '%s'\n",
2223 shdr->sh_info),
2224 (unsigned long int) shdr->sh_info,
2225 (unsigned int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08002226 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002227
2228 fputs_unlocked (class == ELFCLASS32
2229 ? gettext ("\
2230 Num: Value Size Type Bind Vis Ndx Name\n")
2231 : gettext ("\
2232 Num: Value Size Type Bind Vis Ndx Name\n"),
2233 stdout);
2234
2235 for (unsigned int cnt = 0; cnt < nsyms; ++cnt)
2236 {
2237 char typebuf[64];
2238 char bindbuf[64];
2239 char scnbuf[64];
2240 Elf32_Word xndx;
2241 GElf_Sym sym_mem;
2242 GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
2243
2244 if (unlikely (sym == NULL))
2245 continue;
2246
2247 /* Determine the real section index. */
2248 if (likely (sym->st_shndx != SHN_XINDEX))
2249 xndx = sym->st_shndx;
2250
2251 printf (gettext ("\
2252%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"),
2253 cnt,
2254 class == ELFCLASS32 ? 8 : 16,
2255 sym->st_value,
2256 sym->st_size,
2257 ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
2258 typebuf, sizeof (typebuf)),
2259 ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info),
2260 bindbuf, sizeof (bindbuf)),
2261 get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)),
2262 ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf,
2263 sizeof (scnbuf), NULL, shnum),
2264 elf_strptr (ebl->elf, shdr->sh_link, sym->st_name));
2265
2266 if (versym_data != NULL)
2267 {
2268 /* Get the version information. */
2269 GElf_Versym versym_mem;
2270 GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem);
2271
2272 if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1))
2273 {
2274 bool is_nobits = false;
2275 bool check_def = xndx != SHN_UNDEF;
2276
2277 if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX)
2278 {
2279 GElf_Shdr symshdr_mem;
2280 GElf_Shdr *symshdr =
2281 gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem);
2282
2283 is_nobits = (symshdr != NULL
2284 && symshdr->sh_type == SHT_NOBITS);
2285 }
2286
2287 if (is_nobits || ! check_def)
2288 {
2289 /* We must test both. */
2290 GElf_Vernaux vernaux_mem;
2291 GElf_Vernaux *vernaux = NULL;
2292 size_t vn_offset = 0;
2293
2294 GElf_Verneed verneed_mem;
2295 GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0,
2296 &verneed_mem);
2297 while (verneed != NULL)
2298 {
2299 size_t vna_offset = vn_offset;
2300
2301 vernaux = gelf_getvernaux (verneed_data,
2302 vna_offset += verneed->vn_aux,
2303 &vernaux_mem);
2304 while (vernaux != NULL
2305 && vernaux->vna_other != *versym
2306 && vernaux->vna_next != 0)
2307 {
2308 /* Update the offset. */
2309 vna_offset += vernaux->vna_next;
2310
2311 vernaux = (vernaux->vna_next == 0
2312 ? NULL
2313 : gelf_getvernaux (verneed_data,
2314 vna_offset,
2315 &vernaux_mem));
2316 }
2317
2318 /* Check whether we found the version. */
2319 if (vernaux != NULL && vernaux->vna_other == *versym)
2320 /* Found it. */
2321 break;
2322
2323 vn_offset += verneed->vn_next;
2324 verneed = (verneed->vn_next == 0
2325 ? NULL
2326 : gelf_getverneed (verneed_data, vn_offset,
2327 &verneed_mem));
2328 }
2329
2330 if (vernaux != NULL && vernaux->vna_other == *versym)
2331 {
2332 printf ("@%s (%u)",
2333 elf_strptr (ebl->elf, verneed_stridx,
2334 vernaux->vna_name),
2335 (unsigned int) vernaux->vna_other);
2336 check_def = 0;
2337 }
2338 else if (unlikely (! is_nobits))
2339 error (0, 0, gettext ("bad dynamic symbol"));
2340 else
2341 check_def = 1;
2342 }
2343
2344 if (check_def && *versym != 0x8001)
2345 {
2346 /* We must test both. */
2347 size_t vd_offset = 0;
2348
2349 GElf_Verdef verdef_mem;
2350 GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0,
2351 &verdef_mem);
2352 while (verdef != NULL)
2353 {
2354 if (verdef->vd_ndx == (*versym & 0x7fff))
2355 /* Found the definition. */
2356 break;
2357
2358 vd_offset += verdef->vd_next;
2359 verdef = (verdef->vd_next == 0
2360 ? NULL
2361 : gelf_getverdef (verdef_data, vd_offset,
2362 &verdef_mem));
2363 }
2364
2365 if (verdef != NULL)
2366 {
2367 GElf_Verdaux verdaux_mem;
2368 GElf_Verdaux *verdaux
2369 = gelf_getverdaux (verdef_data,
2370 vd_offset + verdef->vd_aux,
2371 &verdaux_mem);
2372
2373 if (verdaux != NULL)
2374 printf ((*versym & 0x8000) ? "@%s" : "@@%s",
2375 elf_strptr (ebl->elf, verdef_stridx,
2376 verdaux->vda_name));
2377 }
2378 }
2379 }
2380 }
2381
2382 putchar_unlocked ('\n');
2383 }
2384}
2385
2386
2387/* Print version information. */
2388static void
2389print_verinfo (Ebl *ebl)
2390{
2391 /* Find the version information sections. For this we have to
2392 search through the section table. */
2393 Elf_Scn *scn = NULL;
2394
2395 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2396 {
2397 /* Handle the section if it is part of the versioning handling. */
2398 GElf_Shdr shdr_mem;
2399 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2400
2401 if (likely (shdr != NULL))
2402 {
2403 if (shdr->sh_type == SHT_GNU_verneed)
2404 handle_verneed (ebl, scn, shdr);
2405 else if (shdr->sh_type == SHT_GNU_verdef)
2406 handle_verdef (ebl, scn, shdr);
2407 else if (shdr->sh_type == SHT_GNU_versym)
2408 handle_versym (ebl, scn, shdr);
2409 }
2410 }
2411}
2412
2413
2414static const char *
2415get_ver_flags (unsigned int flags)
2416{
2417 static char buf[32];
2418 char *endp;
2419
2420 if (flags == 0)
2421 return gettext ("none");
2422
2423 if (flags & VER_FLG_BASE)
2424 endp = stpcpy (buf, "BASE ");
2425 else
2426 endp = buf;
2427
2428 if (flags & VER_FLG_WEAK)
2429 {
2430 if (endp != buf)
2431 endp = stpcpy (endp, "| ");
2432
2433 endp = stpcpy (endp, "WEAK ");
2434 }
2435
2436 if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
2437 {
2438 strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
2439 buf[sizeof (buf) - 1] = '\0';
2440 }
2441
2442 return buf;
2443}
2444
2445
2446static void
2447handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2448{
2449 int class = gelf_getclass (ebl->elf);
2450
2451 /* Get the data of the section. */
2452 Elf_Data *data = elf_getdata (scn, NULL);
2453 if (data == NULL)
2454 return;
2455
2456 /* Get the section header string table index. */
2457 size_t shstrndx;
2458 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2459 error (EXIT_FAILURE, 0,
2460 gettext ("cannot get section header string table index"));
2461
Elliott Hughes03333822015-02-18 22:19:45 -08002462 GElf_Shdr glink_mem;
2463 GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2464 &glink_mem);
2465 if (glink == NULL)
2466 error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
2467 elf_ndxscn (scn));
2468
Ben Cheng25b3c042013-11-20 14:45:36 -08002469 printf (ngettext ("\
2470\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2471 "\
2472\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2473 shdr->sh_info),
2474 (unsigned int) elf_ndxscn (scn),
2475 elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info,
2476 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2477 shdr->sh_offset,
2478 (unsigned int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08002479 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002480
2481 unsigned int offset = 0;
2482 for (int cnt = shdr->sh_info; --cnt >= 0; )
2483 {
2484 /* Get the data at the next offset. */
2485 GElf_Verneed needmem;
2486 GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
2487 if (unlikely (need == NULL))
2488 break;
2489
2490 printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"),
2491 offset, (unsigned short int) need->vn_version,
2492 elf_strptr (ebl->elf, shdr->sh_link, need->vn_file),
2493 (unsigned short int) need->vn_cnt);
2494
2495 unsigned int auxoffset = offset + need->vn_aux;
2496 for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
2497 {
2498 GElf_Vernaux auxmem;
2499 GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
2500 if (unlikely (aux == NULL))
2501 break;
2502
2503 printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"),
2504 auxoffset,
2505 elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name),
2506 get_ver_flags (aux->vna_flags),
2507 (unsigned short int) aux->vna_other);
2508
Elliott Hughes03333822015-02-18 22:19:45 -08002509 if (aux->vna_next == 0)
2510 break;
2511
Ben Cheng25b3c042013-11-20 14:45:36 -08002512 auxoffset += aux->vna_next;
2513 }
2514
2515 /* Find the next offset. */
Elliott Hughes03333822015-02-18 22:19:45 -08002516 if (need->vn_next == 0)
2517 break;
2518
Ben Cheng25b3c042013-11-20 14:45:36 -08002519 offset += need->vn_next;
2520 }
2521}
2522
2523
2524static void
2525handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2526{
2527 /* Get the data of the section. */
2528 Elf_Data *data = elf_getdata (scn, NULL);
2529 if (data == NULL)
2530 return;
2531
2532 /* Get the section header string table index. */
2533 size_t shstrndx;
2534 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2535 error (EXIT_FAILURE, 0,
2536 gettext ("cannot get section header string table index"));
2537
Elliott Hughes03333822015-02-18 22:19:45 -08002538 GElf_Shdr glink_mem;
2539 GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2540 &glink_mem);
2541 if (glink == NULL)
2542 error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
2543 elf_ndxscn (scn));
2544
Ben Cheng25b3c042013-11-20 14:45:36 -08002545 int class = gelf_getclass (ebl->elf);
Ben Cheng25b3c042013-11-20 14:45:36 -08002546 printf (ngettext ("\
2547\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2548 "\
2549\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2550 shdr->sh_info),
2551 (unsigned int) elf_ndxscn (scn),
2552 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2553 shdr->sh_info,
2554 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2555 shdr->sh_offset,
2556 (unsigned int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08002557 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002558
2559 unsigned int offset = 0;
2560 for (int cnt = shdr->sh_info; --cnt >= 0; )
2561 {
2562 /* Get the data at the next offset. */
2563 GElf_Verdef defmem;
2564 GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
2565 if (unlikely (def == NULL))
2566 break;
2567
2568 unsigned int auxoffset = offset + def->vd_aux;
2569 GElf_Verdaux auxmem;
2570 GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
2571 if (unlikely (aux == NULL))
2572 break;
2573
2574 printf (gettext ("\
2575 %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"),
2576 offset, def->vd_version,
2577 get_ver_flags (def->vd_flags),
2578 def->vd_ndx,
2579 def->vd_cnt,
2580 elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2581
2582 auxoffset += aux->vda_next;
2583 for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
2584 {
2585 aux = gelf_getverdaux (data, auxoffset, &auxmem);
2586 if (unlikely (aux == NULL))
2587 break;
2588
2589 printf (gettext (" %#06x: Parent %d: %s\n"),
2590 auxoffset, cnt2,
2591 elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2592
Elliott Hughes03333822015-02-18 22:19:45 -08002593 if (aux->vda_next == 0)
2594 break;
2595
Ben Cheng25b3c042013-11-20 14:45:36 -08002596 auxoffset += aux->vda_next;
2597 }
2598
2599 /* Find the next offset. */
Elliott Hughes03333822015-02-18 22:19:45 -08002600 if (def->vd_next == 0)
2601 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002602 offset += def->vd_next;
2603 }
2604}
2605
2606
2607static void
2608handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2609{
2610 int class = gelf_getclass (ebl->elf);
2611 const char **vername;
2612 const char **filename;
2613
2614 /* Get the data of the section. */
2615 Elf_Data *data = elf_getdata (scn, NULL);
2616 if (data == NULL)
2617 return;
2618
2619 /* Get the section header string table index. */
2620 size_t shstrndx;
2621 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
2622 error (EXIT_FAILURE, 0,
2623 gettext ("cannot get section header string table index"));
2624
2625 /* We have to find the version definition section and extract the
2626 version names. */
2627 Elf_Scn *defscn = NULL;
2628 Elf_Scn *needscn = NULL;
2629
2630 Elf_Scn *verscn = NULL;
2631 while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL)
2632 {
2633 GElf_Shdr vershdr_mem;
2634 GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
2635
2636 if (likely (vershdr != NULL))
2637 {
2638 if (vershdr->sh_type == SHT_GNU_verdef)
2639 defscn = verscn;
2640 else if (vershdr->sh_type == SHT_GNU_verneed)
2641 needscn = verscn;
2642 }
2643 }
2644
2645 size_t nvername;
2646 if (defscn != NULL || needscn != NULL)
2647 {
2648 /* We have a version information (better should have). Now get
2649 the version names. First find the maximum version number. */
2650 nvername = 0;
2651 if (defscn != NULL)
2652 {
2653 /* Run through the version definitions and find the highest
2654 index. */
2655 unsigned int offset = 0;
2656 Elf_Data *defdata;
2657 GElf_Shdr defshdrmem;
2658 GElf_Shdr *defshdr;
2659
2660 defdata = elf_getdata (defscn, NULL);
2661 if (unlikely (defdata == NULL))
2662 return;
2663
2664 defshdr = gelf_getshdr (defscn, &defshdrmem);
2665 if (unlikely (defshdr == NULL))
2666 return;
2667
2668 for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
2669 {
2670 GElf_Verdef defmem;
2671 GElf_Verdef *def;
2672
2673 /* Get the data at the next offset. */
2674 def = gelf_getverdef (defdata, offset, &defmem);
2675 if (unlikely (def == NULL))
2676 break;
2677
2678 nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
2679
Elliott Hughes03333822015-02-18 22:19:45 -08002680 if (def->vd_next == 0)
2681 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002682 offset += def->vd_next;
2683 }
2684 }
2685 if (needscn != NULL)
2686 {
2687 unsigned int offset = 0;
2688 Elf_Data *needdata;
2689 GElf_Shdr needshdrmem;
2690 GElf_Shdr *needshdr;
2691
2692 needdata = elf_getdata (needscn, NULL);
2693 if (unlikely (needdata == NULL))
2694 return;
2695
2696 needshdr = gelf_getshdr (needscn, &needshdrmem);
2697 if (unlikely (needshdr == NULL))
2698 return;
2699
2700 for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
2701 {
2702 GElf_Verneed needmem;
2703 GElf_Verneed *need;
2704 unsigned int auxoffset;
2705 int cnt2;
2706
2707 /* Get the data at the next offset. */
2708 need = gelf_getverneed (needdata, offset, &needmem);
2709 if (unlikely (need == NULL))
2710 break;
2711
2712 /* Run through the auxiliary entries. */
2713 auxoffset = offset + need->vn_aux;
2714 for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
2715 {
2716 GElf_Vernaux auxmem;
2717 GElf_Vernaux *aux;
2718
2719 aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
2720 if (unlikely (aux == NULL))
2721 break;
2722
2723 nvername = MAX (nvername,
2724 (size_t) (aux->vna_other & 0x7fff));
2725
Elliott Hughes03333822015-02-18 22:19:45 -08002726 if (aux->vna_next == 0)
2727 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002728 auxoffset += aux->vna_next;
2729 }
2730
Elliott Hughes03333822015-02-18 22:19:45 -08002731 if (need->vn_next == 0)
2732 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002733 offset += need->vn_next;
2734 }
2735 }
2736
2737 /* This is the number of versions we know about. */
2738 ++nvername;
2739
2740 /* Allocate the array. */
2741 vername = (const char **) alloca (nvername * sizeof (const char *));
Elliott Hughes03333822015-02-18 22:19:45 -08002742 memset(vername, 0, nvername * sizeof (const char *));
Ben Cheng25b3c042013-11-20 14:45:36 -08002743 filename = (const char **) alloca (nvername * sizeof (const char *));
Elliott Hughes03333822015-02-18 22:19:45 -08002744 memset(filename, 0, nvername * sizeof (const char *));
Ben Cheng25b3c042013-11-20 14:45:36 -08002745
2746 /* Run through the data structures again and collect the strings. */
2747 if (defscn != NULL)
2748 {
2749 /* Run through the version definitions and find the highest
2750 index. */
2751 unsigned int offset = 0;
2752 Elf_Data *defdata;
2753 GElf_Shdr defshdrmem;
2754 GElf_Shdr *defshdr;
2755
2756 defdata = elf_getdata (defscn, NULL);
2757 if (unlikely (defdata == NULL))
2758 return;
2759
2760 defshdr = gelf_getshdr (defscn, &defshdrmem);
2761 if (unlikely (defshdr == NULL))
2762 return;
2763
2764 for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
2765 {
2766
2767 /* Get the data at the next offset. */
2768 GElf_Verdef defmem;
2769 GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
Elliott Hughes03333822015-02-18 22:19:45 -08002770 if (unlikely (def == NULL))
2771 break;
2772
Ben Cheng25b3c042013-11-20 14:45:36 -08002773 GElf_Verdaux auxmem;
2774 GElf_Verdaux *aux = gelf_getverdaux (defdata,
2775 offset + def->vd_aux,
2776 &auxmem);
Elliott Hughes03333822015-02-18 22:19:45 -08002777 if (unlikely (aux == NULL))
Ben Cheng25b3c042013-11-20 14:45:36 -08002778 break;
2779
2780 vername[def->vd_ndx & 0x7fff]
2781 = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name);
2782 filename[def->vd_ndx & 0x7fff] = NULL;
2783
Elliott Hughes03333822015-02-18 22:19:45 -08002784 if (def->vd_next == 0)
2785 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002786 offset += def->vd_next;
2787 }
2788 }
2789 if (needscn != NULL)
2790 {
2791 unsigned int offset = 0;
2792
2793 Elf_Data *needdata = elf_getdata (needscn, NULL);
2794 GElf_Shdr needshdrmem;
2795 GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
2796 if (unlikely (needdata == NULL || needshdr == NULL))
2797 return;
2798
2799 for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
2800 {
2801 /* Get the data at the next offset. */
2802 GElf_Verneed needmem;
2803 GElf_Verneed *need = gelf_getverneed (needdata, offset,
2804 &needmem);
2805 if (unlikely (need == NULL))
2806 break;
2807
2808 /* Run through the auxiliary entries. */
2809 unsigned int auxoffset = offset + need->vn_aux;
2810 for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
2811 {
2812 GElf_Vernaux auxmem;
2813 GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
2814 &auxmem);
2815 if (unlikely (aux == NULL))
2816 break;
2817
2818 vername[aux->vna_other & 0x7fff]
2819 = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name);
2820 filename[aux->vna_other & 0x7fff]
2821 = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file);
2822
Elliott Hughes03333822015-02-18 22:19:45 -08002823 if (aux->vna_next == 0)
2824 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002825 auxoffset += aux->vna_next;
2826 }
2827
Elliott Hughes03333822015-02-18 22:19:45 -08002828 if (need->vn_next == 0)
2829 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08002830 offset += need->vn_next;
2831 }
2832 }
2833 }
2834 else
2835 {
2836 vername = NULL;
2837 nvername = 1;
2838 filename = NULL;
2839 }
2840
Elliott Hughes03333822015-02-18 22:19:45 -08002841 GElf_Shdr glink_mem;
2842 GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2843 &glink_mem);
2844 size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_HALF, 1, EV_CURRENT);
2845 if (glink == NULL)
2846 error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %Zu"),
2847 elf_ndxscn (scn));
2848
Ben Cheng25b3c042013-11-20 14:45:36 -08002849 /* Print the header. */
Ben Cheng25b3c042013-11-20 14:45:36 -08002850 printf (ngettext ("\
2851\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
2852 "\
2853\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
Elliott Hughes03333822015-02-18 22:19:45 -08002854 shdr->sh_size / sh_entsize),
Ben Cheng25b3c042013-11-20 14:45:36 -08002855 (unsigned int) elf_ndxscn (scn),
2856 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
Elliott Hughes03333822015-02-18 22:19:45 -08002857 (int) (shdr->sh_size / sh_entsize),
Ben Cheng25b3c042013-11-20 14:45:36 -08002858 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2859 shdr->sh_offset,
2860 (unsigned int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08002861 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002862
2863 /* Now we can finally look at the actual contents of this section. */
Elliott Hughes03333822015-02-18 22:19:45 -08002864 for (unsigned int cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt)
Ben Cheng25b3c042013-11-20 14:45:36 -08002865 {
2866 if (cnt % 2 == 0)
2867 printf ("\n %4d:", cnt);
2868
2869 GElf_Versym symmem;
2870 GElf_Versym *sym = gelf_getversym (data, cnt, &symmem);
2871 if (sym == NULL)
2872 break;
2873
2874 switch (*sym)
2875 {
2876 ssize_t n;
2877 case 0:
2878 fputs_unlocked (gettext (" 0 *local* "),
2879 stdout);
2880 break;
2881
2882 case 1:
2883 fputs_unlocked (gettext (" 1 *global* "),
2884 stdout);
2885 break;
2886
2887 default:
2888 n = printf ("%4d%c%s",
2889 *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ',
Elliott Hughes03333822015-02-18 22:19:45 -08002890 (vername != NULL
2891 && (unsigned int) (*sym & 0x7fff) < nvername)
Ben Cheng25b3c042013-11-20 14:45:36 -08002892 ? vername[*sym & 0x7fff] : "???");
2893 if ((unsigned int) (*sym & 0x7fff) < nvername
Elliott Hughes03333822015-02-18 22:19:45 -08002894 && filename != NULL && filename[*sym & 0x7fff] != NULL)
Ben Cheng25b3c042013-11-20 14:45:36 -08002895 n += printf ("(%s)", filename[*sym & 0x7fff]);
2896 printf ("%*s", MAX (0, 33 - (int) n), " ");
2897 break;
2898 }
2899 }
2900 putchar_unlocked ('\n');
2901}
2902
2903
2904static void
2905print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
2906 uint_fast32_t maxlength, Elf32_Word nbucket,
2907 uint_fast32_t nsyms, uint32_t *lengths, const char *extrastr)
2908{
2909 uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
2910
2911 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2912 ++counts[lengths[cnt]];
2913
Elliott Hughes03333822015-02-18 22:19:45 -08002914 GElf_Shdr glink_mem;
2915 GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf,
2916 shdr->sh_link),
2917 &glink_mem);
2918 if (glink == NULL)
2919 {
2920 error (0, 0, gettext ("invalid sh_link value in section %Zu"),
2921 elf_ndxscn (scn));
2922 return;
2923 }
2924
Ben Cheng25b3c042013-11-20 14:45:36 -08002925 printf (ngettext ("\
2926\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",
2927 "\
2928\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",
2929 nbucket),
2930 (unsigned int) elf_ndxscn (scn),
2931 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2932 (int) nbucket,
2933 gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
2934 shdr->sh_addr,
2935 shdr->sh_offset,
2936 (unsigned int) shdr->sh_link,
Elliott Hughes03333822015-02-18 22:19:45 -08002937 elf_strptr (ebl->elf, shstrndx, glink->sh_name));
Ben Cheng25b3c042013-11-20 14:45:36 -08002938
2939 if (extrastr != NULL)
2940 fputs (extrastr, stdout);
2941
2942 if (likely (nbucket > 0))
2943 {
2944 uint64_t success = 0;
2945
2946 /* xgettext:no-c-format */
2947 fputs_unlocked (gettext ("\
2948 Length Number % of total Coverage\n"), stdout);
2949 printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
2950 counts[0], (counts[0] * 100.0) / nbucket);
2951
2952 uint64_t nzero_counts = 0;
2953 for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2954 {
2955 nzero_counts += counts[cnt] * cnt;
2956 printf (gettext ("\
2957%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
2958 (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
2959 (nzero_counts * 100.0) / nsyms);
2960 }
2961
2962 Elf32_Word acc = 0;
2963 for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2964 {
2965 acc += cnt;
2966 success += counts[cnt] * acc;
2967 }
2968
2969 printf (gettext ("\
2970 Average number of tests: successful lookup: %f\n\
2971 unsuccessful lookup: %f\n"),
2972 (double) success / (double) nzero_counts,
2973 (double) nzero_counts / (double) nbucket);
2974 }
2975
2976 free (counts);
2977}
2978
2979
2980/* This function handles the traditional System V-style hash table format. */
2981static void
2982handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2983{
2984 Elf_Data *data = elf_getdata (scn, NULL);
2985 if (unlikely (data == NULL))
2986 {
2987 error (0, 0, gettext ("cannot get data for section %d: %s"),
2988 (int) elf_ndxscn (scn), elf_errmsg (-1));
2989 return;
2990 }
2991
Elliott Hughes03333822015-02-18 22:19:45 -08002992 if (unlikely (data->d_size < 2 * sizeof (Elf32_Word)))
2993 {
2994 invalid_data:
2995 error (0, 0, gettext ("invalid data in sysv.hash section %d"),
2996 (int) elf_ndxscn (scn));
2997 return;
2998 }
2999
Ben Cheng25b3c042013-11-20 14:45:36 -08003000 Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
3001 Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
Elliott Hughes03333822015-02-18 22:19:45 -08003002
3003 uint64_t used_buf = (2ULL + nchain + nbucket) * sizeof (Elf32_Word);
3004 if (used_buf > data->d_size)
3005 goto invalid_data;
3006
Ben Cheng25b3c042013-11-20 14:45:36 -08003007 Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
3008 Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
3009
3010 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
3011
3012 uint_fast32_t maxlength = 0;
3013 uint_fast32_t nsyms = 0;
3014 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
3015 {
3016 Elf32_Word inner = bucket[cnt];
3017 while (inner > 0 && inner < nchain)
3018 {
3019 ++nsyms;
3020 if (maxlength < ++lengths[cnt])
3021 ++maxlength;
3022
3023 inner = chain[inner];
3024 }
3025 }
3026
3027 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
3028 lengths, NULL);
3029
3030 free (lengths);
3031}
3032
3033
3034/* This function handles the incorrect, System V-style hash table
3035 format some 64-bit architectures use. */
3036static void
3037handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
3038{
3039 Elf_Data *data = elf_getdata (scn, NULL);
3040 if (unlikely (data == NULL))
3041 {
3042 error (0, 0, gettext ("cannot get data for section %d: %s"),
3043 (int) elf_ndxscn (scn), elf_errmsg (-1));
3044 return;
3045 }
3046
Elliott Hughes03333822015-02-18 22:19:45 -08003047 if (unlikely (data->d_size < 2 * sizeof (Elf64_Xword)))
3048 {
3049 invalid_data:
3050 error (0, 0, gettext ("invalid data in sysv.hash64 section %d"),
3051 (int) elf_ndxscn (scn));
3052 return;
3053 }
3054
Ben Cheng25b3c042013-11-20 14:45:36 -08003055 Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
3056 Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
Elliott Hughes03333822015-02-18 22:19:45 -08003057
3058 uint64_t maxwords = data->d_size / sizeof (Elf64_Xword);
3059 if (maxwords < 2
3060 || maxwords - 2 < nbucket
3061 || maxwords - 2 - nbucket < nchain)
3062 goto invalid_data;
3063
Ben Cheng25b3c042013-11-20 14:45:36 -08003064 Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
3065 Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
3066
3067 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
3068
3069 uint_fast32_t maxlength = 0;
3070 uint_fast32_t nsyms = 0;
3071 for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
3072 {
3073 Elf64_Xword inner = bucket[cnt];
3074 while (inner > 0 && inner < nchain)
3075 {
3076 ++nsyms;
3077 if (maxlength < ++lengths[cnt])
3078 ++maxlength;
3079
3080 inner = chain[inner];
3081 }
3082 }
3083
3084 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
3085 lengths, NULL);
3086
3087 free (lengths);
3088}
3089
3090
3091/* This function handles the GNU-style hash table format. */
3092static void
3093handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
3094{
3095 Elf_Data *data = elf_getdata (scn, NULL);
3096 if (unlikely (data == NULL))
3097 {
3098 error (0, 0, gettext ("cannot get data for section %d: %s"),
3099 (int) elf_ndxscn (scn), elf_errmsg (-1));
3100 return;
3101 }
3102
Elliott Hughes03333822015-02-18 22:19:45 -08003103 if (unlikely (data->d_size < 4 * sizeof (Elf32_Word)))
3104 {
3105 invalid_data:
3106 error (0, 0, gettext ("invalid data in gnu.hash section %d"),
3107 (int) elf_ndxscn (scn));
3108 return;
3109 }
3110
Ben Cheng25b3c042013-11-20 14:45:36 -08003111 Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
3112 Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
3113
3114 /* Next comes the size of the bitmap. It's measured in words for
3115 the architecture. It's 32 bits for 32 bit archs, and 64 bits for
Elliott Hughes03333822015-02-18 22:19:45 -08003116 64 bit archs. There is always a bloom filter present, so zero is
3117 an invalid value. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003118 Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
3119 if (gelf_getclass (ebl->elf) == ELFCLASS64)
3120 bitmask_words *= 2;
3121
Elliott Hughes03333822015-02-18 22:19:45 -08003122 if (bitmask_words == 0)
3123 goto invalid_data;
3124
Ben Cheng25b3c042013-11-20 14:45:36 -08003125 Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
3126
Elliott Hughes03333822015-02-18 22:19:45 -08003127 /* Is there still room for the sym chain?
3128 Use uint64_t calculation to prevent 32bit overlow. */
3129 uint64_t used_buf = (4ULL + bitmask_words + nbucket) * sizeof (Elf32_Word);
3130 uint32_t max_nsyms = (data->d_size - used_buf) / sizeof (Elf32_Word);
3131 if (used_buf > data->d_size)
3132 goto invalid_data;
3133
Ben Cheng25b3c042013-11-20 14:45:36 -08003134 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
3135
3136 Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
3137 Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
3138 Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[4 + bitmask_words
3139 + nbucket];
3140
3141 /* Compute distribution of chain lengths. */
3142 uint_fast32_t maxlength = 0;
3143 uint_fast32_t nsyms = 0;
3144 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
3145 if (bucket[cnt] != 0)
3146 {
3147 Elf32_Word inner = bucket[cnt] - symbias;
3148 do
3149 {
3150 ++nsyms;
3151 if (maxlength < ++lengths[cnt])
3152 ++maxlength;
Elliott Hughes03333822015-02-18 22:19:45 -08003153 if (inner > max_nsyms)
3154 goto invalid_data;
Ben Cheng25b3c042013-11-20 14:45:36 -08003155 }
3156 while ((chain[inner++] & 1) == 0);
3157 }
3158
3159 /* Count bits in bitmask. */
3160 uint_fast32_t nbits = 0;
3161 for (Elf32_Word cnt = 0; cnt < bitmask_words; ++cnt)
3162 {
3163 uint_fast32_t word = bitmask[cnt];
3164
3165 word = (word & 0x55555555) + ((word >> 1) & 0x55555555);
3166 word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
3167 word = (word & 0x0f0f0f0f) + ((word >> 4) & 0x0f0f0f0f);
3168 word = (word & 0x00ff00ff) + ((word >> 8) & 0x00ff00ff);
3169 nbits += (word & 0x0000ffff) + ((word >> 16) & 0x0000ffff);
3170 }
3171
3172 char *str;
3173 if (unlikely (asprintf (&str, gettext ("\
3174 Symbol Bias: %u\n\
3175 Bitmask Size: %zu bytes %" PRIuFAST32 "%% bits set 2nd hash shift: %u\n"),
3176 (unsigned int) symbias,
3177 bitmask_words * sizeof (Elf32_Word),
3178 ((nbits * 100 + 50)
3179 / (uint_fast32_t) (bitmask_words
3180 * sizeof (Elf32_Word) * 8)),
3181 (unsigned int) shift) == -1))
3182 error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
3183
3184 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
3185 lengths, str);
3186
3187 free (str);
3188 free (lengths);
3189}
3190
3191
3192/* Find the symbol table(s). For this we have to search through the
3193 section table. */
3194static void
3195handle_hash (Ebl *ebl)
3196{
3197 /* Get the section header string table index. */
3198 size_t shstrndx;
3199 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
3200 error (EXIT_FAILURE, 0,
3201 gettext ("cannot get section header string table index"));
3202
3203 Elf_Scn *scn = NULL;
3204 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
3205 {
3206 /* Handle the section if it is a symbol table. */
3207 GElf_Shdr shdr_mem;
3208 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
3209
3210 if (likely (shdr != NULL))
3211 {
3212 if (shdr->sh_type == SHT_HASH)
3213 {
3214 if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
3215 handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
3216 else
3217 handle_sysv_hash (ebl, scn, shdr, shstrndx);
3218 }
3219 else if (shdr->sh_type == SHT_GNU_HASH)
3220 handle_gnu_hash (ebl, scn, shdr, shstrndx);
3221 }
3222 }
3223}
3224
3225
3226static void
3227print_liblist (Ebl *ebl)
3228{
3229 /* Find the library list sections. For this we have to search
3230 through the section table. */
3231 Elf_Scn *scn = NULL;
3232
3233 /* Get the section header string table index. */
3234 size_t shstrndx;
3235 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
3236 error (EXIT_FAILURE, 0,
3237 gettext ("cannot get section header string table index"));
3238
3239 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
3240 {
3241 GElf_Shdr shdr_mem;
3242 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
3243
3244 if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST)
3245 {
Elliott Hughes03333822015-02-18 22:19:45 -08003246 size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_LIB, 1, EV_CURRENT);
3247 int nentries = shdr->sh_size / sh_entsize;
Ben Cheng25b3c042013-11-20 14:45:36 -08003248 printf (ngettext ("\
3249\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
3250 "\
3251\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
3252 nentries),
3253 elf_ndxscn (scn),
3254 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
3255 shdr->sh_offset,
3256 nentries);
3257
3258 Elf_Data *data = elf_getdata (scn, NULL);
3259 if (data == NULL)
3260 return;
3261
3262 puts (gettext ("\
3263 Library Time Stamp Checksum Version Flags"));
3264
3265 for (int cnt = 0; cnt < nentries; ++cnt)
3266 {
3267 GElf_Lib lib_mem;
3268 GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
3269 if (unlikely (lib == NULL))
3270 continue;
3271
3272 time_t t = (time_t) lib->l_time_stamp;
3273 struct tm *tm = gmtime (&t);
3274 if (unlikely (tm == NULL))
3275 continue;
3276
3277 printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
3278 cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name),
3279 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
3280 tm->tm_hour, tm->tm_min, tm->tm_sec,
3281 (unsigned int) lib->l_checksum,
3282 (unsigned int) lib->l_version,
3283 (unsigned int) lib->l_flags);
3284 }
3285 }
3286 }
3287}
3288
3289static void
3290print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
3291{
3292 /* Find the object attributes sections. For this we have to search
3293 through the section table. */
3294 Elf_Scn *scn = NULL;
3295
3296 /* Get the section header string table index. */
3297 size_t shstrndx;
3298 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
3299 error (EXIT_FAILURE, 0,
3300 gettext ("cannot get section header string table index"));
3301
3302 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
3303 {
3304 GElf_Shdr shdr_mem;
3305 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
3306
3307 if (shdr == NULL || (shdr->sh_type != SHT_GNU_ATTRIBUTES
3308 && (shdr->sh_type != SHT_ARM_ATTRIBUTES
3309 || ehdr->e_machine != EM_ARM)))
3310 continue;
3311
3312 printf (gettext ("\
3313\nObject attributes section [%2zu] '%s' of %" PRIu64
3314 " bytes at offset %#0" PRIx64 ":\n"),
3315 elf_ndxscn (scn),
3316 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
3317 shdr->sh_size, shdr->sh_offset);
3318
3319 Elf_Data *data = elf_rawdata (scn, NULL);
Elliott Hughes03333822015-02-18 22:19:45 -08003320 if (unlikely (data == NULL || data->d_size == 0))
Ben Cheng25b3c042013-11-20 14:45:36 -08003321 return;
3322
3323 const unsigned char *p = data->d_buf;
3324
Elliott Hughes03333822015-02-18 22:19:45 -08003325 /* There is only one 'version', A. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003326 if (unlikely (*p++ != 'A'))
3327 return;
3328
3329 fputs_unlocked (gettext (" Owner Size\n"), stdout);
3330
3331 inline size_t left (void)
3332 {
3333 return (const unsigned char *) data->d_buf + data->d_size - p;
3334 }
3335
Elliott Hughes03333822015-02-18 22:19:45 -08003336 /* Loop over the sections. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003337 while (left () >= 4)
3338 {
Elliott Hughes03333822015-02-18 22:19:45 -08003339 /* Section length. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003340 uint32_t len;
3341 memcpy (&len, p, sizeof len);
3342
3343 if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3344 CONVERT (len);
3345
3346 if (unlikely (len > left ()))
3347 break;
3348
Elliott Hughes03333822015-02-18 22:19:45 -08003349 /* Section vendor name. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003350 const unsigned char *name = p + sizeof len;
3351 p += len;
3352
3353 unsigned const char *q = memchr (name, '\0', len);
3354 if (unlikely (q == NULL))
Elliott Hughes03333822015-02-18 22:19:45 -08003355 break;
Ben Cheng25b3c042013-11-20 14:45:36 -08003356 ++q;
3357
3358 printf (gettext (" %-13s %4" PRIu32 "\n"), name, len);
3359
Elliott Hughes03333822015-02-18 22:19:45 -08003360 bool gnu_vendor = (q - name == sizeof "gnu"
3361 && !memcmp (name, "gnu", sizeof "gnu"));
3362
3363 /* Loop over subsections. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003364 if (shdr->sh_type != SHT_GNU_ATTRIBUTES
Elliott Hughes03333822015-02-18 22:19:45 -08003365 || gnu_vendor)
Ben Cheng25b3c042013-11-20 14:45:36 -08003366 while (q < p)
3367 {
3368 const unsigned char *const sub = q;
3369
3370 unsigned int subsection_tag;
Elliott Hughes03333822015-02-18 22:19:45 -08003371 get_uleb128 (subsection_tag, q, p);
Ben Cheng25b3c042013-11-20 14:45:36 -08003372 if (unlikely (q >= p))
3373 break;
3374
3375 uint32_t subsection_len;
3376 if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len))
3377 break;
3378
3379 memcpy (&subsection_len, q, sizeof subsection_len);
3380
3381 if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3382 CONVERT (subsection_len);
3383
Elliott Hughes03333822015-02-18 22:19:45 -08003384 /* Don't overflow, ptrdiff_t might be 32bits, but signed. */
3385 if (unlikely (subsection_len == 0
3386 || subsection_len >= (uint32_t) PTRDIFF_MAX
3387 || p - sub < (ptrdiff_t) subsection_len))
Ben Cheng25b3c042013-11-20 14:45:36 -08003388 break;
3389
3390 const unsigned char *r = q + sizeof subsection_len;
3391 q = sub + subsection_len;
3392
3393 switch (subsection_tag)
3394 {
3395 default:
Elliott Hughes03333822015-02-18 22:19:45 -08003396 /* Unknown subsection, print and skip. */
Ben Cheng25b3c042013-11-20 14:45:36 -08003397 printf (gettext (" %-4u %12" PRIu32 "\n"),
3398 subsection_tag, subsection_len);
3399 break;
3400
3401 case 1: /* Tag_File */
3402 printf (gettext (" File: %11" PRIu32 "\n"),
3403 subsection_len);
3404
3405 while (r < q)
3406 {
3407 unsigned int tag;
Elliott Hughes03333822015-02-18 22:19:45 -08003408 get_uleb128 (tag, r, q);
Ben Cheng25b3c042013-11-20 14:45:36 -08003409 if (unlikely (r >= q))
3410 break;
3411
Elliott Hughes03333822015-02-18 22:19:45 -08003412 /* GNU style tags have either a uleb128 value,
3413 when lowest bit is not set, or a string
3414 when the lowest bit is set.
3415 "compatibility" (32) is special. It has
3416 both a string and a uleb128 value. For
3417 non-gnu we assume 6 till 31 only take ints.
3418 XXX see arm backend, do we need a separate
3419 hook? */
Ben Cheng25b3c042013-11-20 14:45:36 -08003420 uint64_t value = 0;
3421 const char *string = NULL;
Elliott Hughes03333822015-02-18 22:19:45 -08003422 if (tag == 32 || (tag & 1) == 0
3423 || (! gnu_vendor && (tag > 5 && tag < 32)))
Ben Cheng25b3c042013-11-20 14:45:36 -08003424 {
Elliott Hughes03333822015-02-18 22:19:45 -08003425 get_uleb128 (value, r, q);
Ben Cheng25b3c042013-11-20 14:45:36 -08003426 if (r > q)
3427 break;
3428 }
Elliott Hughes03333822015-02-18 22:19:45 -08003429 if (tag == 32
3430 || ((tag & 1) != 0
3431 && (gnu_vendor
3432 || (! gnu_vendor && tag > 32)))
3433 || (! gnu_vendor && tag > 3 && tag < 6))
Ben Cheng25b3c042013-11-20 14:45:36 -08003434 {
Elliott Hughes03333822015-02-18 22:19:45 -08003435 string = (const char *) r;
Ben Cheng25b3c042013-11-20 14:45:36 -08003436 r = memchr (r, '\0', q - r);
3437 if (r == NULL)
3438 break;
3439 ++r;
3440 }
3441
3442 const char *tag_name = NULL;
3443 const char *value_name = NULL;
3444 ebl_check_object_attribute (ebl, (const char *) name,
3445 tag, value,
3446 &tag_name, &value_name);
3447
3448 if (tag_name != NULL)
3449 {
3450 if (tag == 32)
3451 printf (gettext (" %s: %" PRId64 ", %s\n"),
3452 tag_name, value, string);
3453 else if (string == NULL && value_name == NULL)
3454 printf (gettext (" %s: %" PRId64 "\n"),
3455 tag_name, value);
3456 else
3457 printf (gettext (" %s: %s\n"),
3458 tag_name, string ?: value_name);
3459 }
3460 else
3461 {
Elliott Hughes03333822015-02-18 22:19:45 -08003462 /* For "gnu" vendor 32 "compatibility" has
3463 already been handled above. */
3464 assert (tag != 32
3465 || strcmp ((const char *) name, "gnu"));
Ben Cheng25b3c042013-11-20 14:45:36 -08003466 if (string == NULL)
3467 printf (gettext (" %u: %" PRId64 "\n"),
3468 tag, value);
3469 else
3470 printf (gettext (" %u: %s\n"),
3471 tag, string);
3472 }
3473 }
3474 }
3475 }
3476 }
3477 }
3478}
3479
3480
3481static char *
3482format_dwarf_addr (Dwfl_Module *dwflmod,
Elliott Hughes03333822015-02-18 22:19:45 -08003483 int address_size, Dwarf_Addr address, Dwarf_Addr raw)
Ben Cheng25b3c042013-11-20 14:45:36 -08003484{
3485 /* See if there is a name we can give for this address. */
3486 GElf_Sym sym;
Elliott Hughes03333822015-02-18 22:19:45 -08003487 GElf_Off off = 0;
3488 const char *name = (print_address_names && ! print_unresolved_addresses)
3489 ? dwfl_module_addrinfo (dwflmod, address, &off, &sym, NULL, NULL, NULL)
3490 : NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003491
Elliott Hughes03333822015-02-18 22:19:45 -08003492 const char *scn;
3493 if (print_unresolved_addresses)
3494 {
3495 address = raw;
3496 scn = NULL;
3497 }
3498 else
3499 {
3500 /* Relativize the address. */
3501 int n = dwfl_module_relocations (dwflmod);
3502 int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
Ben Cheng25b3c042013-11-20 14:45:36 -08003503
Elliott Hughes03333822015-02-18 22:19:45 -08003504 /* In an ET_REL file there is a section name to refer to. */
3505 scn = (i < 0 ? NULL
3506 : dwfl_module_relocation_info (dwflmod, i, NULL));
3507 }
Ben Cheng25b3c042013-11-20 14:45:36 -08003508
3509 char *result;
3510 if ((name != NULL
Elliott Hughes03333822015-02-18 22:19:45 -08003511 ? (off != 0
Ben Cheng25b3c042013-11-20 14:45:36 -08003512 ? (scn != NULL
3513 ? (address_size == 0
3514 ? asprintf (&result,
3515 gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
Elliott Hughes03333822015-02-18 22:19:45 -08003516 scn, address, name, off)
Ben Cheng25b3c042013-11-20 14:45:36 -08003517 : asprintf (&result,
3518 gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
3519 scn, 2 + address_size * 2, address,
Elliott Hughes03333822015-02-18 22:19:45 -08003520 name, off))
Ben Cheng25b3c042013-11-20 14:45:36 -08003521 : (address_size == 0
3522 ? asprintf (&result,
3523 gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
Elliott Hughes03333822015-02-18 22:19:45 -08003524 address, name, off)
Ben Cheng25b3c042013-11-20 14:45:36 -08003525 : asprintf (&result,
3526 gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
3527 2 + address_size * 2, address,
Elliott Hughes03333822015-02-18 22:19:45 -08003528 name, off)))
Ben Cheng25b3c042013-11-20 14:45:36 -08003529 : (scn != NULL
3530 ? (address_size == 0
3531 ? asprintf (&result,
3532 gettext ("%s+%#" PRIx64 " <%s>"),
3533 scn, address, name)
3534 : asprintf (&result,
3535 gettext ("%s+%#0*" PRIx64 " <%s>"),
3536 scn, 2 + address_size * 2, address, name))
3537 : (address_size == 0
3538 ? asprintf (&result,
3539 gettext ("%#" PRIx64 " <%s>"),
3540 address, name)
3541 : asprintf (&result,
3542 gettext ("%#0*" PRIx64 " <%s>"),
3543 2 + address_size * 2, address, name))))
3544 : (scn != NULL
3545 ? (address_size == 0
3546 ? asprintf (&result,
3547 gettext ("%s+%#" PRIx64),
3548 scn, address)
3549 : asprintf (&result,
3550 gettext ("%s+%#0*" PRIx64),
3551 scn, 2 + address_size * 2, address))
3552 : (address_size == 0
3553 ? asprintf (&result,
3554 "%#" PRIx64,
3555 address)
3556 : asprintf (&result,
3557 "%#0*" PRIx64,
3558 2 + address_size * 2, address)))) < 0)
3559 error (EXIT_FAILURE, 0, _("memory exhausted"));
3560
3561 return result;
3562}
3563
3564static const char *
3565dwarf_tag_string (unsigned int tag)
3566{
Elliott Hughes03333822015-02-18 22:19:45 -08003567 switch (tag)
Ben Cheng25b3c042013-11-20 14:45:36 -08003568 {
Elliott Hughes03333822015-02-18 22:19:45 -08003569#define ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
3570 ALL_KNOWN_DW_TAG
3571#undef ONE_KNOWN_DW_TAG
3572 default:
3573 return NULL;
3574 }
Ben Cheng25b3c042013-11-20 14:45:36 -08003575}
3576
3577
3578static const char *
3579dwarf_attr_string (unsigned int attrnum)
3580{
Elliott Hughes03333822015-02-18 22:19:45 -08003581 switch (attrnum)
Ben Cheng25b3c042013-11-20 14:45:36 -08003582 {
Elliott Hughes03333822015-02-18 22:19:45 -08003583#define ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
3584 ALL_KNOWN_DW_AT
3585#undef ONE_KNOWN_DW_AT
3586 default:
3587 return NULL;
3588 }
Ben Cheng25b3c042013-11-20 14:45:36 -08003589}
3590
3591
3592static const char *
3593dwarf_form_string (unsigned int form)
3594{
Elliott Hughes03333822015-02-18 22:19:45 -08003595 switch (form)
Ben Cheng25b3c042013-11-20 14:45:36 -08003596 {
Elliott Hughes03333822015-02-18 22:19:45 -08003597#define ONE_KNOWN_DW_FORM_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_FORM (NAME, CODE)
3598#define ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
3599 ALL_KNOWN_DW_FORM
3600#undef ONE_KNOWN_DW_FORM
3601#undef ONE_KNOWN_DW_FORM_DESC
3602 default:
3603 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003604 }
Ben Cheng25b3c042013-11-20 14:45:36 -08003605}
3606
3607
3608static const char *
3609dwarf_lang_string (unsigned int lang)
3610{
Elliott Hughes03333822015-02-18 22:19:45 -08003611 switch (lang)
Ben Cheng25b3c042013-11-20 14:45:36 -08003612 {
Elliott Hughes03333822015-02-18 22:19:45 -08003613#define ONE_KNOWN_DW_LANG_DESC(NAME, CODE, DESC) case CODE: return #NAME;
3614 ALL_KNOWN_DW_LANG
3615#undef ONE_KNOWN_DW_LANG_DESC
3616 default:
3617 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003618 }
Ben Cheng25b3c042013-11-20 14:45:36 -08003619}
3620
3621
3622static const char *
3623dwarf_inline_string (unsigned int code)
3624{
3625 static const char *const known[] =
3626 {
Elliott Hughes03333822015-02-18 22:19:45 -08003627#define ONE_KNOWN_DW_INL(NAME, CODE) [CODE] = #NAME,
3628 ALL_KNOWN_DW_INL
3629#undef ONE_KNOWN_DW_INL
Ben Cheng25b3c042013-11-20 14:45:36 -08003630 };
3631
3632 if (likely (code < sizeof (known) / sizeof (known[0])))
3633 return known[code];
3634
Elliott Hughes03333822015-02-18 22:19:45 -08003635 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003636}
3637
3638
3639static const char *
3640dwarf_encoding_string (unsigned int code)
3641{
3642 static const char *const known[] =
3643 {
Elliott Hughes03333822015-02-18 22:19:45 -08003644#define ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
3645 ALL_KNOWN_DW_ATE
3646#undef ONE_KNOWN_DW_ATE
Ben Cheng25b3c042013-11-20 14:45:36 -08003647 };
3648
3649 if (likely (code < sizeof (known) / sizeof (known[0])))
3650 return known[code];
3651
Elliott Hughes03333822015-02-18 22:19:45 -08003652 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003653}
3654
3655
3656static const char *
3657dwarf_access_string (unsigned int code)
3658{
3659 static const char *const known[] =
3660 {
Elliott Hughes03333822015-02-18 22:19:45 -08003661#define ONE_KNOWN_DW_ACCESS(NAME, CODE) [CODE] = #NAME,
3662 ALL_KNOWN_DW_ACCESS
3663#undef ONE_KNOWN_DW_ACCESS
Ben Cheng25b3c042013-11-20 14:45:36 -08003664 };
3665
3666 if (likely (code < sizeof (known) / sizeof (known[0])))
3667 return known[code];
3668
Elliott Hughes03333822015-02-18 22:19:45 -08003669 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003670}
3671
3672
3673static const char *
3674dwarf_visibility_string (unsigned int code)
3675{
3676 static const char *const known[] =
3677 {
Elliott Hughes03333822015-02-18 22:19:45 -08003678#define ONE_KNOWN_DW_VIS(NAME, CODE) [CODE] = #NAME,
3679 ALL_KNOWN_DW_VIS
3680#undef ONE_KNOWN_DW_VIS
Ben Cheng25b3c042013-11-20 14:45:36 -08003681 };
3682
3683 if (likely (code < sizeof (known) / sizeof (known[0])))
3684 return known[code];
3685
Elliott Hughes03333822015-02-18 22:19:45 -08003686 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003687}
3688
3689
3690static const char *
3691dwarf_virtuality_string (unsigned int code)
3692{
3693 static const char *const known[] =
3694 {
Elliott Hughes03333822015-02-18 22:19:45 -08003695#define ONE_KNOWN_DW_VIRTUALITY(NAME, CODE) [CODE] = #NAME,
3696 ALL_KNOWN_DW_VIRTUALITY
3697#undef ONE_KNOWN_DW_VIRTUALITY
Ben Cheng25b3c042013-11-20 14:45:36 -08003698 };
3699
3700 if (likely (code < sizeof (known) / sizeof (known[0])))
3701 return known[code];
3702
Elliott Hughes03333822015-02-18 22:19:45 -08003703 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003704}
3705
3706
3707static const char *
3708dwarf_identifier_case_string (unsigned int code)
3709{
3710 static const char *const known[] =
3711 {
Elliott Hughes03333822015-02-18 22:19:45 -08003712#define ONE_KNOWN_DW_ID(NAME, CODE) [CODE] = #NAME,
3713 ALL_KNOWN_DW_ID
3714#undef ONE_KNOWN_DW_ID
Ben Cheng25b3c042013-11-20 14:45:36 -08003715 };
3716
3717 if (likely (code < sizeof (known) / sizeof (known[0])))
3718 return known[code];
3719
Elliott Hughes03333822015-02-18 22:19:45 -08003720 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003721}
3722
3723
3724static const char *
3725dwarf_calling_convention_string (unsigned int code)
3726{
3727 static const char *const known[] =
3728 {
Elliott Hughes03333822015-02-18 22:19:45 -08003729#define ONE_KNOWN_DW_CC(NAME, CODE) [CODE] = #NAME,
3730 ALL_KNOWN_DW_CC
3731#undef ONE_KNOWN_DW_CC
Ben Cheng25b3c042013-11-20 14:45:36 -08003732 };
3733
3734 if (likely (code < sizeof (known) / sizeof (known[0])))
3735 return known[code];
3736
Elliott Hughes03333822015-02-18 22:19:45 -08003737 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003738}
3739
3740
3741static const char *
3742dwarf_ordering_string (unsigned int code)
3743{
3744 static const char *const known[] =
3745 {
Elliott Hughes03333822015-02-18 22:19:45 -08003746#define ONE_KNOWN_DW_ORD(NAME, CODE) [CODE] = #NAME,
3747 ALL_KNOWN_DW_ORD
3748#undef ONE_KNOWN_DW_ORD
Ben Cheng25b3c042013-11-20 14:45:36 -08003749 };
3750
3751 if (likely (code < sizeof (known) / sizeof (known[0])))
3752 return known[code];
3753
Elliott Hughes03333822015-02-18 22:19:45 -08003754 return NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -08003755}
3756
3757
3758static const char *
3759dwarf_discr_list_string (unsigned int code)
3760{
3761 static const char *const known[] =
3762 {
Elliott Hughes03333822015-02-18 22:19:45 -08003763#define ONE_KNOWN_DW_DSC(NAME, CODE) [CODE] = #NAME,
3764 ALL_KNOWN_DW_DSC
3765#undef ONE_KNOWN_DW_DSC
Ben Cheng25b3c042013-11-20 14:45:36 -08003766 };
3767
3768 if (likely (code < sizeof (known) / sizeof (known[0])))
3769 return known[code];
3770
Elliott Hughes03333822015-02-18 22:19:45 -08003771 return NULL;
3772}
3773
3774
3775static const char *
3776dwarf_locexpr_opcode_string (unsigned int code)
3777{
3778 static const char *const known[] =
3779 {
3780 /* Normally we can't affort building huge table of 64K entries,
3781 most of them zero, just because there are a couple defined
3782 values at the far end. In case of opcodes, it's OK. */
3783#define ONE_KNOWN_DW_OP_DESC(NAME, CODE, DESC) ONE_KNOWN_DW_OP (NAME, CODE)
3784#define ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
3785 ALL_KNOWN_DW_OP
3786#undef ONE_KNOWN_DW_OP
3787#undef ONE_KNOWN_DW_OP_DESC
3788 };
3789
3790 if (likely (code < sizeof (known) / sizeof (known[0])))
3791 return known[code];
3792
3793 return NULL;
3794}
3795
3796
3797/* Used by all dwarf_foo_name functions. */
3798static const char *
3799string_or_unknown (const char *known, unsigned int code,
3800 unsigned int lo_user, unsigned int hi_user,
3801 bool print_unknown_num)
3802{
3803 static char unknown_buf[20];
3804
3805 if (likely (known != NULL))
3806 return known;
3807
3808 if (lo_user != 0 && code >= lo_user && code <= hi_user)
3809 {
3810 snprintf (unknown_buf, sizeof unknown_buf, "lo_user+%#x",
3811 code - lo_user);
3812 return unknown_buf;
3813 }
3814
3815 if (print_unknown_num)
3816 {
3817 snprintf (unknown_buf, sizeof unknown_buf, "??? (%#x)", code);
3818 return unknown_buf;
3819 }
3820
Ben Cheng25b3c042013-11-20 14:45:36 -08003821 return "???";
3822}
3823
3824
Elliott Hughes03333822015-02-18 22:19:45 -08003825static const char *
3826dwarf_tag_name (unsigned int tag)
3827{
3828 const char *ret = dwarf_tag_string (tag);
3829 return string_or_unknown (ret, tag, DW_TAG_lo_user, DW_TAG_hi_user, true);
3830}
3831
3832static const char *
3833dwarf_attr_name (unsigned int attr)
3834{
3835 const char *ret = dwarf_attr_string (attr);
3836 return string_or_unknown (ret, attr, DW_AT_lo_user, DW_AT_hi_user, true);
3837}
3838
3839
3840static const char *
3841dwarf_form_name (unsigned int form)
3842{
3843 const char *ret = dwarf_form_string (form);
3844 return string_or_unknown (ret, form, 0, 0, true);
3845}
3846
3847
3848static const char *
3849dwarf_lang_name (unsigned int lang)
3850{
3851 const char *ret = dwarf_lang_string (lang);
3852 return string_or_unknown (ret, lang, DW_LANG_lo_user, DW_LANG_hi_user, false);
3853}
3854
3855
3856static const char *
3857dwarf_inline_name (unsigned int code)
3858{
3859 const char *ret = dwarf_inline_string (code);
3860 return string_or_unknown (ret, code, 0, 0, false);
3861}
3862
3863
3864static const char *
3865dwarf_encoding_name (unsigned int code)
3866{
3867 const char *ret = dwarf_encoding_string (code);
3868 return string_or_unknown (ret, code, DW_ATE_lo_user, DW_ATE_hi_user, false);
3869}
3870
3871
3872static const char *
3873dwarf_access_name (unsigned int code)
3874{
3875 const char *ret = dwarf_access_string (code);
3876 return string_or_unknown (ret, code, 0, 0, false);
3877}
3878
3879
3880static const char *
3881dwarf_visibility_name (unsigned int code)
3882{
3883 const char *ret = dwarf_visibility_string (code);
3884 return string_or_unknown (ret, code, 0, 0, false);
3885}
3886
3887
3888static const char *
3889dwarf_virtuality_name (unsigned int code)
3890{
3891 const char *ret = dwarf_virtuality_string (code);
3892 return string_or_unknown (ret, code, 0, 0, false);
3893}
3894
3895
3896static const char *
3897dwarf_identifier_case_name (unsigned int code)
3898{
3899 const char *ret = dwarf_identifier_case_string (code);
3900 return string_or_unknown (ret, code, 0, 0, false);
3901}
3902
3903
3904static const char *
3905dwarf_calling_convention_name (unsigned int code)
3906{
3907 const char *ret = dwarf_calling_convention_string (code);
3908 return string_or_unknown (ret, code, DW_CC_lo_user, DW_CC_hi_user, false);
3909}
3910
3911
3912static const char *
3913dwarf_ordering_name (unsigned int code)
3914{
3915 const char *ret = dwarf_ordering_string (code);
3916 return string_or_unknown (ret, code, 0, 0, false);
3917}
3918
3919
3920static const char *
3921dwarf_discr_list_name (unsigned int code)
3922{
3923 const char *ret = dwarf_discr_list_string (code);
3924 return string_or_unknown (ret, code, 0, 0, false);
3925}
3926
3927
Ben Cheng25b3c042013-11-20 14:45:36 -08003928static void
3929print_block (size_t n, const void *block)
3930{
3931 if (n == 0)
3932 puts (_("empty block"));
3933 else
3934 {
3935 printf (_("%zu byte block:"), n);
3936 const unsigned char *data = block;
3937 do
3938 printf (" %02x", *data++);
3939 while (--n > 0);
3940 putchar ('\n');
3941 }
3942}
3943
3944static void
3945print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
3946 unsigned int vers, unsigned int addrsize, unsigned int offset_size,
Elliott Hughes03333822015-02-18 22:19:45 -08003947 struct Dwarf_CU *cu, Dwarf_Word len, const unsigned char *data)
Ben Cheng25b3c042013-11-20 14:45:36 -08003948{
3949 const unsigned int ref_size = vers < 3 ? addrsize : offset_size;
3950
Ben Cheng25b3c042013-11-20 14:45:36 -08003951 if (len == 0)
3952 {
3953 printf ("%*s(empty)\n", indent, "");
3954 return;
3955 }
3956
3957#define NEED(n) if (len < (Dwarf_Word) (n)) goto invalid
3958#define CONSUME(n) NEED (n); else len -= (n)
3959
3960 Dwarf_Word offset = 0;
3961 while (len-- > 0)
3962 {
3963 uint_fast8_t op = *data++;
3964
Elliott Hughes03333822015-02-18 22:19:45 -08003965 const char *op_name = dwarf_locexpr_opcode_string (op);
3966 if (unlikely (op_name == NULL))
3967 {
3968 static char buf[20];
3969 if (op >= DW_OP_lo_user)
3970 snprintf (buf, sizeof buf, "lo_user+%#x", op - DW_OP_lo_user);
3971 else
3972 snprintf (buf, sizeof buf, "??? (%#x)", op);
3973 op_name = buf;
3974 }
3975
Ben Cheng25b3c042013-11-20 14:45:36 -08003976 switch (op)
3977 {
3978 case DW_OP_addr:;
3979 /* Address operand. */
3980 Dwarf_Word addr;
3981 NEED (addrsize);
3982 if (addrsize == 4)
3983 addr = read_4ubyte_unaligned (dbg, data);
Elliott Hughes03333822015-02-18 22:19:45 -08003984 else if (addrsize == 8)
3985 addr = read_8ubyte_unaligned (dbg, data);
Ben Cheng25b3c042013-11-20 14:45:36 -08003986 else
Elliott Hughes03333822015-02-18 22:19:45 -08003987 goto invalid;
Ben Cheng25b3c042013-11-20 14:45:36 -08003988 data += addrsize;
3989 CONSUME (addrsize);
3990
Elliott Hughes03333822015-02-18 22:19:45 -08003991 char *a = format_dwarf_addr (dwflmod, 0, addr, addr);
Ben Cheng25b3c042013-11-20 14:45:36 -08003992 printf ("%*s[%4" PRIuMAX "] %s %s\n",
Elliott Hughes03333822015-02-18 22:19:45 -08003993 indent, "", (uintmax_t) offset, op_name, a);
Ben Cheng25b3c042013-11-20 14:45:36 -08003994 free (a);
3995
3996 offset += 1 + addrsize;
3997 break;
3998
3999 case DW_OP_call_ref:
4000 /* Offset operand. */
Elliott Hughes03333822015-02-18 22:19:45 -08004001 if (ref_size != 4 && ref_size != 8)
4002 goto invalid; /* Cannot be used in CFA. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004003 NEED (ref_size);
4004 if (ref_size == 4)
4005 addr = read_4ubyte_unaligned (dbg, data);
4006 else
Elliott Hughes03333822015-02-18 22:19:45 -08004007 addr = read_8ubyte_unaligned (dbg, data);
Ben Cheng25b3c042013-11-20 14:45:36 -08004008 data += ref_size;
4009 CONSUME (ref_size);
4010
4011 printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
4012 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004013 op_name, (uintmax_t) addr);
Ben Cheng25b3c042013-11-20 14:45:36 -08004014 offset += 1 + ref_size;
4015 break;
4016
4017 case DW_OP_deref_size:
4018 case DW_OP_xderef_size:
4019 case DW_OP_pick:
4020 case DW_OP_const1u:
4021 // XXX value might be modified by relocation
4022 NEED (1);
4023 printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
4024 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004025 op_name, *((uint8_t *) data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004026 ++data;
4027 --len;
4028 offset += 2;
4029 break;
4030
4031 case DW_OP_const2u:
4032 NEED (2);
4033 // XXX value might be modified by relocation
4034 printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
4035 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004036 op_name, read_2ubyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004037 CONSUME (2);
4038 data += 2;
4039 offset += 3;
4040 break;
4041
4042 case DW_OP_const4u:
4043 NEED (4);
4044 // XXX value might be modified by relocation
4045 printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
4046 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004047 op_name, read_4ubyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004048 CONSUME (4);
4049 data += 4;
4050 offset += 5;
4051 break;
4052
4053 case DW_OP_const8u:
4054 NEED (8);
4055 // XXX value might be modified by relocation
4056 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
4057 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004058 op_name, (uint64_t) read_8ubyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004059 CONSUME (8);
4060 data += 8;
4061 offset += 9;
4062 break;
4063
4064 case DW_OP_const1s:
4065 NEED (1);
4066 // XXX value might be modified by relocation
4067 printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
4068 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004069 op_name, *((int8_t *) data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004070 ++data;
4071 --len;
4072 offset += 2;
4073 break;
4074
4075 case DW_OP_const2s:
4076 NEED (2);
4077 // XXX value might be modified by relocation
4078 printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
4079 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004080 op_name, read_2sbyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004081 CONSUME (2);
4082 data += 2;
4083 offset += 3;
4084 break;
4085
4086 case DW_OP_const4s:
4087 NEED (4);
4088 // XXX value might be modified by relocation
4089 printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
4090 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004091 op_name, read_4sbyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004092 CONSUME (4);
4093 data += 4;
4094 offset += 5;
4095 break;
4096
4097 case DW_OP_const8s:
4098 NEED (8);
4099 // XXX value might be modified by relocation
4100 printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
4101 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004102 op_name, read_8sbyte_unaligned (dbg, data));
Ben Cheng25b3c042013-11-20 14:45:36 -08004103 CONSUME (8);
4104 data += 8;
4105 offset += 9;
4106 break;
4107
4108 case DW_OP_piece:
4109 case DW_OP_regx:
4110 case DW_OP_plus_uconst:
4111 case DW_OP_constu:;
4112 const unsigned char *start = data;
4113 uint64_t uleb;
4114 NEED (1);
Elliott Hughes03333822015-02-18 22:19:45 -08004115 get_uleb128 (uleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004116 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004117 indent, "", (uintmax_t) offset, op_name, uleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004118 CONSUME (data - start);
4119 offset += 1 + (data - start);
4120 break;
4121
4122 case DW_OP_bit_piece:
4123 start = data;
4124 uint64_t uleb2;
Elliott Hughes03333822015-02-18 22:19:45 -08004125 NEED (1);
4126 get_uleb128 (uleb, data, data + len);
4127 NEED (1);
4128 get_uleb128 (uleb2, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004129 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004130 indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
Ben Cheng25b3c042013-11-20 14:45:36 -08004131 CONSUME (data - start);
4132 offset += 1 + (data - start);
4133 break;
4134
4135 case DW_OP_fbreg:
4136 case DW_OP_breg0 ... DW_OP_breg31:
4137 case DW_OP_consts:
4138 start = data;
4139 int64_t sleb;
4140 NEED (1);
Elliott Hughes03333822015-02-18 22:19:45 -08004141 get_sleb128 (sleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004142 printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004143 indent, "", (uintmax_t) offset, op_name, sleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004144 CONSUME (data - start);
4145 offset += 1 + (data - start);
4146 break;
4147
4148 case DW_OP_bregx:
4149 start = data;
Elliott Hughes03333822015-02-18 22:19:45 -08004150 NEED (1);
4151 get_uleb128 (uleb, data, data + len);
4152 NEED (1);
4153 get_sleb128 (sleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004154 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004155 indent, "", (uintmax_t) offset, op_name, uleb, sleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004156 CONSUME (data - start);
4157 offset += 1 + (data - start);
4158 break;
4159
4160 case DW_OP_call2:
4161 NEED (2);
4162 printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004163 indent, "", (uintmax_t) offset, op_name,
Ben Cheng25b3c042013-11-20 14:45:36 -08004164 read_2ubyte_unaligned (dbg, data));
4165 CONSUME (2);
4166 offset += 3;
4167 break;
4168
4169 case DW_OP_call4:
4170 NEED (4);
4171 printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004172 indent, "", (uintmax_t) offset, op_name,
Ben Cheng25b3c042013-11-20 14:45:36 -08004173 read_4ubyte_unaligned (dbg, data));
4174 CONSUME (4);
4175 offset += 5;
4176 break;
4177
4178 case DW_OP_skip:
4179 case DW_OP_bra:
4180 NEED (2);
4181 printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004182 indent, "", (uintmax_t) offset, op_name,
4183 (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data) + 3));
Ben Cheng25b3c042013-11-20 14:45:36 -08004184 CONSUME (2);
4185 data += 2;
4186 offset += 3;
4187 break;
4188
4189 case DW_OP_implicit_value:
4190 start = data;
4191 NEED (1);
Elliott Hughes03333822015-02-18 22:19:45 -08004192 get_uleb128 (uleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004193 printf ("%*s[%4" PRIuMAX "] %s: ",
Elliott Hughes03333822015-02-18 22:19:45 -08004194 indent, "", (uintmax_t) offset, op_name);
Ben Cheng25b3c042013-11-20 14:45:36 -08004195 NEED (uleb);
4196 print_block (uleb, data);
4197 data += uleb;
4198 CONSUME (data - start);
4199 offset += 1 + (data - start);
4200 break;
4201
4202 case DW_OP_GNU_implicit_pointer:
4203 /* DIE offset operand. */
4204 start = data;
Elliott Hughes03333822015-02-18 22:19:45 -08004205 NEED (ref_size);
4206 if (ref_size != 4 && ref_size != 8)
4207 goto invalid; /* Cannot be used in CFA. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004208 if (ref_size == 4)
4209 addr = read_4ubyte_unaligned (dbg, data);
4210 else
Elliott Hughes03333822015-02-18 22:19:45 -08004211 addr = read_8ubyte_unaligned (dbg, data);
Ben Cheng25b3c042013-11-20 14:45:36 -08004212 data += ref_size;
4213 /* Byte offset operand. */
Elliott Hughes03333822015-02-18 22:19:45 -08004214 NEED (1);
4215 get_sleb128 (sleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004216
Elliott Hughes03333822015-02-18 22:19:45 -08004217 printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] %+" PRId64 "\n",
Ben Cheng25b3c042013-11-20 14:45:36 -08004218 indent, "", (intmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004219 op_name, (uintmax_t) addr, sleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004220 CONSUME (data - start);
4221 offset += 1 + (data - start);
4222 break;
4223
4224 case DW_OP_GNU_entry_value:
4225 /* Size plus expression block. */
4226 start = data;
4227 NEED (1);
Elliott Hughes03333822015-02-18 22:19:45 -08004228 get_uleb128 (uleb, data, data + len);
Ben Cheng25b3c042013-11-20 14:45:36 -08004229 printf ("%*s[%4" PRIuMAX "] %s:\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004230 indent, "", (uintmax_t) offset, op_name);
Ben Cheng25b3c042013-11-20 14:45:36 -08004231 NEED (uleb);
4232 print_ops (dwflmod, dbg, indent + 6, indent + 6, vers,
Elliott Hughes03333822015-02-18 22:19:45 -08004233 addrsize, offset_size, cu, uleb, data);
Ben Cheng25b3c042013-11-20 14:45:36 -08004234 data += uleb;
4235 CONSUME (data - start);
4236 offset += 1 + (data - start);
4237 break;
4238
4239 case DW_OP_GNU_const_type:
Elliott Hughes03333822015-02-18 22:19:45 -08004240 /* uleb128 CU relative DW_TAG_base_type DIE offset, 1-byte
4241 unsigned size plus block. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004242 start = data;
Elliott Hughes03333822015-02-18 22:19:45 -08004243 NEED (1);
4244 get_uleb128 (uleb, data, data + len);
4245 if (! print_unresolved_addresses && cu != NULL)
4246 uleb += cu->start;
4247 NEED (1);
Ben Cheng25b3c042013-11-20 14:45:36 -08004248 uint8_t usize = *(uint8_t *) data++;
4249 NEED (usize);
4250 printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] ",
Elliott Hughes03333822015-02-18 22:19:45 -08004251 indent, "", (uintmax_t) offset, op_name, uleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004252 print_block (usize, data);
4253 data += usize;
4254 CONSUME (data - start);
4255 offset += 1 + (data - start);
4256 break;
4257
4258 case DW_OP_GNU_regval_type:
Elliott Hughes03333822015-02-18 22:19:45 -08004259 /* uleb128 register number, uleb128 CU relative
4260 DW_TAG_base_type DIE offset. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004261 start = data;
Elliott Hughes03333822015-02-18 22:19:45 -08004262 NEED (1);
4263 get_uleb128 (uleb, data, data + len);
4264 NEED (1);
4265 get_uleb128 (uleb2, data, data + len);
4266 if (! print_unresolved_addresses && cu != NULL)
4267 uleb2 += cu->start;
4268 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " [%6" PRIx64 "]\n",
4269 indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
Ben Cheng25b3c042013-11-20 14:45:36 -08004270 CONSUME (data - start);
4271 offset += 1 + (data - start);
4272 break;
4273
4274 case DW_OP_GNU_deref_type:
Elliott Hughes03333822015-02-18 22:19:45 -08004275 /* 1-byte unsigned size of value, uleb128 CU relative
4276 DW_TAG_base_type DIE offset. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004277 start = data;
Elliott Hughes03333822015-02-18 22:19:45 -08004278 NEED (1);
Ben Cheng25b3c042013-11-20 14:45:36 -08004279 usize = *(uint8_t *) data++;
Elliott Hughes03333822015-02-18 22:19:45 -08004280 NEED (1);
4281 get_uleb128 (uleb, data, data + len);
4282 if (! print_unresolved_addresses && cu != NULL)
4283 uleb += cu->start;
Ben Cheng25b3c042013-11-20 14:45:36 -08004284 printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
4285 indent, "", (uintmax_t) offset,
Elliott Hughes03333822015-02-18 22:19:45 -08004286 op_name, usize, uleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004287 CONSUME (data - start);
4288 offset += 1 + (data - start);
4289 break;
4290
4291 case DW_OP_GNU_convert:
4292 case DW_OP_GNU_reinterpret:
Elliott Hughes03333822015-02-18 22:19:45 -08004293 /* uleb128 CU relative offset to DW_TAG_base_type, or zero
4294 for conversion to untyped. */
Ben Cheng25b3c042013-11-20 14:45:36 -08004295 start = data;
4296 NEED (1);
Elliott Hughes03333822015-02-18 22:19:45 -08004297 get_uleb128 (uleb, data, data + len);
4298 if (uleb != 0 && ! print_unresolved_addresses && cu != NULL)
4299 uleb += cu->start;
Ben Cheng25b3c042013-11-20 14:45:36 -08004300 printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004301 indent, "", (uintmax_t) offset, op_name, uleb);
Ben Cheng25b3c042013-11-20 14:45:36 -08004302 CONSUME (data - start);
4303 offset += 1 + (data - start);
4304 break;
4305
Elliott Hughes03333822015-02-18 22:19:45 -08004306 case DW_OP_GNU_parameter_ref:
4307 /* 4 byte CU relative reference to the abstract optimized away
4308 DW_TAG_formal_parameter. */
4309 NEED (4);
4310 uintmax_t param_off = (uintmax_t) read_4ubyte_unaligned (dbg, data);
4311 if (! print_unresolved_addresses && cu != NULL)
4312 param_off += cu->start;
4313 printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
4314 indent, "", (uintmax_t) offset, op_name, param_off);
4315 CONSUME (4);
4316 data += 4;
4317 offset += 5;
4318 break;
4319
Ben Cheng25b3c042013-11-20 14:45:36 -08004320 default:
4321 /* No Operand. */
Elliott Hughes03333822015-02-18 22:19:45 -08004322 printf ("%*s[%4" PRIuMAX "] %s\n",
4323 indent, "", (uintmax_t) offset, op_name);
Ben Cheng25b3c042013-11-20 14:45:36 -08004324 ++offset;
4325 break;
4326 }
4327
4328 indent = indentrest;
4329 continue;
4330
4331 invalid:
4332 printf (gettext ("%*s[%4" PRIuMAX "] %s <TRUNCATED>\n"),
Elliott Hughes03333822015-02-18 22:19:45 -08004333 indent, "", (uintmax_t) offset, op_name);
Ben Cheng25b3c042013-11-20 14:45:36 -08004334 break;
4335 }
4336}
4337
4338
4339struct listptr
4340{
4341 Dwarf_Off offset:(64 - 3);
4342 bool addr64:1;
4343 bool dwarf64:1;
4344 bool warned:1;
Elliott Hughes03333822015-02-18 22:19:45 -08004345 struct Dwarf_CU *cu;
Ben Cheng25b3c042013-11-20 14:45:36 -08004346};
4347
4348#define listptr_offset_size(p) ((p)->dwarf64 ? 8 : 4)
4349#define listptr_address_size(p) ((p)->addr64 ? 8 : 4)
4350
Elliott Hughes03333822015-02-18 22:19:45 -08004351static Dwarf_Addr
4352listptr_base (struct listptr *p)
4353{
4354 Dwarf_Addr base;
4355 Dwarf_Die cu = CUDIE (p->cu);
4356 /* Find the base address of the compilation unit. It will normally
4357 be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base
4358 address could be overridden by DW_AT_entry_pc. It's been
4359 removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for
4360 compilation units with discontinuous ranges. */
4361 if (unlikely (dwarf_lowpc (&cu, &base) != 0))
4362 {
4363 Dwarf_Attribute attr_mem;
4364 if (dwarf_formaddr (dwarf_attr (&cu, DW_AT_entry_pc, &attr_mem),
4365 &base) != 0)
4366 base = 0;
4367 }
4368 return base;
4369}
4370
Ben Cheng25b3c042013-11-20 14:45:36 -08004371static int
4372compare_listptr (const void *a, const void *b, void *arg)
4373{
4374 const char *name = arg;
4375 struct listptr *p1 = (void *) a;
4376 struct listptr *p2 = (void *) b;
4377
4378 if (p1->offset < p2->offset)
4379 return -1;
4380 if (p1->offset > p2->offset)
4381 return 1;
4382
4383 if (!p1->warned && !p2->warned)
4384 {
4385 if (p1->addr64 != p2->addr64)
4386 {
4387 p1->warned = p2->warned = true;
4388 error (0, 0,
4389 gettext ("%s %#" PRIx64 " used with different address sizes"),
4390 name, (uint64_t) p1->offset);
4391 }
4392 if (p1->dwarf64 != p2->dwarf64)
4393 {
4394 p1->warned = p2->warned = true;
4395 error (0, 0,
4396 gettext ("%s %#" PRIx64 " used with different offset sizes"),
4397 name, (uint64_t) p1->offset);
4398 }
Elliott Hughes03333822015-02-18 22:19:45 -08004399 if (listptr_base (p1) != listptr_base (p2))
4400 {
4401 p1->warned = p2->warned = true;
4402 error (0, 0,
4403 gettext ("%s %#" PRIx64 " used with different base addresses"),
4404 name, (uint64_t) p1->offset);
4405 }
Ben Cheng25b3c042013-11-20 14:45:36 -08004406 }
4407
4408 return 0;
4409}
4410
4411struct listptr_table
4412{
4413 size_t n;
4414 size_t alloc;
4415 struct listptr *table;
4416};
4417
4418static struct listptr_table known_loclistptr;
4419static struct listptr_table known_rangelistptr;
4420
4421static void
4422reset_listptr (struct listptr_table *table)
4423{
4424 free (table->table);
4425 table->table = NULL;
4426 table->n = table->alloc = 0;
4427}
4428
Elliott Hughes03333822015-02-18 22:19:45 -08004429/* Returns false if offset doesn't fit. See struct listptr. */
4430static bool
Ben Cheng25b3c042013-11-20 14:45:36 -08004431notice_listptr (enum section_e section, struct listptr_table *table,
4432 uint_fast8_t address_size, uint_fast8_t offset_size,
Elliott Hughes03333822015-02-18 22:19:45 -08004433 struct Dwarf_CU *cu, Dwarf_Off offset)
Ben Cheng25b3c042013-11-20 14:45:36 -08004434{
4435 if (print_debug_sections & section)
4436 {
4437 if (table->n == table->alloc)
4438 {
4439 if (table->alloc == 0)
4440 table->alloc = 128;
4441 else
4442 table->alloc *= 2;
4443 table->table = xrealloc (table->table,
4444 table->alloc * sizeof table->table[0]);
4445 }
4446
4447 struct listptr *p = &table->table[table->n++];
4448
4449 *p = (struct listptr)
4450 {
4451 .addr64 = address_size == 8,
4452 .dwarf64 = offset_size == 8,
Elliott Hughes03333822015-02-18 22:19:45 -08004453 .offset = offset,
4454 .cu = cu
Ben Cheng25b3c042013-11-20 14:45:36 -08004455 };
Elliott Hughes03333822015-02-18 22:19:45 -08004456
4457 if (p->offset != offset)
4458 {
4459 table->n--;
4460 return false;
4461 }
Ben Cheng25b3c042013-11-20 14:45:36 -08004462 }
Elliott Hughes03333822015-02-18 22:19:45 -08004463 return true;
Ben Cheng25b3c042013-11-20 14:45:36 -08004464}
4465
4466static void
4467sort_listptr (struct listptr_table *table, const char *name)
4468{
4469 if (table->n > 0)
4470 qsort_r (table->table, table->n, sizeof table->table[0],
4471 &compare_listptr, (void *) name);
4472}
4473
4474static bool
4475skip_listptr_hole (struct listptr_table *table, size_t *idxp,
4476 uint_fast8_t *address_sizep, uint_fast8_t *offset_sizep,
Elliott Hughes03333822015-02-18 22:19:45 -08004477 Dwarf_Addr *base, struct Dwarf_CU **cu, ptrdiff_t offset,
4478 unsigned char **readp, unsigned char *endp)
Ben Cheng25b3c042013-11-20 14:45:36 -08004479{
4480 if (table->n == 0)
4481 return false;
4482
4483 while (*idxp < table->n && table->table[*idxp].offset < (Dwarf_Off) offset)
4484 ++*idxp;
4485
4486 struct listptr *p = &table->table[*idxp];
4487
4488 if (*idxp == table->n
4489 || p->offset >= (Dwarf_Off) (endp - *readp + offset))
4490 {
4491 *readp = endp;
4492 printf (gettext (" [%6tx] <UNUSED GARBAGE IN REST OF SECTION>\n"),
4493 offset);
4494 return true;
4495 }
4496
4497 if (p->offset != (Dwarf_Off) offset)
4498 {
4499 *readp += p->offset - offset;
4500 printf (gettext (" [%6tx] <UNUSED GARBAGE> ... %" PRIu64 " bytes ...\n"),
4501 offset, (Dwarf_Off) p->offset - offset);
4502 return true;
4503 }
4504
4505 if (address_sizep != NULL)
4506 *address_sizep = listptr_address_size (p);
4507 if (offset_sizep != NULL)
4508 *offset_sizep = listptr_offset_size (p);
Elliott Hughes03333822015-02-18 22:19:45 -08004509 if (base != NULL)
4510 *base = listptr_base (p);
4511 if (cu != NULL)
4512 *cu = p->cu;
Ben Cheng25b3c042013-11-20 14:45:36 -08004513
4514 return false;
4515}
4516
4517
4518static void
4519print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4520 Ebl *ebl, GElf_Ehdr *ehdr,
4521 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
4522{
Elliott Hughes03333822015-02-18 22:19:45 -08004523 const size_t sh_size = (dbg->sectiondata[IDX_debug_abbrev] ?
4524 dbg->sectiondata[IDX_debug_abbrev]->d_size : 0);
4525
Ben Cheng25b3c042013-11-20 14:45:36 -08004526 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
4527 " [ Code]\n"),
4528 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4529 (uint64_t) shdr->sh_offset);
4530
4531 Dwarf_Off offset = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08004532 while (offset < sh_size)
Ben Cheng25b3c042013-11-20 14:45:36 -08004533 {
4534 printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
4535 offset);
4536
4537 while (1)
4538 {
4539 size_t length;
4540 Dwarf_Abbrev abbrev;
4541
4542 int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
4543 if (res != 0)
4544 {
4545 if (unlikely (res < 0))
4546 {
4547 printf (gettext ("\
4548 *** error while reading abbreviation: %s\n"),
4549 dwarf_errmsg (-1));
4550 return;
4551 }
4552
4553 /* This is the NUL byte at the end of the section. */
4554 ++offset;
4555 break;
4556 }
4557
4558 /* We know these calls can never fail. */
4559 unsigned int code = dwarf_getabbrevcode (&abbrev);
4560 unsigned int tag = dwarf_getabbrevtag (&abbrev);
4561 int has_children = dwarf_abbrevhaschildren (&abbrev);
4562
4563 printf (gettext (" [%5u] offset: %" PRId64
4564 ", children: %s, tag: %s\n"),
4565 code, (int64_t) offset,
4566 has_children ? gettext ("yes") : gettext ("no"),
Elliott Hughes03333822015-02-18 22:19:45 -08004567 dwarf_tag_name (tag));
Ben Cheng25b3c042013-11-20 14:45:36 -08004568
4569 size_t cnt = 0;
4570 unsigned int name;
4571 unsigned int form;
4572 Dwarf_Off enoffset;
4573 while (dwarf_getabbrevattr (&abbrev, cnt,
4574 &name, &form, &enoffset) == 0)
4575 {
4576 printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08004577 dwarf_attr_name (name), dwarf_form_name (form),
Ben Cheng25b3c042013-11-20 14:45:36 -08004578 (uint64_t) enoffset);
4579
4580 ++cnt;
4581 }
4582
4583 offset += length;
4584 }
4585 }
4586}
4587
4588
4589/* Print content of DWARF .debug_aranges section. We fortunately do
4590 not have to know a bit about the structure of the section, libdwarf
4591 takes care of it. */
4592static void
Elliott Hughes03333822015-02-18 22:19:45 -08004593print_decoded_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
4594 GElf_Shdr *shdr, Dwarf *dbg)
Ben Cheng25b3c042013-11-20 14:45:36 -08004595{
4596 Dwarf_Aranges *aranges;
4597 size_t cnt;
4598 if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
4599 {
4600 error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
4601 dwarf_errmsg (-1));
4602 return;
4603 }
4604
Elliott Hughes03333822015-02-18 22:19:45 -08004605 GElf_Shdr glink_mem;
4606 GElf_Shdr *glink;
4607 glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
4608 if (glink == NULL)
4609 {
4610 error (0, 0, gettext ("invalid sh_link value in section %Zu"),
4611 elf_ndxscn (scn));
4612 return;
4613 }
4614
Ben Cheng25b3c042013-11-20 14:45:36 -08004615 printf (ngettext ("\
4616\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n",
4617 "\
4618\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
4619 cnt),
4620 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4621 (uint64_t) shdr->sh_offset, cnt);
4622
4623 /* Compute floor(log16(cnt)). */
4624 size_t tmp = cnt;
4625 int digits = 1;
4626 while (tmp >= 16)
4627 {
4628 ++digits;
4629 tmp >>= 4;
4630 }
4631
4632 for (size_t n = 0; n < cnt; ++n)
4633 {
4634 Dwarf_Arange *runp = dwarf_onearange (aranges, n);
4635 if (unlikely (runp == NULL))
4636 {
4637 printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
4638 return;
4639 }
4640
4641 Dwarf_Addr start;
4642 Dwarf_Word length;
4643 Dwarf_Off offset;
4644
4645 if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
4646 printf (gettext (" [%*zu] ???\n"), digits, n);
4647 else
4648 printf (gettext (" [%*zu] start: %0#*" PRIx64
4649 ", length: %5" PRIu64 ", CU DIE offset: %6"
4650 PRId64 "\n"),
4651 digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18,
4652 (uint64_t) start, (uint64_t) length, (int64_t) offset);
4653 }
4654}
4655
Elliott Hughes03333822015-02-18 22:19:45 -08004656
4657/* Print content of DWARF .debug_aranges section. */
4658static void
4659print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4660 Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
4661 GElf_Shdr *shdr, Dwarf *dbg)
4662{
4663 if (decodedaranges)
4664 {
4665 print_decoded_aranges_section (ebl, ehdr, scn, shdr, dbg);
4666 return;
4667 }
4668
4669 Elf_Data *data = dbg->sectiondata[IDX_debug_aranges];
4670
4671 if (unlikely (data == NULL))
4672 {
4673 error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
4674 elf_errmsg (-1));
4675 return;
4676 }
4677
4678 printf (gettext ("\
4679\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4680 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4681 (uint64_t) shdr->sh_offset);
4682
4683 const unsigned char *readp = data->d_buf;
4684 const unsigned char *readendp = readp + data->d_size;
4685
4686 while (readp < readendp)
4687 {
4688 const unsigned char *hdrstart = readp;
4689 size_t start_offset = hdrstart - (const unsigned char *) data->d_buf;
4690
4691 printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
4692 if (readp + 4 > readendp)
4693 {
4694 invalid_data:
4695 error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
4696 elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
4697 return;
4698 }
4699
4700 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
4701 unsigned int length_bytes = 4;
4702 if (length == DWARF3_LENGTH_64_BIT)
4703 {
4704 if (readp + 8 > readendp)
4705 goto invalid_data;
4706 length = read_8ubyte_unaligned_inc (dbg, readp);
4707 length_bytes = 8;
4708 }
4709
4710 const unsigned char *nexthdr = readp + length;
4711 printf (gettext ("\n Length: %6" PRIu64 "\n"),
4712 (uint64_t) length);
4713
4714 if (unlikely (length > (size_t) (readendp - readp)))
4715 goto invalid_data;
4716
4717 if (length == 0)
4718 continue;
4719
4720 if (readp + 2 > readendp)
4721 goto invalid_data;
4722 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, readp);
4723 printf (gettext (" DWARF version: %6" PRIuFAST16 "\n"),
4724 version);
4725 if (version != 2)
4726 {
4727 error (0, 0, gettext ("unsupported aranges version"));
4728 goto next_table;
4729 }
4730
4731 Dwarf_Word offset;
4732 if (readp + length_bytes > readendp)
4733 goto invalid_data;
4734 if (length_bytes == 8)
4735 offset = read_8ubyte_unaligned_inc (dbg, readp);
4736 else
4737 offset = read_4ubyte_unaligned_inc (dbg, readp);
4738 printf (gettext (" CU offset: %6" PRIx64 "\n"),
4739 (uint64_t) offset);
4740
4741 if (readp + 1 > readendp)
4742 goto invalid_data;
4743 unsigned int address_size = *readp++;
4744 printf (gettext (" Address size: %6" PRIu64 "\n"),
4745 (uint64_t) address_size);
4746 if (address_size != 4 && address_size != 8)
4747 {
4748 error (0, 0, gettext ("unsupported address size"));
4749 goto next_table;
4750 }
4751
4752 unsigned int segment_size = *readp++;
4753 printf (gettext (" Segment size: %6" PRIu64 "\n\n"),
4754 (uint64_t) segment_size);
4755 if (segment_size != 0 && segment_size != 4 && segment_size != 8)
4756 {
4757 error (0, 0, gettext ("unsupported segment size"));
4758 goto next_table;
4759 }
4760
4761 /* Round the address to the next multiple of 2*address_size. */
4762 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
4763 % (2 * address_size));
4764
4765 while (readp < nexthdr)
4766 {
4767 Dwarf_Word range_address;
4768 Dwarf_Word range_length;
4769 Dwarf_Word segment = 0;
4770 if (readp + 2 * address_size + segment_size > readendp)
4771 goto invalid_data;
4772 if (address_size == 4)
4773 {
4774 range_address = read_4ubyte_unaligned_inc (dbg, readp);
4775 range_length = read_4ubyte_unaligned_inc (dbg, readp);
4776 }
4777 else
4778 {
4779 range_address = read_8ubyte_unaligned_inc (dbg, readp);
4780 range_length = read_8ubyte_unaligned_inc (dbg, readp);
4781 }
4782
4783 if (segment_size == 4)
4784 segment = read_4ubyte_unaligned_inc (dbg, readp);
4785 else if (segment_size == 8)
4786 segment = read_8ubyte_unaligned_inc (dbg, readp);
4787
4788 if (range_address == 0 && range_length == 0 && segment == 0)
4789 break;
4790
4791 char *b = format_dwarf_addr (dwflmod, address_size, range_address,
4792 range_address);
4793 char *e = format_dwarf_addr (dwflmod, address_size,
4794 range_address + range_length - 1,
4795 range_length);
4796 if (segment_size != 0)
4797 printf (gettext (" %s..%s (%" PRIx64 ")\n"), b, e,
4798 (uint64_t) segment);
4799 else
4800 printf (gettext (" %s..%s\n"), b, e);
4801 free (b);
4802 free (e);
4803 }
4804
4805 next_table:
4806 if (readp != nexthdr)
4807 {
4808 size_t padding = nexthdr - readp;
4809 printf (gettext (" %Zu padding bytes\n"), padding);
4810 readp = nexthdr;
4811 }
4812 }
4813}
4814
4815
Ben Cheng25b3c042013-11-20 14:45:36 -08004816/* Print content of DWARF .debug_ranges section. */
4817static void
4818print_debug_ranges_section (Dwfl_Module *dwflmod,
4819 Ebl *ebl, GElf_Ehdr *ehdr,
4820 Elf_Scn *scn, GElf_Shdr *shdr,
4821 Dwarf *dbg)
4822{
Elliott Hughes03333822015-02-18 22:19:45 -08004823 Elf_Data *data = dbg->sectiondata[IDX_debug_ranges];
Ben Cheng25b3c042013-11-20 14:45:36 -08004824
4825 if (unlikely (data == NULL))
4826 {
4827 error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
4828 elf_errmsg (-1));
4829 return;
4830 }
4831
4832 printf (gettext ("\
4833\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4834 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
4835 (uint64_t) shdr->sh_offset);
4836
4837 sort_listptr (&known_rangelistptr, "rangelistptr");
4838 size_t listptr_idx = 0;
4839
4840 uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4841
4842 bool first = true;
Elliott Hughes03333822015-02-18 22:19:45 -08004843 Dwarf_Addr base = 0;
Ben Cheng25b3c042013-11-20 14:45:36 -08004844 unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
4845 unsigned char *readp = data->d_buf;
4846 while (readp < endp)
4847 {
4848 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
4849
4850 if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
Elliott Hughes03333822015-02-18 22:19:45 -08004851 &address_size, NULL, &base, NULL,
Ben Cheng25b3c042013-11-20 14:45:36 -08004852 offset, &readp, endp))
4853 continue;
4854
Elliott Hughes03333822015-02-18 22:19:45 -08004855 if (unlikely (data->d_size - offset < (size_t) address_size * 2))
Ben Cheng25b3c042013-11-20 14:45:36 -08004856 {
4857 printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
4858 break;
4859 }
4860
4861 Dwarf_Addr begin;
4862 Dwarf_Addr end;
4863 if (address_size == 8)
4864 {
4865 begin = read_8ubyte_unaligned_inc (dbg, readp);
4866 end = read_8ubyte_unaligned_inc (dbg, readp);
4867 }
4868 else
4869 {
4870 begin = read_4ubyte_unaligned_inc (dbg, readp);
4871 end = read_4ubyte_unaligned_inc (dbg, readp);
4872 if (begin == (Dwarf_Addr) (uint32_t) -1)
4873 begin = (Dwarf_Addr) -1l;
4874 }
4875
4876 if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
4877 {
Elliott Hughes03333822015-02-18 22:19:45 -08004878 char *b = format_dwarf_addr (dwflmod, address_size, end, end);
Ben Cheng25b3c042013-11-20 14:45:36 -08004879 printf (gettext (" [%6tx] base address %s\n"), offset, b);
4880 free (b);
Elliott Hughes03333822015-02-18 22:19:45 -08004881 base = end;
Ben Cheng25b3c042013-11-20 14:45:36 -08004882 }
4883 else if (begin == 0 && end == 0) /* End of list entry. */
4884 {
4885 if (first)
4886 printf (gettext (" [%6tx] empty list\n"), offset);
4887 first = true;
4888 }
4889 else
4890 {
Elliott Hughes03333822015-02-18 22:19:45 -08004891 char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
4892 begin);
4893 char *e = format_dwarf_addr (dwflmod, address_size, base + end,
4894 end);
Ben Cheng25b3c042013-11-20 14:45:36 -08004895 /* We have an address range entry. */
4896 if (first) /* First address range entry in a list. */
4897 printf (gettext (" [%6tx] %s..%s\n"), offset, b, e);
4898 else
4899 printf (gettext (" %s..%s\n"), b, e);
4900 free (b);
4901 free (e);
4902
4903 first = false;
4904 }
4905 }
4906}
4907
4908#define REGNAMESZ 16
4909static const char *
4910register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc,
4911 char name[REGNAMESZ], int *bits, int *type)
4912{
4913 const char *set;
4914 const char *pfx;
4915 int ignore;
4916 ssize_t n = ebl_register_info (ebl, regno, name, REGNAMESZ, &pfx, &set,
4917 bits ?: &ignore, type ?: &ignore);
4918 if (n <= 0)
4919 {
Elliott Hughes03333822015-02-18 22:19:45 -08004920 if (loc != NULL)
4921 snprintf (name, REGNAMESZ, "reg%u", loc->regno);
4922 else
4923 snprintf (name, REGNAMESZ, "??? 0x%x", regno);
Ben Cheng25b3c042013-11-20 14:45:36 -08004924 if (bits != NULL)
Elliott Hughes03333822015-02-18 22:19:45 -08004925 *bits = loc != NULL ? loc->bits : 0;
Ben Cheng25b3c042013-11-20 14:45:36 -08004926 if (type != NULL)
4927 *type = DW_ATE_unsigned;
4928 set = "??? unrecognized";
4929 }
4930 else
4931 {
4932 if (bits != NULL && *bits <= 0)
Elliott Hughes03333822015-02-18 22:19:45 -08004933 *bits = loc != NULL ? loc->bits : 0;
Ben Cheng25b3c042013-11-20 14:45:36 -08004934 if (type != NULL && *type == DW_ATE_void)
4935 *type = DW_ATE_unsigned;
4936
4937 }
4938 return set;
4939}
4940
4941static void
4942print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
4943 Dwarf_Word vma_base, unsigned int code_align,
4944 int data_align,
4945 unsigned int version, unsigned int ptr_size,
4946 Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
4947{
4948 char regnamebuf[REGNAMESZ];
4949 const char *regname (unsigned int regno)
4950 {
4951 register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
4952 return regnamebuf;
4953 }
4954
4955 puts ("\n Program:");
4956 Dwarf_Word pc = vma_base;
4957 while (readp < endp)
4958 {
4959 unsigned int opcode = *readp++;
4960
4961 if (opcode < DW_CFA_advance_loc)
4962 /* Extended opcode. */
4963 switch (opcode)
4964 {
4965 uint64_t op1;
4966 int64_t sop1;
4967 uint64_t op2;
4968 int64_t sop2;
4969
4970 case DW_CFA_nop:
4971 puts (" nop");
4972 break;
4973 case DW_CFA_set_loc:
Elliott Hughes03333822015-02-18 22:19:45 -08004974 if ((uint64_t) (endp - readp) < 1)
4975 goto invalid;
4976 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08004977 op1 += vma_base;
4978 printf (" set_loc %" PRIu64 "\n", op1 * code_align);
4979 break;
4980 case DW_CFA_advance_loc1:
Elliott Hughes03333822015-02-18 22:19:45 -08004981 if ((uint64_t) (endp - readp) < 1)
4982 goto invalid;
Ben Cheng25b3c042013-11-20 14:45:36 -08004983 printf (" advance_loc1 %u to %#" PRIx64 "\n",
4984 *readp, pc += *readp * code_align);
4985 ++readp;
4986 break;
4987 case DW_CFA_advance_loc2:
Elliott Hughes03333822015-02-18 22:19:45 -08004988 if ((uint64_t) (endp - readp) < 2)
4989 goto invalid;
Ben Cheng25b3c042013-11-20 14:45:36 -08004990 op1 = read_2ubyte_unaligned_inc (dbg, readp);
4991 printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n",
4992 op1, pc += op1 * code_align);
4993 break;
4994 case DW_CFA_advance_loc4:
Elliott Hughes03333822015-02-18 22:19:45 -08004995 if ((uint64_t) (endp - readp) < 4)
4996 goto invalid;
Ben Cheng25b3c042013-11-20 14:45:36 -08004997 op1 = read_4ubyte_unaligned_inc (dbg, readp);
4998 printf (" advance_loc4 %" PRIu64 " to %#" PRIx64 "\n",
4999 op1, pc += op1 * code_align);
5000 break;
5001 case DW_CFA_offset_extended:
Elliott Hughes03333822015-02-18 22:19:45 -08005002 if ((uint64_t) (endp - readp) < 1)
5003 goto invalid;
5004 get_uleb128 (op1, readp, endp);
5005 if ((uint64_t) (endp - readp) < 1)
5006 goto invalid;
5007 get_uleb128 (op2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005008 printf (" offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64
5009 "\n",
5010 op1, regname (op1), op2 * data_align);
5011 break;
5012 case DW_CFA_restore_extended:
Elliott Hughes03333822015-02-18 22:19:45 -08005013 if ((uint64_t) (endp - readp) < 1)
5014 goto invalid;
5015 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005016 printf (" restore_extended r%" PRIu64 " (%s)\n",
5017 op1, regname (op1));
5018 break;
5019 case DW_CFA_undefined:
Elliott Hughes03333822015-02-18 22:19:45 -08005020 if ((uint64_t) (endp - readp) < 1)
5021 goto invalid;
5022 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005023 printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1));
5024 break;
5025 case DW_CFA_same_value:
Elliott Hughes03333822015-02-18 22:19:45 -08005026 if ((uint64_t) (endp - readp) < 1)
5027 goto invalid;
5028 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005029 printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1));
5030 break;
5031 case DW_CFA_register:
Elliott Hughes03333822015-02-18 22:19:45 -08005032 if ((uint64_t) (endp - readp) < 1)
5033 goto invalid;
5034 get_uleb128 (op1, readp, endp);
5035 if ((uint64_t) (endp - readp) < 1)
5036 goto invalid;
5037 get_uleb128 (op2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005038 printf (" register r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n",
5039 op1, regname (op1), op2, regname (op2));
5040 break;
5041 case DW_CFA_remember_state:
5042 puts (" remember_state");
5043 break;
5044 case DW_CFA_restore_state:
5045 puts (" restore_state");
5046 break;
5047 case DW_CFA_def_cfa:
Elliott Hughes03333822015-02-18 22:19:45 -08005048 if ((uint64_t) (endp - readp) < 1)
5049 goto invalid;
5050 get_uleb128 (op1, readp, endp);
5051 if ((uint64_t) (endp - readp) < 1)
5052 goto invalid;
5053 get_uleb128 (op2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005054 printf (" def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n",
5055 op1, regname (op1), op2);
5056 break;
5057 case DW_CFA_def_cfa_register:
Elliott Hughes03333822015-02-18 22:19:45 -08005058 if ((uint64_t) (endp - readp) < 1)
5059 goto invalid;
5060 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005061 printf (" def_cfa_register r%" PRIu64 " (%s)\n",
5062 op1, regname (op1));
5063 break;
5064 case DW_CFA_def_cfa_offset:
Elliott Hughes03333822015-02-18 22:19:45 -08005065 if ((uint64_t) (endp - readp) < 1)
5066 goto invalid;
5067 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005068 printf (" def_cfa_offset %" PRIu64 "\n", op1);
5069 break;
5070 case DW_CFA_def_cfa_expression:
Elliott Hughes03333822015-02-18 22:19:45 -08005071 if ((uint64_t) (endp - readp) < 1)
5072 goto invalid;
5073 get_uleb128 (op1, readp, endp); /* Length of DW_FORM_block. */
Ben Cheng25b3c042013-11-20 14:45:36 -08005074 printf (" def_cfa_expression %" PRIu64 "\n", op1);
Elliott Hughes03333822015-02-18 22:19:45 -08005075 if ((uint64_t) (endp - readp) < op1)
5076 {
5077 invalid:
5078 fputs (gettext (" <INVALID DATA>\n"), stdout);
5079 return;
5080 }
5081 print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, NULL,
5082 op1, readp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005083 readp += op1;
5084 break;
5085 case DW_CFA_expression:
Elliott Hughes03333822015-02-18 22:19:45 -08005086 if ((uint64_t) (endp - readp) < 1)
5087 goto invalid;
5088 get_uleb128 (op1, readp, endp);
5089 if ((uint64_t) (endp - readp) < 1)
5090 goto invalid;
5091 get_uleb128 (op2, readp, endp); /* Length of DW_FORM_block. */
Ben Cheng25b3c042013-11-20 14:45:36 -08005092 printf (" expression r%" PRIu64 " (%s) \n",
5093 op1, regname (op1));
Elliott Hughes03333822015-02-18 22:19:45 -08005094 if ((uint64_t) (endp - readp) < op2)
5095 goto invalid;
5096 print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, NULL,
5097 op2, readp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005098 readp += op2;
5099 break;
5100 case DW_CFA_offset_extended_sf:
Elliott Hughes03333822015-02-18 22:19:45 -08005101 if ((uint64_t) (endp - readp) < 1)
5102 goto invalid;
5103 get_uleb128 (op1, readp, endp);
5104 if ((uint64_t) (endp - readp) < 1)
5105 goto invalid;
5106 get_sleb128 (sop2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005107 printf (" offset_extended_sf r%" PRIu64 " (%s) at cfa%+"
5108 PRId64 "\n",
5109 op1, regname (op1), sop2 * data_align);
5110 break;
5111 case DW_CFA_def_cfa_sf:
Elliott Hughes03333822015-02-18 22:19:45 -08005112 if ((uint64_t) (endp - readp) < 1)
5113 goto invalid;
5114 get_uleb128 (op1, readp, endp);
5115 if ((uint64_t) (endp - readp) < 1)
5116 goto invalid;
5117 get_sleb128 (sop2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005118 printf (" def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n",
5119 op1, regname (op1), sop2 * data_align);
5120 break;
5121 case DW_CFA_def_cfa_offset_sf:
Elliott Hughes03333822015-02-18 22:19:45 -08005122 if ((uint64_t) (endp - readp) < 1)
5123 goto invalid;
5124 get_sleb128 (sop1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005125 printf (" def_cfa_offset_sf %" PRId64 "\n", sop1 * data_align);
5126 break;
5127 case DW_CFA_val_offset:
Elliott Hughes03333822015-02-18 22:19:45 -08005128 if ((uint64_t) (endp - readp) < 1)
5129 goto invalid;
5130 get_uleb128 (op1, readp, endp);
5131 if ((uint64_t) (endp - readp) < 1)
5132 goto invalid;
5133 get_uleb128 (op2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005134 printf (" val_offset %" PRIu64 " at offset %" PRIu64 "\n",
5135 op1, op2 * data_align);
5136 break;
5137 case DW_CFA_val_offset_sf:
Elliott Hughes03333822015-02-18 22:19:45 -08005138 if ((uint64_t) (endp - readp) < 1)
5139 goto invalid;
5140 get_uleb128 (op1, readp, endp);
5141 if ((uint64_t) (endp - readp) < 1)
5142 goto invalid;
5143 get_sleb128 (sop2, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005144 printf (" val_offset_sf %" PRIu64 " at offset %" PRId64 "\n",
5145 op1, sop2 * data_align);
5146 break;
5147 case DW_CFA_val_expression:
Elliott Hughes03333822015-02-18 22:19:45 -08005148 if ((uint64_t) (endp - readp) < 1)
5149 goto invalid;
5150 get_uleb128 (op1, readp, endp);
5151 if ((uint64_t) (endp - readp) < 1)
5152 goto invalid;
5153 get_uleb128 (op2, readp, endp); /* Length of DW_FORM_block. */
Ben Cheng25b3c042013-11-20 14:45:36 -08005154 printf (" val_expression r%" PRIu64 " (%s)\n",
5155 op1, regname (op1));
Elliott Hughes03333822015-02-18 22:19:45 -08005156 if ((uint64_t) (endp - readp) < op2)
5157 goto invalid;
5158 print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0,
5159 NULL, op2, readp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005160 readp += op2;
5161 break;
5162 case DW_CFA_MIPS_advance_loc8:
Elliott Hughes03333822015-02-18 22:19:45 -08005163 if ((uint64_t) (endp - readp) < 8)
5164 goto invalid;
Ben Cheng25b3c042013-11-20 14:45:36 -08005165 op1 = read_8ubyte_unaligned_inc (dbg, readp);
5166 printf (" MIPS_advance_loc8 %" PRIu64 " to %#" PRIx64 "\n",
5167 op1, pc += op1 * code_align);
5168 break;
5169 case DW_CFA_GNU_window_save:
5170 puts (" GNU_window_save");
5171 break;
5172 case DW_CFA_GNU_args_size:
Elliott Hughes03333822015-02-18 22:19:45 -08005173 if ((uint64_t) (endp - readp) < 1)
5174 goto invalid;
5175 get_uleb128 (op1, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005176 printf (" args_size %" PRIu64 "\n", op1);
5177 break;
5178 default:
5179 printf (" ??? (%u)\n", opcode);
5180 break;
5181 }
5182 else if (opcode < DW_CFA_offset)
5183 printf (" advance_loc %u to %#" PRIx64 "\n",
5184 opcode & 0x3f, pc += (opcode & 0x3f) * code_align);
5185 else if (opcode < DW_CFA_restore)
5186 {
5187 uint64_t offset;
Elliott Hughes03333822015-02-18 22:19:45 -08005188 if ((uint64_t) (endp - readp) < 1)
5189 goto invalid;
5190 get_uleb128 (offset, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005191 printf (" offset r%u (%s) at cfa%+" PRId64 "\n",
5192 opcode & 0x3f, regname (opcode & 0x3f), offset * data_align);
5193 }
5194 else
5195 printf (" restore r%u (%s)\n",
5196 opcode & 0x3f, regname (opcode & 0x3f));
5197 }
5198}
5199
5200
5201static unsigned int
5202encoded_ptr_size (int encoding, unsigned int ptr_size)
5203{
5204 switch (encoding & 7)
5205 {
Elliott Hughes03333822015-02-18 22:19:45 -08005206 case DW_EH_PE_udata4:
Ben Cheng25b3c042013-11-20 14:45:36 -08005207 return 4;
Elliott Hughes03333822015-02-18 22:19:45 -08005208 case DW_EH_PE_udata8:
Ben Cheng25b3c042013-11-20 14:45:36 -08005209 return 8;
Elliott Hughes03333822015-02-18 22:19:45 -08005210 case 0:
Ben Cheng25b3c042013-11-20 14:45:36 -08005211 return ptr_size;
5212 }
Elliott Hughes03333822015-02-18 22:19:45 -08005213
5214 fprintf (stderr, "Unsupported pointer encoding: %#x, "
5215 "assuming pointer size of %d.\n", encoding, ptr_size);
5216 return ptr_size;
Ben Cheng25b3c042013-11-20 14:45:36 -08005217}
5218
5219
5220static unsigned int
5221print_encoding (unsigned int val)
5222{
5223 switch (val & 0xf)
5224 {
5225 case DW_EH_PE_absptr:
5226 fputs ("absptr", stdout);
5227 break;
5228 case DW_EH_PE_uleb128:
5229 fputs ("uleb128", stdout);
5230 break;
5231 case DW_EH_PE_udata2:
5232 fputs ("udata2", stdout);
5233 break;
5234 case DW_EH_PE_udata4:
5235 fputs ("udata4", stdout);
5236 break;
5237 case DW_EH_PE_udata8:
5238 fputs ("udata8", stdout);
5239 break;
5240 case DW_EH_PE_sleb128:
5241 fputs ("sleb128", stdout);
5242 break;
5243 case DW_EH_PE_sdata2:
5244 fputs ("sdata2", stdout);
5245 break;
5246 case DW_EH_PE_sdata4:
5247 fputs ("sdata4", stdout);
5248 break;
5249 case DW_EH_PE_sdata8:
5250 fputs ("sdata8", stdout);
5251 break;
5252 default:
5253 /* We did not use any of the bits after all. */
5254 return val;
5255 }
5256
5257 return val & ~0xf;
5258}
5259
5260
5261static unsigned int
5262print_relinfo (unsigned int val)
5263{
5264 switch (val & 0x70)
5265 {
5266 case DW_EH_PE_pcrel:
5267 fputs ("pcrel", stdout);
5268 break;
5269 case DW_EH_PE_textrel:
5270 fputs ("textrel", stdout);
5271 break;
5272 case DW_EH_PE_datarel:
5273 fputs ("datarel", stdout);
5274 break;
5275 case DW_EH_PE_funcrel:
5276 fputs ("funcrel", stdout);
5277 break;
5278 case DW_EH_PE_aligned:
5279 fputs ("aligned", stdout);
5280 break;
5281 default:
5282 return val;
5283 }
5284
5285 return val & ~0x70;
5286}
5287
5288
5289static void
5290print_encoding_base (const char *pfx, unsigned int fde_encoding)
5291{
5292 printf ("(%s", pfx);
5293
5294 if (fde_encoding == DW_EH_PE_omit)
5295 puts ("omit)");
5296 else
5297 {
5298 unsigned int w = fde_encoding;
5299
5300 w = print_encoding (w);
5301
5302 if (w & 0x70)
5303 {
5304 if (w != fde_encoding)
5305 fputc_unlocked (' ', stdout);
5306
5307 w = print_relinfo (w);
5308 }
5309
5310 if (w != 0)
5311 printf ("%s%x", w != fde_encoding ? " " : "", w);
5312
5313 puts (")");
5314 }
5315}
5316
5317
5318static const unsigned char *
5319read_encoded (unsigned int encoding, const unsigned char *readp,
5320 const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
5321{
5322 if ((encoding & 0xf) == DW_EH_PE_absptr)
5323 encoding = gelf_getclass (dbg->elf) == ELFCLASS32
5324 ? DW_EH_PE_udata4 : DW_EH_PE_udata8;
5325
5326 switch (encoding & 0xf)
5327 {
5328 case DW_EH_PE_uleb128:
Elliott Hughes03333822015-02-18 22:19:45 -08005329 get_uleb128 (*res, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005330 break;
5331 case DW_EH_PE_sleb128:
Elliott Hughes03333822015-02-18 22:19:45 -08005332 get_sleb128 (*res, readp, endp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005333 break;
5334 case DW_EH_PE_udata2:
5335 if (readp + 2 > endp)
5336 goto invalid;
5337 *res = read_2ubyte_unaligned_inc (dbg, readp);
5338 break;
5339 case DW_EH_PE_udata4:
5340 if (readp + 4 > endp)
5341 goto invalid;
5342 *res = read_4ubyte_unaligned_inc (dbg, readp);
5343 break;
5344 case DW_EH_PE_udata8:
5345 if (readp + 8 > endp)
5346 goto invalid;
5347 *res = read_8ubyte_unaligned_inc (dbg, readp);
5348 break;
5349 case DW_EH_PE_sdata2:
5350 if (readp + 2 > endp)
5351 goto invalid;
5352 *res = read_2sbyte_unaligned_inc (dbg, readp);
5353 break;
5354 case DW_EH_PE_sdata4:
5355 if (readp + 4 > endp)
5356 goto invalid;
5357 *res = read_4sbyte_unaligned_inc (dbg, readp);
5358 break;
5359 case DW_EH_PE_sdata8:
5360 if (readp + 8 > endp)
5361 goto invalid;
5362 *res = read_8sbyte_unaligned_inc (dbg, readp);
5363 break;
5364 default:
5365 invalid:
5366 error (1, 0,
5367 gettext ("invalid encoding"));
5368 }
5369
5370 return readp;
5371}
5372
5373
5374static void
5375print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
5376 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5377{
5378 size_t shstrndx;
5379 /* We know this call will succeed since it did in the caller. */
5380 (void) elf_getshdrstrndx (ebl->elf, &shstrndx);
5381 const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
5382
Elliott Hughes03333822015-02-18 22:19:45 -08005383 /* Needed if we find PC-relative addresses. */
5384 GElf_Addr bias;
5385 if (dwfl_module_getelf (dwflmod, &bias) == NULL)
5386 {
5387 error (0, 0, gettext ("cannot get ELF: %s"), dwfl_errmsg (-1));
5388 return;
5389 }
5390
5391 bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0;
5392 Elf_Data *data = (is_eh_frame
5393 ? elf_rawdata (scn, NULL)
5394 : dbg->sectiondata[IDX_debug_frame]);
Ben Cheng25b3c042013-11-20 14:45:36 -08005395
5396 if (unlikely (data == NULL))
5397 {
5398 error (0, 0, gettext ("cannot get %s content: %s"),
5399 scnname, elf_errmsg (-1));
5400 return;
5401 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005402
5403 if (is_eh_frame)
5404 printf (gettext ("\
5405\nCall frame information section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5406 elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
5407 else
5408 printf (gettext ("\
5409\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5410 elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
5411
5412 struct cieinfo
5413 {
5414 ptrdiff_t cie_offset;
5415 const char *augmentation;
5416 unsigned int code_alignment_factor;
5417 unsigned int data_alignment_factor;
5418 uint8_t address_size;
5419 uint8_t fde_encoding;
5420 uint8_t lsda_encoding;
5421 struct cieinfo *next;
5422 } *cies = NULL;
5423
5424 const unsigned char *readp = data->d_buf;
5425 const unsigned char *const dataend = ((unsigned char *) data->d_buf
5426 + data->d_size);
5427 while (readp < dataend)
5428 {
5429 if (unlikely (readp + 4 > dataend))
5430 {
5431 invalid_data:
5432 error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
5433 elf_ndxscn (scn), scnname);
5434 return;
5435 }
5436
5437 /* At the beginning there must be a CIE. There can be multiple,
5438 hence we test tis in a loop. */
5439 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
5440
5441 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp);
5442 unsigned int length = 4;
5443 if (unlikely (unit_length == 0xffffffff))
5444 {
5445 if (unlikely (readp + 8 > dataend))
5446 goto invalid_data;
5447
5448 unit_length = read_8ubyte_unaligned_inc (dbg, readp);
5449 length = 8;
5450 }
5451
5452 if (unlikely (unit_length == 0))
5453 {
5454 printf (gettext ("\n [%6tx] Zero terminator\n"), offset);
5455 continue;
5456 }
5457
Elliott Hughes03333822015-02-18 22:19:45 -08005458 Dwarf_Word maxsize = dataend - readp;
5459 if (unlikely (unit_length > maxsize))
5460 goto invalid_data;
5461
Ben Cheng25b3c042013-11-20 14:45:36 -08005462 unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
5463
5464 ptrdiff_t start = readp - (unsigned char *) data->d_buf;
5465 const unsigned char *const cieend = readp + unit_length;
5466 if (unlikely (cieend > dataend || readp + 8 > dataend))
5467 goto invalid_data;
5468
5469 Dwarf_Off cie_id;
5470 if (length == 4)
5471 {
5472 cie_id = read_4ubyte_unaligned_inc (dbg, readp);
5473 if (!is_eh_frame && cie_id == DW_CIE_ID_32)
5474 cie_id = DW_CIE_ID_64;
5475 }
5476 else
5477 cie_id = read_8ubyte_unaligned_inc (dbg, readp);
5478
5479 uint_fast8_t version = 2;
5480 unsigned int code_alignment_factor;
5481 int data_alignment_factor;
5482 unsigned int fde_encoding = 0;
5483 unsigned int lsda_encoding = 0;
5484 Dwarf_Word initial_location = 0;
5485 Dwarf_Word vma_base = 0;
5486
5487 if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID_64))
5488 {
5489 version = *readp++;
5490 const char *const augmentation = (const char *) readp;
5491 readp = memchr (readp, '\0', cieend - readp);
5492 if (unlikely (readp == NULL))
5493 goto invalid_data;
5494 ++readp;
5495
5496 uint_fast8_t segment_size = 0;
5497 if (version >= 4)
5498 {
5499 if (cieend - readp < 5)
5500 goto invalid_data;
5501 ptr_size = *readp++;
5502 segment_size = *readp++;
5503 }
5504
Elliott Hughes03333822015-02-18 22:19:45 -08005505 if (cieend - readp < 1)
5506 goto invalid_data;
5507 get_uleb128 (code_alignment_factor, readp, cieend);
5508 if (cieend - readp < 1)
5509 goto invalid_data;
5510 get_sleb128 (data_alignment_factor, readp, cieend);
Ben Cheng25b3c042013-11-20 14:45:36 -08005511
5512 /* In some variant for unwind data there is another field. */
5513 if (strcmp (augmentation, "eh") == 0)
5514 readp += ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
5515
5516 unsigned int return_address_register;
Elliott Hughes03333822015-02-18 22:19:45 -08005517 if (cieend - readp < 1)
5518 goto invalid_data;
Ben Cheng25b3c042013-11-20 14:45:36 -08005519 if (unlikely (version == 1))
5520 return_address_register = *readp++;
5521 else
Elliott Hughes03333822015-02-18 22:19:45 -08005522 get_uleb128 (return_address_register, readp, cieend);
Ben Cheng25b3c042013-11-20 14:45:36 -08005523
5524 printf ("\n [%6tx] CIE length=%" PRIu64 "\n"
5525 " CIE_id: %" PRIu64 "\n"
5526 " version: %u\n"
5527 " augmentation: \"%s\"\n",
5528 offset, (uint64_t) unit_length, (uint64_t) cie_id,
5529 version, augmentation);
5530 if (version >= 4)
5531 printf (" address_size: %u\n"
5532 " segment_size: %u\n",
5533 ptr_size, segment_size);
5534 printf (" code_alignment_factor: %u\n"
5535 " data_alignment_factor: %d\n"
5536 " return_address_register: %u\n",
5537 code_alignment_factor,
5538 data_alignment_factor, return_address_register);
5539
5540 if (augmentation[0] == 'z')
5541 {
5542 unsigned int augmentationlen;
Elliott Hughes03333822015-02-18 22:19:45 -08005543 get_uleb128 (augmentationlen, readp, cieend);
Ben Cheng25b3c042013-11-20 14:45:36 -08005544
Elliott Hughes03333822015-02-18 22:19:45 -08005545 if (augmentationlen > (size_t) (cieend - readp))
5546 {
5547 error (0, 0, gettext ("invalid augmentation length"));
5548 readp = cieend;
5549 continue;
5550 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005551
5552 const char *hdr = "Augmentation data:";
5553 const char *cp = augmentation + 1;
Elliott Hughes03333822015-02-18 22:19:45 -08005554 while (*cp != '\0' && cp < augmentation + augmentationlen + 1)
Ben Cheng25b3c042013-11-20 14:45:36 -08005555 {
5556 printf (" %-26s%#x ", hdr, *readp);
5557 hdr = "";
5558
5559 if (*cp == 'R')
5560 {
5561 fde_encoding = *readp++;
5562 print_encoding_base (gettext ("FDE address encoding: "),
5563 fde_encoding);
5564 }
5565 else if (*cp == 'L')
5566 {
5567 lsda_encoding = *readp++;
5568 print_encoding_base (gettext ("LSDA pointer encoding: "),
5569 lsda_encoding);
5570 }
5571 else if (*cp == 'P')
5572 {
5573 /* Personality. This field usually has a relocation
5574 attached pointing to __gcc_personality_v0. */
5575 const unsigned char *startp = readp;
5576 unsigned int encoding = *readp++;
5577 uint64_t val = 0;
5578 readp = read_encoded (encoding, readp,
5579 readp - 1 + augmentationlen,
5580 &val, dbg);
5581
5582 while (++startp < readp)
5583 printf ("%#x ", *startp);
5584
5585 putchar ('(');
5586 print_encoding (encoding);
5587 putchar (' ');
5588 switch (encoding & 0xf)
5589 {
5590 case DW_EH_PE_sleb128:
5591 case DW_EH_PE_sdata2:
5592 case DW_EH_PE_sdata4:
5593 printf ("%" PRId64 ")\n", val);
5594 break;
5595 default:
5596 printf ("%#" PRIx64 ")\n", val);
5597 break;
5598 }
5599 }
5600 else
5601 printf ("(%x)\n", *readp++);
5602
5603 ++cp;
5604 }
5605 }
5606
5607 if (likely (ptr_size == 4 || ptr_size == 8))
5608 {
5609 struct cieinfo *newp = alloca (sizeof (*newp));
5610 newp->cie_offset = offset;
5611 newp->augmentation = augmentation;
5612 newp->fde_encoding = fde_encoding;
5613 newp->lsda_encoding = lsda_encoding;
5614 newp->address_size = ptr_size;
5615 newp->code_alignment_factor = code_alignment_factor;
5616 newp->data_alignment_factor = data_alignment_factor;
5617 newp->next = cies;
5618 cies = newp;
5619 }
5620 }
5621 else
5622 {
5623 struct cieinfo *cie = cies;
5624 while (cie != NULL)
5625 if (is_eh_frame
5626 ? start - (ptrdiff_t) cie_id == cie->cie_offset
5627 : (ptrdiff_t) cie_id == cie->cie_offset)
5628 break;
5629 else
5630 cie = cie->next;
5631 if (unlikely (cie == NULL))
5632 {
5633 puts ("invalid CIE reference in FDE");
5634 return;
5635 }
5636
5637 /* Initialize from CIE data. */
5638 fde_encoding = cie->fde_encoding;
5639 lsda_encoding = cie->lsda_encoding;
5640 ptr_size = encoded_ptr_size (fde_encoding, cie->address_size);
5641 code_alignment_factor = cie->code_alignment_factor;
5642 data_alignment_factor = cie->data_alignment_factor;
5643
5644 const unsigned char *base = readp;
5645 // XXX There are sometimes relocations for this value
Elliott Hughes03333822015-02-18 22:19:45 -08005646 initial_location = read_addr_unaligned_inc (ptr_size, dbg, readp);
Ben Cheng25b3c042013-11-20 14:45:36 -08005647 Dwarf_Word address_range
Elliott Hughes03333822015-02-18 22:19:45 -08005648 = read_addr_unaligned_inc (ptr_size, dbg, readp);
5649
5650 /* pcrel for an FDE address is relative to the runtime
5651 address of the start_address field itself. Sign extend
5652 if necessary to make sure the calculation is done on the
5653 full 64 bit address even when initial_location only holds
5654 the lower 32 bits. */
5655 Dwarf_Addr pc_start = initial_location;
5656 if (ptr_size == 4)
5657 pc_start = (uint64_t) (int32_t) pc_start;
5658 if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
5659 pc_start += ((uint64_t) shdr->sh_addr
5660 + (base - (const unsigned char *) data->d_buf)
5661 - bias);
Ben Cheng25b3c042013-11-20 14:45:36 -08005662
5663 char *a = format_dwarf_addr (dwflmod, cie->address_size,
Elliott Hughes03333822015-02-18 22:19:45 -08005664 pc_start, initial_location);
Ben Cheng25b3c042013-11-20 14:45:36 -08005665 printf ("\n [%6tx] FDE length=%" PRIu64 " cie=[%6tx]\n"
5666 " CIE_pointer: %" PRIu64 "\n"
5667 " initial_location: %s",
5668 offset, (uint64_t) unit_length,
5669 cie->cie_offset, (uint64_t) cie_id, a);
5670 free (a);
5671 if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
5672 {
5673 vma_base = (((uint64_t) shdr->sh_offset
5674 + (base - (const unsigned char *) data->d_buf)
5675 + (uint64_t) initial_location)
5676 & (ptr_size == 4
5677 ? UINT64_C (0xffffffff)
5678 : UINT64_C (0xffffffffffffffff)));
5679 printf (gettext (" (offset: %#" PRIx64 ")"),
5680 (uint64_t) vma_base);
5681 }
5682
5683 printf ("\n address_range: %#" PRIx64,
5684 (uint64_t) address_range);
5685 if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
5686 printf (gettext (" (end offset: %#" PRIx64 ")"),
5687 ((uint64_t) vma_base + (uint64_t) address_range)
5688 & (ptr_size == 4
5689 ? UINT64_C (0xffffffff)
5690 : UINT64_C (0xffffffffffffffff)));
5691 putchar ('\n');
5692
5693 if (cie->augmentation[0] == 'z')
5694 {
5695 unsigned int augmentationlen;
Elliott Hughes03333822015-02-18 22:19:45 -08005696 if (cieend - readp < 1)
5697 goto invalid_data;
5698 get_uleb128 (augmentationlen, readp, cieend);
5699
5700 if (augmentationlen > (size_t) (cieend - readp))
5701 {
5702 error (0, 0, gettext ("invalid augmentation length"));
5703 readp = cieend;
5704 continue;
5705 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005706
5707 if (augmentationlen > 0)
5708 {
5709 const char *hdr = "Augmentation data:";
5710 const char *cp = cie->augmentation + 1;
5711 unsigned int u = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08005712 while (*cp != '\0'
5713 && cp < cie->augmentation + augmentationlen + 1)
Ben Cheng25b3c042013-11-20 14:45:36 -08005714 {
5715 if (*cp == 'L')
5716 {
5717 uint64_t lsda_pointer;
5718 const unsigned char *p
5719 = read_encoded (lsda_encoding, &readp[u],
5720 &readp[augmentationlen],
5721 &lsda_pointer, dbg);
5722 u = p - readp;
5723 printf (gettext ("\
5724 %-26sLSDA pointer: %#" PRIx64 "\n"),
5725 hdr, lsda_pointer);
5726 hdr = "";
5727 }
5728 ++cp;
5729 }
5730
5731 while (u < augmentationlen)
5732 {
5733 printf (" %-26s%#x\n", hdr, readp[u++]);
5734 hdr = "";
5735 }
5736 }
5737
5738 readp += augmentationlen;
5739 }
5740 }
5741
5742 /* Handle the initialization instructions. */
Elliott Hughes03333822015-02-18 22:19:45 -08005743 if (ptr_size != 4 && ptr_size !=8)
5744 printf ("invalid CIE pointer size (%u), must be 4 or 8.\n", ptr_size);
5745 else
5746 print_cfa_program (readp, cieend, vma_base, code_alignment_factor,
5747 data_alignment_factor, version, ptr_size,
5748 dwflmod, ebl, dbg);
Ben Cheng25b3c042013-11-20 14:45:36 -08005749 readp = cieend;
5750 }
5751}
5752
5753
5754struct attrcb_args
5755{
5756 Dwfl_Module *dwflmod;
5757 Dwarf *dbg;
Elliott Hughes03333822015-02-18 22:19:45 -08005758 Dwarf_Die *die;
Ben Cheng25b3c042013-11-20 14:45:36 -08005759 int level;
5760 bool silent;
5761 unsigned int version;
5762 unsigned int addrsize;
5763 unsigned int offset_size;
Elliott Hughes03333822015-02-18 22:19:45 -08005764 struct Dwarf_CU *cu;
Ben Cheng25b3c042013-11-20 14:45:36 -08005765};
5766
5767
5768static int
5769attr_callback (Dwarf_Attribute *attrp, void *arg)
5770{
5771 struct attrcb_args *cbargs = (struct attrcb_args *) arg;
5772 const int level = cbargs->level;
5773
5774 unsigned int attr = dwarf_whatattr (attrp);
5775 if (unlikely (attr == 0))
5776 {
5777 if (!cbargs->silent)
5778 error (0, 0, gettext ("cannot get attribute code: %s"),
5779 dwarf_errmsg (-1));
5780 return DWARF_CB_ABORT;
5781 }
5782
5783 unsigned int form = dwarf_whatform (attrp);
5784 if (unlikely (form == 0))
5785 {
5786 if (!cbargs->silent)
5787 error (0, 0, gettext ("cannot get attribute form: %s"),
5788 dwarf_errmsg (-1));
5789 return DWARF_CB_ABORT;
5790 }
5791
5792 switch (form)
5793 {
5794 case DW_FORM_addr:
5795 if (!cbargs->silent)
5796 {
5797 Dwarf_Addr addr;
5798 if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
5799 {
5800 attrval_out:
5801 if (!cbargs->silent)
5802 error (0, 0, gettext ("cannot get attribute value: %s"),
5803 dwarf_errmsg (-1));
5804 return DWARF_CB_ABORT;
5805 }
Elliott Hughes03333822015-02-18 22:19:45 -08005806 char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize,
5807 addr, addr);
Ben Cheng25b3c042013-11-20 14:45:36 -08005808 printf (" %*s%-20s (%s) %s\n",
Elliott Hughes03333822015-02-18 22:19:45 -08005809 (int) (level * 2), "", dwarf_attr_name (attr),
5810 dwarf_form_name (form), a);
Ben Cheng25b3c042013-11-20 14:45:36 -08005811 free (a);
5812 }
5813 break;
5814
5815 case DW_FORM_indirect:
5816 case DW_FORM_strp:
5817 case DW_FORM_string:
Elliott Hughes03333822015-02-18 22:19:45 -08005818 case DW_FORM_GNU_strp_alt:
Ben Cheng25b3c042013-11-20 14:45:36 -08005819 if (cbargs->silent)
5820 break;
5821 const char *str = dwarf_formstring (attrp);
5822 if (unlikely (str == NULL))
5823 goto attrval_out;
5824 printf (" %*s%-20s (%s) \"%s\"\n",
Elliott Hughes03333822015-02-18 22:19:45 -08005825 (int) (level * 2), "", dwarf_attr_name (attr),
5826 dwarf_form_name (form), str);
Ben Cheng25b3c042013-11-20 14:45:36 -08005827 break;
5828
5829 case DW_FORM_ref_addr:
5830 case DW_FORM_ref_udata:
5831 case DW_FORM_ref8:
5832 case DW_FORM_ref4:
5833 case DW_FORM_ref2:
Elliott Hughes03333822015-02-18 22:19:45 -08005834 case DW_FORM_ref1:
5835 case DW_FORM_GNU_ref_alt:
Ben Cheng25b3c042013-11-20 14:45:36 -08005836 if (cbargs->silent)
5837 break;
5838 Dwarf_Die ref;
5839 if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
5840 goto attrval_out;
5841
5842 printf (" %*s%-20s (%s) [%6" PRIxMAX "]\n",
Elliott Hughes03333822015-02-18 22:19:45 -08005843 (int) (level * 2), "", dwarf_attr_name (attr),
5844 dwarf_form_name (form), (uintmax_t) dwarf_dieoffset (&ref));
Ben Cheng25b3c042013-11-20 14:45:36 -08005845 break;
5846
5847 case DW_FORM_ref_sig8:
5848 if (cbargs->silent)
5849 break;
5850 printf (" %*s%-20s (%s) {%6" PRIx64 "}\n",
Elliott Hughes03333822015-02-18 22:19:45 -08005851 (int) (level * 2), "", dwarf_attr_name (attr),
5852 dwarf_form_name (form),
5853 (uint64_t) read_8ubyte_unaligned (attrp->cu->dbg, attrp->valp));
Ben Cheng25b3c042013-11-20 14:45:36 -08005854 break;
5855
5856 case DW_FORM_sec_offset:
5857 case DW_FORM_udata:
5858 case DW_FORM_sdata:
5859 case DW_FORM_data8:
5860 case DW_FORM_data4:
5861 case DW_FORM_data2:
5862 case DW_FORM_data1:;
5863 Dwarf_Word num;
5864 if (unlikely (dwarf_formudata (attrp, &num) != 0))
5865 goto attrval_out;
5866
5867 const char *valuestr = NULL;
5868 switch (attr)
5869 {
5870 /* This case can take either a constant or a loclistptr. */
5871 case DW_AT_data_member_location:
5872 if (form != DW_FORM_sec_offset
5873 && (cbargs->version >= 4
5874 || (form != DW_FORM_data4 && form != DW_FORM_data8)))
5875 {
5876 if (!cbargs->silent)
5877 printf (" %*s%-20s (%s) %" PRIxMAX "\n",
Elliott Hughes03333822015-02-18 22:19:45 -08005878 (int) (level * 2), "", dwarf_attr_name (attr),
5879 dwarf_form_name (form), (uintmax_t) num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005880 return DWARF_CB_OK;
5881 }
5882 /* else fallthrough */
5883
5884 /* These cases always take a loclistptr and no constant. */
5885 case DW_AT_location:
5886 case DW_AT_data_location:
5887 case DW_AT_vtable_elem_location:
5888 case DW_AT_string_length:
5889 case DW_AT_use_location:
5890 case DW_AT_frame_base:
5891 case DW_AT_return_addr:
5892 case DW_AT_static_link:
5893 case DW_AT_GNU_call_site_value:
5894 case DW_AT_GNU_call_site_data_value:
5895 case DW_AT_GNU_call_site_target:
5896 case DW_AT_GNU_call_site_target_clobbered:
Elliott Hughes03333822015-02-18 22:19:45 -08005897 {
5898 bool nlpt = notice_listptr (section_loc, &known_loclistptr,
5899 cbargs->addrsize, cbargs->offset_size,
5900 cbargs->cu, num);
5901 if (!cbargs->silent)
5902 printf (" %*s%-20s (%s) location list [%6" PRIxMAX "]%s\n",
5903 (int) (level * 2), "", dwarf_attr_name (attr),
5904 dwarf_form_name (form), (uintmax_t) num,
5905 nlpt ? "" : " <WARNING offset too big>");
5906 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005907 return DWARF_CB_OK;
5908
5909 case DW_AT_ranges:
Elliott Hughes03333822015-02-18 22:19:45 -08005910 {
5911 bool nlpt = notice_listptr (section_ranges, &known_rangelistptr,
5912 cbargs->addrsize, cbargs->offset_size,
5913 cbargs->cu, num);
5914 if (!cbargs->silent)
5915 printf (" %*s%-20s (%s) range list [%6" PRIxMAX "]%s\n",
5916 (int) (level * 2), "", dwarf_attr_name (attr),
5917 dwarf_form_name (form), (uintmax_t) num,
5918 nlpt ? "" : " <WARNING offset too big>");
5919 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005920 return DWARF_CB_OK;
5921
5922 case DW_AT_language:
Elliott Hughes03333822015-02-18 22:19:45 -08005923 valuestr = dwarf_lang_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005924 break;
5925 case DW_AT_encoding:
Elliott Hughes03333822015-02-18 22:19:45 -08005926 valuestr = dwarf_encoding_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005927 break;
5928 case DW_AT_accessibility:
Elliott Hughes03333822015-02-18 22:19:45 -08005929 valuestr = dwarf_access_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005930 break;
5931 case DW_AT_visibility:
Elliott Hughes03333822015-02-18 22:19:45 -08005932 valuestr = dwarf_visibility_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005933 break;
5934 case DW_AT_virtuality:
Elliott Hughes03333822015-02-18 22:19:45 -08005935 valuestr = dwarf_virtuality_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005936 break;
5937 case DW_AT_identifier_case:
Elliott Hughes03333822015-02-18 22:19:45 -08005938 valuestr = dwarf_identifier_case_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005939 break;
5940 case DW_AT_calling_convention:
Elliott Hughes03333822015-02-18 22:19:45 -08005941 valuestr = dwarf_calling_convention_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005942 break;
5943 case DW_AT_inline:
Elliott Hughes03333822015-02-18 22:19:45 -08005944 valuestr = dwarf_inline_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005945 break;
5946 case DW_AT_ordering:
Elliott Hughes03333822015-02-18 22:19:45 -08005947 valuestr = dwarf_ordering_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005948 break;
5949 case DW_AT_discr_list:
Elliott Hughes03333822015-02-18 22:19:45 -08005950 valuestr = dwarf_discr_list_name (num);
Ben Cheng25b3c042013-11-20 14:45:36 -08005951 break;
5952 default:
5953 /* Nothing. */
5954 break;
5955 }
5956
5957 if (cbargs->silent)
5958 break;
5959
Elliott Hughes03333822015-02-18 22:19:45 -08005960 /* When highpc is in constant form it is relative to lowpc.
5961 In that case also show the address. */
5962 Dwarf_Addr highpc;
5963 if (attr == DW_AT_high_pc && dwarf_highpc (cbargs->die, &highpc) == 0)
5964 {
5965 char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize,
5966 highpc, highpc);
5967 printf (" %*s%-20s (%s) %" PRIuMAX " (%s)\n",
5968 (int) (level * 2), "", dwarf_attr_name (attr),
5969 dwarf_form_name (form), (uintmax_t) num, a);
5970 free (a);
5971 }
Ben Cheng25b3c042013-11-20 14:45:36 -08005972 else
Elliott Hughes03333822015-02-18 22:19:45 -08005973 {
5974 Dwarf_Sword snum = 0;
5975 if (form == DW_FORM_sdata)
5976 if (unlikely (dwarf_formsdata (attrp, &snum) != 0))
5977 goto attrval_out;
5978
5979 if (valuestr == NULL)
5980 {
5981 printf (" %*s%-20s (%s)",
5982 (int) (level * 2), "", dwarf_attr_name (attr),
5983 dwarf_form_name (form));
5984 if (form == DW_FORM_sdata)
5985 printf (" %" PRIdMAX "\n", (intmax_t) snum);
5986 else
5987 printf (" %" PRIuMAX "\n", (uintmax_t) num);
5988 }
5989 else
5990 {
5991 printf (" %*s%-20s (%s) %s",
5992 (int) (level * 2), "", dwarf_attr_name (attr),
5993 dwarf_form_name (form), valuestr);
5994 if (form == DW_FORM_sdata)
5995 printf (" (%" PRIdMAX ")\n", (intmax_t) snum);
5996 else
5997 printf (" (%" PRIuMAX ")\n", (uintmax_t) num);
5998 }
5999 }
Ben Cheng25b3c042013-11-20 14:45:36 -08006000 break;
6001
6002 case DW_FORM_flag:
6003 if (cbargs->silent)
6004 break;
6005 bool flag;
6006 if (unlikely (dwarf_formflag (attrp, &flag) != 0))
6007 goto attrval_out;
6008
6009 printf (" %*s%-20s (%s) %s\n",
Elliott Hughes03333822015-02-18 22:19:45 -08006010 (int) (level * 2), "", dwarf_attr_name (attr),
6011 dwarf_form_name (form), nl_langinfo (flag ? YESSTR : NOSTR));
Ben Cheng25b3c042013-11-20 14:45:36 -08006012 break;
6013
6014 case DW_FORM_flag_present:
6015 if (cbargs->silent)
6016 break;
6017 printf (" %*s%-20s (%s) %s\n",
Elliott Hughes03333822015-02-18 22:19:45 -08006018 (int) (level * 2), "", dwarf_attr_name (attr),
6019 dwarf_form_name (form), nl_langinfo (YESSTR));
Ben Cheng25b3c042013-11-20 14:45:36 -08006020 break;
6021
6022 case DW_FORM_exprloc:
6023 case DW_FORM_block4:
6024 case DW_FORM_block2:
6025 case DW_FORM_block1:
6026 case DW_FORM_block:
6027 if (cbargs->silent)
6028 break;
6029 Dwarf_Block block;
6030 if (unlikely (dwarf_formblock (attrp, &block) != 0))
6031 goto attrval_out;
6032
6033 printf (" %*s%-20s (%s) ",
Elliott Hughes03333822015-02-18 22:19:45 -08006034 (int) (level * 2), "", dwarf_attr_name (attr),
6035 dwarf_form_name (form));
Ben Cheng25b3c042013-11-20 14:45:36 -08006036
6037 switch (attr)
6038 {
6039 default:
6040 if (form != DW_FORM_exprloc)
6041 {
6042 print_block (block.length, block.data);
6043 break;
6044 }
6045 /* Fall through. */
6046
6047 case DW_AT_location:
6048 case DW_AT_data_location:
6049 case DW_AT_data_member_location:
6050 case DW_AT_vtable_elem_location:
6051 case DW_AT_string_length:
6052 case DW_AT_use_location:
6053 case DW_AT_frame_base:
6054 case DW_AT_return_addr:
6055 case DW_AT_static_link:
6056 case DW_AT_allocated:
6057 case DW_AT_associated:
6058 case DW_AT_bit_size:
6059 case DW_AT_bit_offset:
6060 case DW_AT_bit_stride:
6061 case DW_AT_byte_size:
6062 case DW_AT_byte_stride:
6063 case DW_AT_count:
6064 case DW_AT_lower_bound:
6065 case DW_AT_upper_bound:
6066 case DW_AT_GNU_call_site_value:
6067 case DW_AT_GNU_call_site_data_value:
6068 case DW_AT_GNU_call_site_target:
6069 case DW_AT_GNU_call_site_target_clobbered:
6070 putchar ('\n');
6071 print_ops (cbargs->dwflmod, cbargs->dbg,
6072 12 + level * 2, 12 + level * 2,
6073 cbargs->version, cbargs->addrsize, cbargs->offset_size,
Elliott Hughes03333822015-02-18 22:19:45 -08006074 attrp->cu, block.length, block.data);
Ben Cheng25b3c042013-11-20 14:45:36 -08006075 break;
6076 }
6077 break;
6078
6079 default:
6080 if (cbargs->silent)
6081 break;
6082 printf (" %*s%-20s (form: %#x) ???\n",
Elliott Hughes03333822015-02-18 22:19:45 -08006083 (int) (level * 2), "", dwarf_attr_name (attr),
Ben Cheng25b3c042013-11-20 14:45:36 -08006084 (int) form);
6085 break;
6086 }
6087
6088 return DWARF_CB_OK;
6089}
6090
6091static void
6092print_debug_units (Dwfl_Module *dwflmod,
6093 Ebl *ebl, GElf_Ehdr *ehdr,
6094 Elf_Scn *scn, GElf_Shdr *shdr,
6095 Dwarf *dbg, bool debug_types)
6096{
6097 const bool silent = !(print_debug_sections & section_info);
6098 const char *secname = section_name (ebl, ehdr, shdr);
6099
6100 if (!silent)
6101 printf (gettext ("\
6102\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"),
6103 elf_ndxscn (scn), secname, (uint64_t) shdr->sh_offset);
6104
6105 /* If the section is empty we don't have to do anything. */
6106 if (!silent && shdr->sh_size == 0)
6107 return;
6108
6109 int maxdies = 20;
6110 Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
6111
6112 Dwarf_Off offset = 0;
6113
6114 /* New compilation unit. */
6115 size_t cuhl;
6116 Dwarf_Half version;
6117 Dwarf_Off abbroffset;
6118 uint8_t addrsize;
6119 uint8_t offsize;
6120 Dwarf_Off nextcu;
6121 uint64_t typesig;
6122 Dwarf_Off typeoff;
6123 next_cu:
6124 if (dwarf_next_unit (dbg, offset, &nextcu, &cuhl, &version,
6125 &abbroffset, &addrsize, &offsize,
6126 debug_types ? &typesig : NULL,
6127 debug_types ? &typeoff : NULL) != 0)
6128 goto do_return;
6129
6130 if (!silent)
6131 {
6132 if (debug_types)
6133 printf (gettext (" Type unit at offset %" PRIu64 ":\n"
6134 " Version: %" PRIu16 ", Abbreviation section offset: %"
6135 PRIu64 ", Address size: %" PRIu8
6136 ", Offset size: %" PRIu8
6137 "\n Type signature: %#" PRIx64
6138 ", Type offset: %#" PRIx64 "\n"),
6139 (uint64_t) offset, version, abbroffset, addrsize, offsize,
6140 typesig, (uint64_t) typeoff);
6141 else
6142 printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
6143 " Version: %" PRIu16 ", Abbreviation section offset: %"
6144 PRIu64 ", Address size: %" PRIu8
6145 ", Offset size: %" PRIu8 "\n"),
6146 (uint64_t) offset, version, abbroffset, addrsize, offsize);
6147 }
6148
6149 struct attrcb_args args =
6150 {
6151 .dwflmod = dwflmod,
6152 .dbg = dbg,
6153 .silent = silent,
6154 .version = version,
6155 .addrsize = addrsize,
Elliott Hughes03333822015-02-18 22:19:45 -08006156 .offset_size = offsize
Ben Cheng25b3c042013-11-20 14:45:36 -08006157 };
6158
6159 offset += cuhl;
6160
6161 int level = 0;
6162
6163 if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie)
6164 (dbg, offset, &dies[level]) == NULL))
6165 {
6166 if (!silent)
6167 error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
6168 " in section '%s': %s"),
6169 (uint64_t) offset, secname, dwarf_errmsg (-1));
6170 goto do_return;
6171 }
6172
Elliott Hughes03333822015-02-18 22:19:45 -08006173 args.cu = dies[0].cu;
6174
Ben Cheng25b3c042013-11-20 14:45:36 -08006175 do
6176 {
6177 offset = dwarf_dieoffset (&dies[level]);
6178 if (unlikely (offset == ~0ul))
6179 {
6180 if (!silent)
6181 error (0, 0, gettext ("cannot get DIE offset: %s"),
6182 dwarf_errmsg (-1));
6183 goto do_return;
6184 }
6185
6186 int tag = dwarf_tag (&dies[level]);
6187 if (unlikely (tag == DW_TAG_invalid))
6188 {
6189 if (!silent)
6190 error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
6191 " in section '%s': %s"),
6192 (uint64_t) offset, secname, dwarf_errmsg (-1));
6193 goto do_return;
6194 }
6195
6196 if (!silent)
6197 printf (" [%6" PRIx64 "] %*s%s\n",
6198 (uint64_t) offset, (int) (level * 2), "",
Elliott Hughes03333822015-02-18 22:19:45 -08006199 dwarf_tag_name (tag));
Ben Cheng25b3c042013-11-20 14:45:36 -08006200
6201 /* Print the attribute values. */
6202 args.level = level;
Elliott Hughes03333822015-02-18 22:19:45 -08006203 args.die = &dies[level];
Ben Cheng25b3c042013-11-20 14:45:36 -08006204 (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0);
6205
6206 /* Make room for the next level's DIE. */
6207 if (level + 1 == maxdies)
6208 dies = (Dwarf_Die *) xrealloc (dies,
6209 (maxdies += 10)
6210 * sizeof (Dwarf_Die));
6211
6212 int res = dwarf_child (&dies[level], &dies[level + 1]);
6213 if (res > 0)
6214 {
6215 while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1)
6216 if (level-- == 0)
6217 break;
6218
6219 if (unlikely (res == -1))
6220 {
6221 if (!silent)
6222 error (0, 0, gettext ("cannot get next DIE: %s\n"),
6223 dwarf_errmsg (-1));
6224 goto do_return;
6225 }
6226 }
6227 else if (unlikely (res < 0))
6228 {
6229 if (!silent)
6230 error (0, 0, gettext ("cannot get next DIE: %s"),
6231 dwarf_errmsg (-1));
6232 goto do_return;
6233 }
6234 else
6235 ++level;
6236 }
6237 while (level >= 0);
6238
6239 offset = nextcu;
6240 if (offset != 0)
6241 goto next_cu;
6242
6243 do_return:
6244 free (dies);
6245}
6246
6247static void
6248print_debug_info_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
6249 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6250{
6251 print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, false);
6252}
6253
6254static void
6255print_debug_types_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
6256 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6257{
6258 print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, true);
6259}
6260
6261
6262static void
Elliott Hughes03333822015-02-18 22:19:45 -08006263print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
6264 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6265{
6266 printf (gettext ("\
6267\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n\n"),
6268 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6269 (uint64_t) shdr->sh_offset);
6270
6271 size_t address_size
6272 = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
6273
6274 Dwarf_Off cuoffset;
6275 Dwarf_Off ncuoffset = 0;
6276 size_t hsize;
6277 while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
6278 NULL, NULL, NULL) == 0)
6279 {
6280 Dwarf_Die cudie;
6281 if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
6282 continue;
6283
6284 size_t nlines;
6285 Dwarf_Lines *lines;
6286 if (dwarf_getsrclines (&cudie, &lines, &nlines) != 0)
6287 continue;
6288
6289 printf (" CU [%" PRIx64 "] %s\n",
6290 dwarf_dieoffset (&cudie), dwarf_diename (&cudie));
6291 printf (" line:col SBPE* disc isa op address"
6292 " (Statement Block Prologue Epilogue *End)\n");
6293 const char *last_file = "";
6294 for (size_t n = 0; n < nlines; n++)
6295 {
6296 Dwarf_Line *line = dwarf_onesrcline (lines, n);
6297 if (line == NULL)
6298 {
6299 printf (" dwarf_onesrcline: %s\n", dwarf_errmsg (-1));
6300 continue;
6301 }
6302 Dwarf_Word mtime, length;
6303 const char *file = dwarf_linesrc (line, &mtime, &length);
6304 if (file == NULL)
6305 {
6306 printf (" <%s> (mtime: ?, length: ?)\n", dwarf_errmsg (-1));
6307 last_file = "";
6308 }
6309 else if (strcmp (last_file, file) != 0)
6310 {
6311 printf (" %s (mtime: %" PRIu64 ", length: %" PRIu64 ")\n",
6312 file, mtime, length);
6313 last_file = file;
6314 }
6315
6316 int lineno, colno;
6317 bool statement, endseq, block, prologue_end, epilogue_begin;
6318 unsigned int lineop, isa, disc;
6319 Dwarf_Addr address;
6320 dwarf_lineaddr (line, &address);
6321 dwarf_lineno (line, &lineno);
6322 dwarf_linecol (line, &colno);
6323 dwarf_lineop_index (line, &lineop);
6324 dwarf_linebeginstatement (line, &statement);
6325 dwarf_lineendsequence (line, &endseq);
6326 dwarf_lineblock (line, &block);
6327 dwarf_lineprologueend (line, &prologue_end);
6328 dwarf_lineepiloguebegin (line, &epilogue_begin);
6329 dwarf_lineisa (line, &isa);
6330 dwarf_linediscriminator (line, &disc);
6331
6332 /* End sequence is special, it is one byte past. */
6333 char *a = format_dwarf_addr (dwflmod, address_size,
6334 address - (endseq ? 1 : 0), address);
6335 printf (" %4d:%-3d %c%c%c%c%c %4d %3d %2d %s\n",
6336 lineno, colno,
6337 (statement ? 'S' : ' '),
6338 (block ? 'B' : ' '),
6339 (prologue_end ? 'P' : ' '),
6340 (epilogue_begin ? 'E' : ' '),
6341 (endseq ? '*' : ' '),
6342 disc, isa, lineop, a);
6343 free (a);
6344
6345 if (endseq)
6346 printf("\n");
6347 }
6348 }
6349}
6350
6351
6352static void
Ben Cheng25b3c042013-11-20 14:45:36 -08006353print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
6354 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6355{
Elliott Hughes03333822015-02-18 22:19:45 -08006356 if (decodedline)
6357 {
6358 print_decoded_line_section (dwflmod, ebl, ehdr, scn, shdr, dbg);
6359 return;
6360 }
6361
Ben Cheng25b3c042013-11-20 14:45:36 -08006362 printf (gettext ("\
6363\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6364 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6365 (uint64_t) shdr->sh_offset);
6366
6367 if (shdr->sh_size == 0)
6368 return;
6369
6370 /* There is no functionality in libdw to read the information in the
6371 way it is represented here. Hardcode the decoder. */
Elliott Hughes03333822015-02-18 22:19:45 -08006372 Elf_Data *data = dbg->sectiondata[IDX_debug_line];
Ben Cheng25b3c042013-11-20 14:45:36 -08006373 if (unlikely (data == NULL || data->d_buf == NULL))
6374 {
6375 error (0, 0, gettext ("cannot get line data section data: %s"),
6376 elf_errmsg (-1));
6377 return;
6378 }
6379
6380 const unsigned char *linep = (const unsigned char *) data->d_buf;
6381 const unsigned char *lineendp;
6382
6383 while (linep
6384 < (lineendp = (const unsigned char *) data->d_buf + data->d_size))
6385 {
6386 size_t start_offset = linep - (const unsigned char *) data->d_buf;
6387
6388 printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
6389
Elliott Hughes03333822015-02-18 22:19:45 -08006390 if (unlikely (linep + 4 > lineendp))
6391 goto invalid_data;
Ben Cheng25b3c042013-11-20 14:45:36 -08006392 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
6393 unsigned int length = 4;
6394 if (unlikely (unit_length == 0xffffffff))
6395 {
6396 if (unlikely (linep + 8 > lineendp))
6397 {
6398 invalid_data:
6399 error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
6400 elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
6401 return;
6402 }
6403 unit_length = read_8ubyte_unaligned_inc (dbg, linep);
6404 length = 8;
6405 }
6406
6407 /* Check whether we have enough room in the section. */
Elliott Hughes03333822015-02-18 22:19:45 -08006408 if (unlikely (unit_length > (size_t) (lineendp - linep)
6409 || unit_length < 2 + length + 5 * 1))
Ben Cheng25b3c042013-11-20 14:45:36 -08006410 goto invalid_data;
6411 lineendp = linep + unit_length;
6412
6413 /* The next element of the header is the version identifier. */
6414 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
6415
6416 /* Next comes the header length. */
6417 Dwarf_Word header_length;
6418 if (length == 4)
6419 header_length = read_4ubyte_unaligned_inc (dbg, linep);
6420 else
6421 header_length = read_8ubyte_unaligned_inc (dbg, linep);
6422 //const unsigned char *header_start = linep;
6423
6424 /* Next the minimum instruction length. */
6425 uint_fast8_t minimum_instr_len = *linep++;
6426
6427 /* Next the maximum operations per instruction, in version 4 format. */
6428 uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++;
6429
6430 /* Then the flag determining the default value of the is_stmt
6431 register. */
6432 uint_fast8_t default_is_stmt = *linep++;
6433
6434 /* Now the line base. */
6435 int_fast8_t line_base = *((const int_fast8_t *) linep);
6436 ++linep;
6437
6438 /* And the line range. */
6439 uint_fast8_t line_range = *linep++;
6440
6441 /* The opcode base. */
6442 uint_fast8_t opcode_base = *linep++;
6443
6444 /* Print what we got so far. */
6445 printf (gettext ("\n"
6446 " Length: %" PRIu64 "\n"
6447 " DWARF version: %" PRIuFAST16 "\n"
6448 " Prologue length: %" PRIu64 "\n"
6449 " Minimum instruction length: %" PRIuFAST8 "\n"
6450 " Maximum operations per instruction: %" PRIuFAST8 "\n"
6451 " Initial value if '%s': %" PRIuFAST8 "\n"
6452 " Line base: %" PRIdFAST8 "\n"
6453 " Line range: %" PRIuFAST8 "\n"
6454 " Opcode base: %" PRIuFAST8 "\n"
6455 "\n"
6456 "Opcodes:\n"),
6457 (uint64_t) unit_length, version, (uint64_t) header_length,
6458 minimum_instr_len, max_ops_per_instr,
6459 "is_stmt", default_is_stmt, line_base,
6460 line_range, opcode_base);
6461
6462 if (unlikely (linep + opcode_base - 1 >= lineendp))
6463 {
6464 invalid_unit:
6465 error (0, 0,
6466 gettext ("invalid data at offset %tu in section [%zu] '%s'"),
6467 linep - (const unsigned char *) data->d_buf,
6468 elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
6469 linep = lineendp;
6470 continue;
6471 }
6472 int opcode_base_l10 = 1;
6473 unsigned int tmp = opcode_base;
6474 while (tmp > 10)
6475 {
6476 tmp /= 10;
6477 ++opcode_base_l10;
6478 }
6479 const uint8_t *standard_opcode_lengths = linep - 1;
6480 for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt)
6481 printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n",
6482 " [%*" PRIuFAST8 "] %hhu arguments\n",
6483 (int) linep[cnt - 1]),
6484 opcode_base_l10, cnt, linep[cnt - 1]);
6485 linep += opcode_base - 1;
6486 if (unlikely (linep >= lineendp))
6487 goto invalid_unit;
6488
6489 puts (gettext ("\nDirectory table:"));
6490 while (*linep != 0)
6491 {
6492 unsigned char *endp = memchr (linep, '\0', lineendp - linep);
6493 if (unlikely (endp == NULL))
6494 goto invalid_unit;
6495
6496 printf (" %s\n", (char *) linep);
6497
6498 linep = endp + 1;
6499 }
6500 /* Skip the final NUL byte. */
6501 ++linep;
6502
6503 if (unlikely (linep >= lineendp))
6504 goto invalid_unit;
6505 puts (gettext ("\nFile name table:\n"
6506 " Entry Dir Time Size Name"));
6507 for (unsigned int cnt = 1; *linep != 0; ++cnt)
6508 {
6509 /* First comes the file name. */
6510 char *fname = (char *) linep;
6511 unsigned char *endp = memchr (fname, '\0', lineendp - linep);
6512 if (unlikely (endp == NULL))
6513 goto invalid_unit;
6514 linep = endp + 1;
6515
6516 /* Then the index. */
6517 unsigned int diridx;
Elliott Hughes03333822015-02-18 22:19:45 -08006518 if (lineendp - linep < 1)
6519 goto invalid_unit;
6520 get_uleb128 (diridx, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006521
6522 /* Next comes the modification time. */
6523 unsigned int mtime;
Elliott Hughes03333822015-02-18 22:19:45 -08006524 if (lineendp - linep < 1)
6525 goto invalid_unit;
6526 get_uleb128 (mtime, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006527
6528 /* Finally the length of the file. */
6529 unsigned int fsize;
Elliott Hughes03333822015-02-18 22:19:45 -08006530 if (lineendp - linep < 1)
6531 goto invalid_unit;
6532 get_uleb128 (fsize, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006533
6534 printf (" %-5u %-5u %-9u %-9u %s\n",
6535 cnt, diridx, mtime, fsize, fname);
6536 }
6537 /* Skip the final NUL byte. */
6538 ++linep;
6539
6540 puts (gettext ("\nLine number statements:"));
6541 Dwarf_Word address = 0;
6542 unsigned int op_index = 0;
6543 size_t line = 1;
6544 uint_fast8_t is_stmt = default_is_stmt;
6545
6546 /* Default address value, in case we do not find the CU. */
6547 size_t address_size
6548 = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
6549
6550 /* Determine the CU this block is for. */
6551 Dwarf_Off cuoffset;
6552 Dwarf_Off ncuoffset = 0;
6553 size_t hsize;
6554 while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
6555 NULL, NULL, NULL) == 0)
6556 {
6557 Dwarf_Die cudie;
6558 if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
6559 continue;
6560 Dwarf_Attribute stmt_list;
6561 if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL)
6562 continue;
6563 Dwarf_Word lineoff;
6564 if (dwarf_formudata (&stmt_list, &lineoff) != 0)
6565 continue;
6566 if (lineoff == start_offset)
6567 {
6568 /* Found the CU. */
6569 address_size = cudie.cu->address_size;
6570 break;
6571 }
6572 }
6573
6574 /* Apply the "operation advance" from a special opcode
6575 or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */
6576 unsigned int op_addr_advance;
6577 bool show_op_index;
6578 inline void advance_pc (unsigned int op_advance)
6579 {
6580 op_addr_advance = minimum_instr_len * ((op_index + op_advance)
6581 / max_ops_per_instr);
6582 address += op_advance;
6583 show_op_index = (op_index > 0 ||
6584 (op_index + op_advance) % max_ops_per_instr > 0);
6585 op_index = (op_index + op_advance) % max_ops_per_instr;
6586 }
6587
Elliott Hughes03333822015-02-18 22:19:45 -08006588 if (max_ops_per_instr == 0)
6589 {
6590 error (0, 0,
6591 gettext ("invalid maximum operations per instruction is zero"));
6592 linep = lineendp;
6593 continue;
6594 }
6595
Ben Cheng25b3c042013-11-20 14:45:36 -08006596 while (linep < lineendp)
6597 {
6598 size_t offset = linep - (const unsigned char *) data->d_buf;
6599 unsigned int u128;
6600 int s128;
6601
6602 /* Read the opcode. */
6603 unsigned int opcode = *linep++;
6604
6605 printf (" [%6" PRIx64 "]", (uint64_t)offset);
6606 /* Is this a special opcode? */
6607 if (likely (opcode >= opcode_base))
6608 {
Elliott Hughes03333822015-02-18 22:19:45 -08006609 if (unlikely (line_range == 0))
6610 goto invalid_unit;
6611
Ben Cheng25b3c042013-11-20 14:45:36 -08006612 /* Yes. Handling this is quite easy since the opcode value
6613 is computed with
6614
6615 opcode = (desired line increment - line_base)
6616 + (line_range * address advance) + opcode_base
6617 */
6618 int line_increment = (line_base
6619 + (opcode - opcode_base) % line_range);
6620
6621 /* Perform the increments. */
6622 line += line_increment;
6623 advance_pc ((opcode - opcode_base) / line_range);
6624
Elliott Hughes03333822015-02-18 22:19:45 -08006625 char *a = format_dwarf_addr (dwflmod, 0, address, address);
Ben Cheng25b3c042013-11-20 14:45:36 -08006626 if (show_op_index)
6627 printf (gettext ("\
6628 special opcode %u: address+%u = %s, op_index = %u, line%+d = %zu\n"),
6629 opcode, op_addr_advance, a, op_index,
6630 line_increment, line);
6631 else
6632 printf (gettext ("\
6633 special opcode %u: address+%u = %s, line%+d = %zu\n"),
6634 opcode, op_addr_advance, a, line_increment, line);
6635 free (a);
6636 }
6637 else if (opcode == 0)
6638 {
6639 /* This an extended opcode. */
6640 if (unlikely (linep + 2 > lineendp))
6641 goto invalid_unit;
6642
6643 /* The length. */
6644 unsigned int len = *linep++;
6645
6646 if (unlikely (linep + len > lineendp))
6647 goto invalid_unit;
6648
6649 /* The sub-opcode. */
6650 opcode = *linep++;
6651
6652 printf (gettext (" extended opcode %u: "), opcode);
6653
6654 switch (opcode)
6655 {
6656 case DW_LNE_end_sequence:
6657 puts (gettext (" end of sequence"));
6658
6659 /* Reset the registers we care about. */
6660 address = 0;
6661 op_index = 0;
6662 line = 1;
6663 is_stmt = default_is_stmt;
6664 break;
6665
6666 case DW_LNE_set_address:
6667 op_index = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08006668 if (unlikely ((size_t) (lineendp - linep) < address_size))
6669 goto invalid_unit;
Ben Cheng25b3c042013-11-20 14:45:36 -08006670 if (address_size == 4)
6671 address = read_4ubyte_unaligned_inc (dbg, linep);
6672 else
6673 address = read_8ubyte_unaligned_inc (dbg, linep);
6674 {
Elliott Hughes03333822015-02-18 22:19:45 -08006675 char *a = format_dwarf_addr (dwflmod, 0, address, address);
Ben Cheng25b3c042013-11-20 14:45:36 -08006676 printf (gettext (" set address to %s\n"), a);
6677 free (a);
6678 }
6679 break;
6680
6681 case DW_LNE_define_file:
6682 {
6683 char *fname = (char *) linep;
6684 unsigned char *endp = memchr (linep, '\0',
6685 lineendp - linep);
6686 if (unlikely (endp == NULL))
6687 goto invalid_unit;
6688 linep = endp + 1;
6689
6690 unsigned int diridx;
Elliott Hughes03333822015-02-18 22:19:45 -08006691 if (lineendp - linep < 1)
6692 goto invalid_unit;
6693 get_uleb128 (diridx, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006694 Dwarf_Word mtime;
Elliott Hughes03333822015-02-18 22:19:45 -08006695 if (lineendp - linep < 1)
6696 goto invalid_unit;
6697 get_uleb128 (mtime, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006698 Dwarf_Word filelength;
Elliott Hughes03333822015-02-18 22:19:45 -08006699 if (lineendp - linep < 1)
6700 goto invalid_unit;
6701 get_uleb128 (filelength, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006702
6703 printf (gettext ("\
6704 define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
6705 diridx, (uint64_t) mtime, (uint64_t) filelength,
6706 fname);
6707 }
6708 break;
6709
6710 case DW_LNE_set_discriminator:
6711 /* Takes one ULEB128 parameter, the discriminator. */
6712 if (unlikely (standard_opcode_lengths[opcode] != 1))
6713 goto invalid_unit;
6714
Elliott Hughes03333822015-02-18 22:19:45 -08006715 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006716 printf (gettext (" set discriminator to %u\n"), u128);
6717 break;
6718
6719 default:
6720 /* Unknown, ignore it. */
6721 puts (gettext (" unknown opcode"));
6722 linep += len - 1;
6723 break;
6724 }
6725 }
6726 else if (opcode <= DW_LNS_set_isa)
6727 {
6728 /* This is a known standard opcode. */
6729 switch (opcode)
6730 {
6731 case DW_LNS_copy:
6732 /* Takes no argument. */
6733 puts (gettext (" copy"));
6734 break;
6735
6736 case DW_LNS_advance_pc:
6737 /* Takes one uleb128 parameter which is added to the
6738 address. */
Elliott Hughes03333822015-02-18 22:19:45 -08006739 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006740 advance_pc (u128);
6741 {
Elliott Hughes03333822015-02-18 22:19:45 -08006742 char *a = format_dwarf_addr (dwflmod, 0, address, address);
Ben Cheng25b3c042013-11-20 14:45:36 -08006743 if (show_op_index)
6744 printf (gettext ("\
6745 advance address by %u to %s, op_index to %u\n"),
6746 op_addr_advance, a, op_index);
6747 else
6748 printf (gettext (" advance address by %u to %s\n"),
6749 op_addr_advance, a);
6750 free (a);
6751 }
6752 break;
6753
6754 case DW_LNS_advance_line:
6755 /* Takes one sleb128 parameter which is added to the
6756 line. */
Elliott Hughes03333822015-02-18 22:19:45 -08006757 get_sleb128 (s128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006758 line += s128;
6759 printf (gettext ("\
6760 advance line by constant %d to %" PRId64 "\n"),
6761 s128, (int64_t) line);
6762 break;
6763
6764 case DW_LNS_set_file:
6765 /* Takes one uleb128 parameter which is stored in file. */
Elliott Hughes03333822015-02-18 22:19:45 -08006766 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006767 printf (gettext (" set file to %" PRIu64 "\n"),
6768 (uint64_t) u128);
6769 break;
6770
6771 case DW_LNS_set_column:
6772 /* Takes one uleb128 parameter which is stored in column. */
6773 if (unlikely (standard_opcode_lengths[opcode] != 1))
6774 goto invalid_unit;
6775
Elliott Hughes03333822015-02-18 22:19:45 -08006776 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006777 printf (gettext (" set column to %" PRIu64 "\n"),
6778 (uint64_t) u128);
6779 break;
6780
6781 case DW_LNS_negate_stmt:
6782 /* Takes no argument. */
6783 is_stmt = 1 - is_stmt;
6784 printf (gettext (" set '%s' to %" PRIuFAST8 "\n"),
6785 "is_stmt", is_stmt);
6786 break;
6787
6788 case DW_LNS_set_basic_block:
6789 /* Takes no argument. */
6790 puts (gettext (" set basic block flag"));
6791 break;
6792
6793 case DW_LNS_const_add_pc:
6794 /* Takes no argument. */
Elliott Hughes03333822015-02-18 22:19:45 -08006795
6796 if (unlikely (line_range == 0))
6797 goto invalid_unit;
6798
Ben Cheng25b3c042013-11-20 14:45:36 -08006799 advance_pc ((255 - opcode_base) / line_range);
6800 {
Elliott Hughes03333822015-02-18 22:19:45 -08006801 char *a = format_dwarf_addr (dwflmod, 0, address, address);
Ben Cheng25b3c042013-11-20 14:45:36 -08006802 if (show_op_index)
6803 printf (gettext ("\
6804 advance address by constant %u to %s, op_index to %u\n"),
6805 op_addr_advance, a, op_index);
6806 else
6807 printf (gettext ("\
6808 advance address by constant %u to %s\n"),
6809 op_addr_advance, a);
6810 free (a);
6811 }
6812 break;
6813
6814 case DW_LNS_fixed_advance_pc:
6815 /* Takes one 16 bit parameter which is added to the
6816 address. */
6817 if (unlikely (standard_opcode_lengths[opcode] != 1))
6818 goto invalid_unit;
6819
6820 u128 = read_2ubyte_unaligned_inc (dbg, linep);
6821 address += u128;
6822 op_index = 0;
6823 {
Elliott Hughes03333822015-02-18 22:19:45 -08006824 char *a = format_dwarf_addr (dwflmod, 0, address, address);
Ben Cheng25b3c042013-11-20 14:45:36 -08006825 printf (gettext ("\
6826 advance address by fixed value %u to %s\n"),
6827 u128, a);
6828 free (a);
6829 }
6830 break;
6831
6832 case DW_LNS_set_prologue_end:
6833 /* Takes no argument. */
6834 puts (gettext (" set prologue end flag"));
6835 break;
6836
6837 case DW_LNS_set_epilogue_begin:
6838 /* Takes no argument. */
6839 puts (gettext (" set epilogue begin flag"));
6840 break;
6841
6842 case DW_LNS_set_isa:
6843 /* Takes one uleb128 parameter which is stored in isa. */
6844 if (unlikely (standard_opcode_lengths[opcode] != 1))
6845 goto invalid_unit;
6846
Elliott Hughes03333822015-02-18 22:19:45 -08006847 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006848 printf (gettext (" set isa to %u\n"), u128);
6849 break;
6850 }
6851 }
6852 else
6853 {
6854 /* This is a new opcode the generator but not we know about.
6855 Read the parameters associated with it but then discard
6856 everything. Read all the parameters for this opcode. */
6857 printf (ngettext (" unknown opcode with %" PRIu8 " parameter:",
6858 " unknown opcode with %" PRIu8 " parameters:",
6859 standard_opcode_lengths[opcode]),
6860 standard_opcode_lengths[opcode]);
6861 for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
6862 {
Elliott Hughes03333822015-02-18 22:19:45 -08006863 get_uleb128 (u128, linep, lineendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006864 if (n != standard_opcode_lengths[opcode])
6865 putc_unlocked (',', stdout);
6866 printf (" %u", u128);
6867 }
6868
6869 /* Next round, ignore this opcode. */
6870 continue;
6871 }
6872 }
6873 }
6874
6875 /* There must only be one data block. */
6876 assert (elf_getdata (scn, data) == NULL);
6877}
6878
6879
6880static void
6881print_debug_loc_section (Dwfl_Module *dwflmod,
6882 Ebl *ebl, GElf_Ehdr *ehdr,
6883 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
6884{
Elliott Hughes03333822015-02-18 22:19:45 -08006885 Elf_Data *data = dbg->sectiondata[IDX_debug_loc];
Ben Cheng25b3c042013-11-20 14:45:36 -08006886
6887 if (unlikely (data == NULL))
6888 {
6889 error (0, 0, gettext ("cannot get .debug_loc content: %s"),
6890 elf_errmsg (-1));
6891 return;
6892 }
6893
6894 printf (gettext ("\
6895\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
6896 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
6897 (uint64_t) shdr->sh_offset);
6898
6899 sort_listptr (&known_loclistptr, "loclistptr");
6900 size_t listptr_idx = 0;
6901
6902 uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
6903 uint_fast8_t offset_size = 4;
6904
6905 bool first = true;
Elliott Hughes03333822015-02-18 22:19:45 -08006906 struct Dwarf_CU *cu = NULL;
6907 Dwarf_Addr base = 0;
Ben Cheng25b3c042013-11-20 14:45:36 -08006908 unsigned char *readp = data->d_buf;
6909 unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
6910 while (readp < endp)
6911 {
6912 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
6913
6914 if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
Elliott Hughes03333822015-02-18 22:19:45 -08006915 &address_size, &offset_size, &base,
6916 &cu, offset, &readp, endp))
Ben Cheng25b3c042013-11-20 14:45:36 -08006917 continue;
6918
Elliott Hughes03333822015-02-18 22:19:45 -08006919 if (unlikely (data->d_size - offset < (size_t) address_size * 2))
Ben Cheng25b3c042013-11-20 14:45:36 -08006920 {
6921 printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
6922 break;
6923 }
6924
6925 Dwarf_Addr begin;
6926 Dwarf_Addr end;
6927 if (address_size == 8)
6928 {
6929 begin = read_8ubyte_unaligned_inc (dbg, readp);
6930 end = read_8ubyte_unaligned_inc (dbg, readp);
6931 }
6932 else
6933 {
6934 begin = read_4ubyte_unaligned_inc (dbg, readp);
6935 end = read_4ubyte_unaligned_inc (dbg, readp);
6936 if (begin == (Dwarf_Addr) (uint32_t) -1)
6937 begin = (Dwarf_Addr) -1l;
6938 }
6939
6940 if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
6941 {
Elliott Hughes03333822015-02-18 22:19:45 -08006942 char *b = format_dwarf_addr (dwflmod, address_size, end, end);
Ben Cheng25b3c042013-11-20 14:45:36 -08006943 printf (gettext (" [%6tx] base address %s\n"), offset, b);
6944 free (b);
Elliott Hughes03333822015-02-18 22:19:45 -08006945 base = end;
Ben Cheng25b3c042013-11-20 14:45:36 -08006946 }
6947 else if (begin == 0 && end == 0) /* End of list entry. */
6948 {
6949 if (first)
6950 printf (gettext (" [%6tx] empty list\n"), offset);
6951 first = true;
6952 }
6953 else
6954 {
6955 /* We have a location expression entry. */
6956 uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
6957
Elliott Hughes03333822015-02-18 22:19:45 -08006958 char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
6959 begin);
6960 char *e = format_dwarf_addr (dwflmod, address_size, base + end,
6961 end);
Ben Cheng25b3c042013-11-20 14:45:36 -08006962
6963 if (first) /* First entry in a list. */
6964 printf (gettext (" [%6tx] %s..%s"), offset, b, e);
6965 else
6966 printf (gettext (" %s..%s"), b, e);
6967
6968 free (b);
6969 free (e);
6970
6971 if (endp - readp <= (ptrdiff_t) len)
6972 {
6973 fputs (gettext (" <INVALID DATA>\n"), stdout);
6974 break;
6975 }
6976
6977 print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
Elliott Hughes03333822015-02-18 22:19:45 -08006978 3 /*XXX*/, address_size, offset_size, cu, len, readp);
Ben Cheng25b3c042013-11-20 14:45:36 -08006979
6980 first = false;
6981 readp += len;
6982 }
6983 }
6984}
6985
6986struct mac_culist
6987{
6988 Dwarf_Die die;
6989 Dwarf_Off offset;
6990 Dwarf_Files *files;
6991 struct mac_culist *next;
6992};
6993
6994
6995static int
6996mac_compare (const void *p1, const void *p2)
6997{
6998 struct mac_culist *m1 = (struct mac_culist *) p1;
6999 struct mac_culist *m2 = (struct mac_culist *) p2;
7000
7001 if (m1->offset < m2->offset)
7002 return -1;
7003 if (m1->offset > m2->offset)
7004 return 1;
7005 return 0;
7006}
7007
7008
7009static void
7010print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
7011 Ebl *ebl, GElf_Ehdr *ehdr,
7012 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7013{
7014 printf (gettext ("\
7015\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
7016 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
7017 (uint64_t) shdr->sh_offset);
7018 putc_unlocked ('\n', stdout);
7019
7020 /* There is no function in libdw to iterate over the raw content of
7021 the section but it is easy enough to do. */
Elliott Hughes03333822015-02-18 22:19:45 -08007022 Elf_Data *data = dbg->sectiondata[IDX_debug_macinfo];
Ben Cheng25b3c042013-11-20 14:45:36 -08007023 if (unlikely (data == NULL || data->d_buf == NULL))
7024 {
7025 error (0, 0, gettext ("cannot get macro information section data: %s"),
7026 elf_errmsg (-1));
7027 return;
7028 }
7029
7030 /* Get the source file information for all CUs. */
7031 Dwarf_Off offset;
7032 Dwarf_Off ncu = 0;
7033 size_t hsize;
7034 struct mac_culist *culist = NULL;
7035 size_t nculist = 0;
7036 while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
7037 {
7038 Dwarf_Die cudie;
7039 if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
7040 continue;
7041
7042 Dwarf_Attribute attr;
7043 if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL)
7044 continue;
7045
7046 Dwarf_Word macoff;
7047 if (dwarf_formudata (&attr, &macoff) != 0)
7048 continue;
7049
7050 struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
7051 newp->die = cudie;
7052 newp->offset = macoff;
7053 newp->files = NULL;
7054 newp->next = culist;
7055 culist = newp;
7056 ++nculist;
7057 }
7058
7059 /* Convert the list into an array for easier consumption. */
7060 struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1)
7061 * sizeof (*cus));
7062 /* Add sentinel. */
7063 cus[nculist].offset = data->d_size;
7064 if (nculist > 0)
7065 {
7066 for (size_t cnt = nculist - 1; culist != NULL; --cnt)
7067 {
7068 assert (cnt < nculist);
7069 cus[cnt] = *culist;
7070 culist = culist->next;
7071 }
7072
7073 /* Sort the array according to the offset in the .debug_macinfo
7074 section. Note we keep the sentinel at the end. */
7075 qsort (cus, nculist, sizeof (*cus), mac_compare);
7076 }
7077
7078 const unsigned char *readp = (const unsigned char *) data->d_buf;
7079 const unsigned char *readendp = readp + data->d_size;
7080 int level = 1;
7081
7082 while (readp < readendp)
7083 {
7084 unsigned int opcode = *readp++;
7085 unsigned int u128;
7086 unsigned int u128_2;
7087 const unsigned char *endp;
7088
7089 switch (opcode)
7090 {
7091 case DW_MACINFO_define:
7092 case DW_MACINFO_undef:
7093 case DW_MACINFO_vendor_ext:
7094 /* For the first two opcodes the parameters are
7095 line, string
7096 For the latter
7097 number, string.
7098 We can treat these cases together. */
Elliott Hughes03333822015-02-18 22:19:45 -08007099 get_uleb128 (u128, readp, readendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08007100
7101 endp = memchr (readp, '\0', readendp - readp);
7102 if (unlikely (endp == NULL))
7103 {
7104 printf (gettext ("\
7105%*s*** non-terminated string at end of section"),
7106 level, "");
7107 return;
7108 }
7109
7110 if (opcode == DW_MACINFO_define)
7111 printf ("%*s#define %s, line %u\n",
7112 level, "", (char *) readp, u128);
7113 else if (opcode == DW_MACINFO_undef)
7114 printf ("%*s#undef %s, line %u\n",
7115 level, "", (char *) readp, u128);
7116 else
7117 printf (" #vendor-ext %s, number %u\n", (char *) readp, u128);
7118
7119 readp = endp + 1;
7120 break;
7121
7122 case DW_MACINFO_start_file:
7123 /* The two parameters are line and file index, in this order. */
Elliott Hughes03333822015-02-18 22:19:45 -08007124 get_uleb128 (u128, readp, readendp);
7125 if (readendp - readp < 1)
7126 {
7127 printf (gettext ("\
7128%*s*** missing DW_MACINFO_start_file argument at end of section"),
7129 level, "");
7130 return;
7131 }
7132 get_uleb128 (u128_2, readp, readendp);
Ben Cheng25b3c042013-11-20 14:45:36 -08007133
7134 /* Find the CU DIE for this file. */
7135 size_t macoff = readp - (const unsigned char *) data->d_buf;
7136 const char *fname = "???";
7137 if (macoff >= cus[0].offset)
7138 {
7139 while (macoff >= cus[1].offset)
7140 ++cus;
7141
7142 if (cus[0].files == NULL
7143 && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0)
7144 cus[0].files = (Dwarf_Files *) -1l;
7145
7146 if (cus[0].files != (Dwarf_Files *) -1l)
7147 fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL)
7148 ?: "???");
7149 }
7150
7151 printf ("%*sstart_file %u, [%u] %s\n",
7152 level, "", u128, u128_2, fname);
7153 ++level;
7154 break;
7155
7156 case DW_MACINFO_end_file:
7157 --level;
7158 printf ("%*send_file\n", level, "");
7159 /* Nothing more to do. */
7160 break;
7161
7162 default:
7163 // XXX gcc seems to generate files with a trailing zero.
7164 if (unlikely (opcode != 0 || readp != readendp))
7165 printf ("%*s*** invalid opcode %u\n", level, "", opcode);
7166 break;
7167 }
7168 }
7169}
7170
7171
Elliott Hughes03333822015-02-18 22:19:45 -08007172static void
7173print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
7174 Ebl *ebl, GElf_Ehdr *ehdr,
7175 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7176{
7177 printf (gettext ("\
7178\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
7179 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
7180 (uint64_t) shdr->sh_offset);
7181 putc_unlocked ('\n', stdout);
7182
7183 Elf_Data *data = dbg->sectiondata[IDX_debug_macro];
7184 if (unlikely (data == NULL || data->d_buf == NULL))
7185 {
7186 error (0, 0, gettext ("cannot get macro information section data: %s"),
7187 elf_errmsg (-1));
7188 return;
7189 }
7190
7191 /* Get the source file information for all CUs. Uses same
7192 datastructure as macinfo. But uses offset field to directly
7193 match .debug_line offset. And just stored in a list. */
7194 Dwarf_Off offset;
7195 Dwarf_Off ncu = 0;
7196 size_t hsize;
7197 struct mac_culist *culist = NULL;
7198 size_t nculist = 0;
7199 while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
7200 {
7201 Dwarf_Die cudie;
7202 if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
7203 continue;
7204
7205 Dwarf_Attribute attr;
7206 if (dwarf_attr (&cudie, DW_AT_stmt_list, &attr) == NULL)
7207 continue;
7208
7209 Dwarf_Word lineoff;
7210 if (dwarf_formudata (&attr, &lineoff) != 0)
7211 continue;
7212
7213 struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
7214 newp->die = cudie;
7215 newp->offset = lineoff;
7216 newp->files = NULL;
7217 newp->next = culist;
7218 culist = newp;
7219 ++nculist;
7220 }
7221
7222 const unsigned char *readp = (const unsigned char *) data->d_buf;
7223 const unsigned char *readendp = readp + data->d_size;
7224
7225 while (readp < readendp)
7226 {
7227 printf (gettext (" Offset: 0x%" PRIx64 "\n"),
7228 (uint64_t) (readp - (const unsigned char *) data->d_buf));
7229
7230 // Header, 2 byte version, 1 byte flag, optional .debug_line offset,
7231 // optional vendor extension macro entry table.
7232 if (readp + 2 > readendp)
7233 {
7234 invalid_data:
7235 error (0, 0, gettext ("invalid data"));
7236 return;
7237 }
7238 const uint16_t vers = read_2ubyte_unaligned_inc (dbg, readp);
7239 printf (gettext (" Version: %" PRIu16 "\n"), vers);
7240
7241 // Version 4 is the GNU extension for DWARF4. DWARF5 will use version
7242 // 5 when it gets standardized.
7243 if (vers != 4)
7244 {
7245 printf (gettext (" unknown version, cannot parse section\n"));
7246 return;
7247 }
7248
7249 if (readp + 1 > readendp)
7250 goto invalid_data;
7251 const unsigned char flag = *readp++;
7252 printf (gettext (" Flag: 0x%" PRIx8 "\n"), flag);
7253
7254 unsigned int offset_len = (flag & 0x01) ? 8 : 4;
7255 printf (gettext (" Offset length: %" PRIu8 "\n"), offset_len);
7256 Dwarf_Off line_offset = -1;
7257 if (flag & 0x02)
7258 {
7259 if (offset_len == 8)
7260 line_offset = read_8ubyte_unaligned_inc (dbg, readp);
7261 else
7262 line_offset = read_4ubyte_unaligned_inc (dbg, readp);
7263 printf (gettext (" .debug_line offset: 0x%" PRIx64 "\n"),
7264 line_offset);
7265 }
7266
7267 const unsigned char *vendor[DW_MACRO_GNU_hi_user - DW_MACRO_GNU_lo_user];
7268 memset (vendor, 0, sizeof vendor);
7269 if (flag & 0x04)
7270 {
7271 // 1 byte length, for each item, 1 byte opcode, uleb128 number
7272 // of arguments, for each argument 1 byte form code.
7273 if (readp + 1 > readendp)
7274 goto invalid_data;
7275 unsigned int tlen = *readp++;
7276 printf (gettext (" extension opcode table, %" PRIu8 " items:\n"),
7277 tlen);
7278 for (unsigned int i = 0; i < tlen; i++)
7279 {
7280 if (readp + 1 > readendp)
7281 goto invalid_data;
7282 unsigned int opcode = *readp++;
7283 printf (gettext (" [%" PRIx8 "]"), opcode);
7284 if (opcode < DW_MACRO_GNU_lo_user
7285 || opcode > DW_MACRO_GNU_hi_user)
7286 goto invalid_data;
7287 // Record the start of description for this vendor opcode.
7288 // uleb128 nr args, 1 byte per arg form.
7289 vendor[opcode - DW_MACRO_GNU_lo_user] = readp;
7290 if (readp + 1 > readendp)
7291 goto invalid_data;
7292 unsigned int args = *readp++;
7293 if (args > 0)
7294 {
7295 printf (gettext (" %" PRIu8 " arguments:"), args);
7296 while (args > 0)
7297 {
7298 if (readp + 1 > readendp)
7299 goto invalid_data;
7300 unsigned int form = *readp++;
7301 printf (" %s", dwarf_form_string (form));
7302 if (form != DW_FORM_data1
7303 && form != DW_FORM_data2
7304 && form != DW_FORM_data4
7305 && form != DW_FORM_data8
7306 && form != DW_FORM_sdata
7307 && form != DW_FORM_udata
7308 && form != DW_FORM_block
7309 && form != DW_FORM_block1
7310 && form != DW_FORM_block2
7311 && form != DW_FORM_block4
7312 && form != DW_FORM_flag
7313 && form != DW_FORM_string
7314 && form != DW_FORM_strp
7315 && form != DW_FORM_sec_offset)
7316 goto invalid_data;
7317 args--;
7318 if (args > 0)
7319 putchar_unlocked (',');
7320 }
7321 }
7322 else
7323 printf (gettext (" no arguments."));
7324 putchar_unlocked ('\n');
7325 }
7326 }
7327 putchar_unlocked ('\n');
7328
7329 int level = 1;
7330 if (readp + 1 > readendp)
7331 goto invalid_data;
7332 unsigned int opcode = *readp++;
7333 while (opcode != 0)
7334 {
7335 unsigned int u128;
7336 unsigned int u128_2;
7337 const unsigned char *endp;
7338 uint64_t off;
7339
7340 switch (opcode)
7341 {
7342 case DW_MACRO_GNU_start_file:
7343 get_uleb128 (u128, readp, readendp);
7344 if (readp >= readendp)
7345 goto invalid_data;
7346 get_uleb128 (u128_2, readp, readendp);
7347
7348 /* Find the CU DIE that matches this line offset. */
7349 const char *fname = "???";
7350 if (line_offset != (Dwarf_Off) -1)
7351 {
7352 struct mac_culist *cu = culist;
7353 while (cu != NULL && line_offset != cu->offset)
7354 cu = cu->next;
7355 if (cu != NULL)
7356 {
7357 if (cu->files == NULL
7358 && dwarf_getsrcfiles (&cu->die, &cu->files,
7359 NULL) != 0)
7360 cu->files = (Dwarf_Files *) -1l;
7361
7362 if (cu->files != (Dwarf_Files *) -1l)
7363 fname = (dwarf_filesrc (cu->files, u128_2,
7364 NULL, NULL) ?: "???");
7365 }
7366 }
7367 printf ("%*sstart_file %u, [%u] %s\n",
7368 level, "", u128, u128_2, fname);
7369 ++level;
7370 break;
7371
7372 case DW_MACRO_GNU_end_file:
7373 --level;
7374 printf ("%*send_file\n", level, "");
7375 break;
7376
7377 case DW_MACRO_GNU_define:
7378 get_uleb128 (u128, readp, readendp);
7379 endp = memchr (readp, '\0', readendp - readp);
7380 if (endp == NULL)
7381 goto invalid_data;
7382 printf ("%*s#define %s, line %u\n",
7383 level, "", readp, u128);
7384 readp = endp + 1;
7385 break;
7386
7387 case DW_MACRO_GNU_undef:
7388 get_uleb128 (u128, readp, readendp);
7389 endp = memchr (readp, '\0', readendp - readp);
7390 if (endp == NULL)
7391 goto invalid_data;
7392 printf ("%*s#undef %s, line %u\n",
7393 level, "", readp, u128);
7394 readp = endp + 1;
7395 break;
7396
7397 case DW_MACRO_GNU_define_indirect:
7398 get_uleb128 (u128, readp, readendp);
7399 if (readp + offset_len > readendp)
7400 goto invalid_data;
7401 if (offset_len == 8)
7402 off = read_8ubyte_unaligned_inc (dbg, readp);
7403 else
7404 off = read_4ubyte_unaligned_inc (dbg, readp);
7405 printf ("%*s#define %s, line %u (indirect)\n",
7406 level, "", dwarf_getstring (dbg, off, NULL), u128);
7407 break;
7408
7409 case DW_MACRO_GNU_undef_indirect:
7410 get_uleb128 (u128, readp, readendp);
7411 if (readp + offset_len > readendp)
7412 goto invalid_data;
7413 if (offset_len == 8)
7414 off = read_8ubyte_unaligned_inc (dbg, readp);
7415 else
7416 off = read_4ubyte_unaligned_inc (dbg, readp);
7417 printf ("%*s#undef %s, line %u (indirect)\n",
7418 level, "", dwarf_getstring (dbg, off, NULL), u128);
7419 break;
7420
7421 case DW_MACRO_GNU_transparent_include:
7422 if (readp + offset_len > readendp)
7423 goto invalid_data;
7424 if (offset_len == 8)
7425 off = read_8ubyte_unaligned_inc (dbg, readp);
7426 else
7427 off = read_4ubyte_unaligned_inc (dbg, readp);
7428 printf ("%*s#include offset 0x%" PRIx64 "\n",
7429 level, "", off);
7430 break;
7431
7432 default:
7433 printf ("%*svendor opcode 0x%" PRIx8, level, "", opcode);
7434 if (opcode < DW_MACRO_GNU_lo_user
7435 || opcode > DW_MACRO_GNU_lo_user
7436 || vendor[opcode - DW_MACRO_GNU_lo_user] == NULL)
7437 goto invalid_data;
7438
7439 const unsigned char *op_desc;
7440 op_desc = vendor[opcode - DW_MACRO_GNU_lo_user];
7441
7442 // Just skip the arguments, we cannot really interpret them,
7443 // but print as much as we can.
7444 unsigned int args = *op_desc++;
7445 while (args > 0)
7446 {
7447 unsigned int form = *op_desc++;
7448 Dwarf_Word val;
7449 switch (form)
7450 {
7451 case DW_FORM_data1:
7452 if (readp + 1 > readendp)
7453 goto invalid_data;
7454 val = *readp++;
7455 printf (" %" PRIx8, (unsigned int) val);
7456 break;
7457
7458 case DW_FORM_data2:
7459 if (readp + 2 > readendp)
7460 goto invalid_data;
7461 val = read_2ubyte_unaligned_inc (dbg, readp);
7462 printf(" %" PRIx16, (unsigned int) val);
7463 break;
7464
7465 case DW_FORM_data4:
7466 if (readp + 4 > readendp)
7467 goto invalid_data;
7468 val = read_4ubyte_unaligned_inc (dbg, readp);
7469 printf (" %" PRIx32, (unsigned int) val);
7470 break;
7471
7472 case DW_FORM_data8:
7473 if (readp + 8 > readendp)
7474 goto invalid_data;
7475 val = read_8ubyte_unaligned_inc (dbg, readp);
7476 printf (" %" PRIx64, val);
7477 break;
7478
7479 case DW_FORM_sdata:
7480 get_sleb128 (val, readp, readendp);
7481 printf (" %" PRIx64, val);
7482 break;
7483
7484 case DW_FORM_udata:
7485 get_uleb128 (val, readp, readendp);
7486 printf (" %" PRIx64, val);
7487 break;
7488
7489 case DW_FORM_block:
7490 get_uleb128 (val, readp, readendp);
7491 printf (" block[%" PRIu64 "]", val);
7492 if (readp + val > readendp)
7493 goto invalid_data;
7494 readp += val;
7495 break;
7496
7497 case DW_FORM_block1:
7498 if (readp + 1 > readendp)
7499 goto invalid_data;
7500 val = *readp++;
7501 printf (" block[%" PRIu64 "]", val);
7502 if (readp + val > readendp)
7503 goto invalid_data;
7504 break;
7505
7506 case DW_FORM_block2:
7507 if (readp + 2 > readendp)
7508 goto invalid_data;
7509 val = read_2ubyte_unaligned_inc (dbg, readp);
7510 printf (" block[%" PRIu64 "]", val);
7511 if (readp + val > readendp)
7512 goto invalid_data;
7513 break;
7514
7515 case DW_FORM_block4:
7516 if (readp + 2 > readendp)
7517 goto invalid_data;
7518 val =read_4ubyte_unaligned_inc (dbg, readp);
7519 printf (" block[%" PRIu64 "]", val);
7520 if (readp + val > readendp)
7521 goto invalid_data;
7522 break;
7523
7524 case DW_FORM_flag:
7525 if (readp + 1 > readendp)
7526 goto invalid_data;
7527 val = *readp++;
7528 printf (" %s", nl_langinfo (val != 0 ? YESSTR : NOSTR));
7529 break;
7530
7531 case DW_FORM_string:
7532 endp = memchr (readp, '\0', readendp - readp);
7533 if (endp == NULL)
7534 goto invalid_data;
7535 printf (" %s", readp);
7536 readp = endp + 1;
7537 break;
7538
7539 case DW_FORM_strp:
7540 if (readp + offset_len > readendp)
7541 goto invalid_data;
7542 if (offset_len == 8)
7543 val = read_8ubyte_unaligned_inc (dbg, readp);
7544 else
7545 val = read_4ubyte_unaligned_inc (dbg, readp);
7546 printf (" %s", dwarf_getstring (dbg, val, NULL));
7547 break;
7548
7549 case DW_FORM_sec_offset:
7550 if (readp + offset_len > readendp)
7551 goto invalid_data;
7552 if (offset_len == 8)
7553 val = read_8ubyte_unaligned_inc (dbg, readp);
7554 else
7555 val = read_4ubyte_unaligned_inc (dbg, readp);
7556 printf (" %" PRIx64, val);
7557 break;
7558
7559 default:
7560 error (0, 0, gettext ("vendor opcode not verified?"));
7561 return;
7562 }
7563
7564 args--;
7565 if (args > 0)
7566 putchar_unlocked (',');
7567 }
7568 putchar_unlocked ('\n');
7569 }
7570
7571 if (readp + 1 > readendp)
7572 goto invalid_data;
7573 opcode = *readp++;
7574 if (opcode == 0)
7575 putchar_unlocked ('\n');
7576 }
7577 }
7578}
7579
7580
Ben Cheng25b3c042013-11-20 14:45:36 -08007581/* Callback for printing global names. */
7582static int
7583print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
7584 void *arg)
7585{
7586 int *np = (int *) arg;
7587
7588 printf (gettext (" [%5d] DIE offset: %6" PRId64
7589 ", CU DIE offset: %6" PRId64 ", name: %s\n"),
7590 (*np)++, global->die_offset, global->cu_offset, global->name);
7591
7592 return 0;
7593}
7594
7595
7596/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
7597static void
7598print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
7599 Ebl *ebl, GElf_Ehdr *ehdr,
7600 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7601{
7602 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
7603 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
7604 (uint64_t) shdr->sh_offset);
7605
7606 int n = 0;
7607 (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
7608}
7609
7610/* Print the content of the DWARF string section '.debug_str'. */
7611static void
7612print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
7613 Ebl *ebl, GElf_Ehdr *ehdr,
7614 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7615{
Elliott Hughes03333822015-02-18 22:19:45 -08007616 const size_t sh_size = (dbg->sectiondata[IDX_debug_str] ?
7617 dbg->sectiondata[IDX_debug_str]->d_size : 0);
Ben Cheng25b3c042013-11-20 14:45:36 -08007618
7619 /* Compute floor(log16(shdr->sh_size)). */
7620 GElf_Addr tmp = sh_size;
7621 int digits = 1;
7622 while (tmp >= 16)
7623 {
7624 ++digits;
7625 tmp >>= 4;
7626 }
7627 digits = MAX (4, digits);
7628
7629 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
7630 " %*s String\n"),
7631 elf_ndxscn (scn),
7632 section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset,
7633 /* TRANS: the debugstr| prefix makes the string unique. */
7634 digits + 2, sgettext ("debugstr|Offset"));
7635
7636 Dwarf_Off offset = 0;
7637 while (offset < sh_size)
7638 {
7639 size_t len;
7640 const char *str = dwarf_getstring (dbg, offset, &len);
7641 if (unlikely (str == NULL))
7642 {
7643 printf (gettext (" *** error while reading strings: %s\n"),
7644 dwarf_errmsg (-1));
7645 break;
7646 }
7647
7648 printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str);
7649
7650 offset += len + 1;
7651 }
7652}
7653
7654
7655/* Print the content of the call frame search table section
7656 '.eh_frame_hdr'. */
7657static void
7658print_debug_frame_hdr_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
7659 Ebl *ebl __attribute__ ((unused)),
7660 GElf_Ehdr *ehdr __attribute__ ((unused)),
7661 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7662{
7663 printf (gettext ("\
7664\nCall frame search table section [%2zu] '.eh_frame_hdr':\n"),
7665 elf_ndxscn (scn));
7666
7667 Elf_Data *data = elf_rawdata (scn, NULL);
7668
7669 if (unlikely (data == NULL))
7670 {
7671 error (0, 0, gettext ("cannot get %s content: %s"),
7672 ".eh_frame_hdr", elf_errmsg (-1));
7673 return;
7674 }
7675
7676 const unsigned char *readp = data->d_buf;
7677 const unsigned char *const dataend = ((unsigned char *) data->d_buf
7678 + data->d_size);
7679
7680 if (unlikely (readp + 4 > dataend))
7681 {
7682 invalid_data:
7683 error (0, 0, gettext ("invalid data"));
7684 return;
7685 }
7686
7687 unsigned int version = *readp++;
7688 unsigned int eh_frame_ptr_enc = *readp++;
7689 unsigned int fde_count_enc = *readp++;
7690 unsigned int table_enc = *readp++;
7691
7692 printf (" version: %u\n"
7693 " eh_frame_ptr_enc: %#x ",
7694 version, eh_frame_ptr_enc);
7695 print_encoding_base ("", eh_frame_ptr_enc);
7696 printf (" fde_count_enc: %#x ", fde_count_enc);
7697 print_encoding_base ("", fde_count_enc);
7698 printf (" table_enc: %#x ", table_enc);
7699 print_encoding_base ("", table_enc);
7700
7701 uint64_t eh_frame_ptr = 0;
7702 if (eh_frame_ptr_enc != DW_EH_PE_omit)
7703 {
7704 readp = read_encoded (eh_frame_ptr_enc, readp, dataend, &eh_frame_ptr,
7705 dbg);
7706 if (unlikely (readp == NULL))
7707 goto invalid_data;
7708
7709 printf (" eh_frame_ptr: %#" PRIx64, eh_frame_ptr);
7710 if ((eh_frame_ptr_enc & 0x70) == DW_EH_PE_pcrel)
7711 printf (" (offset: %#" PRIx64 ")",
7712 /* +4 because of the 4 byte header of the section. */
7713 (uint64_t) shdr->sh_offset + 4 + eh_frame_ptr);
7714
7715 putchar_unlocked ('\n');
7716 }
7717
7718 uint64_t fde_count = 0;
7719 if (fde_count_enc != DW_EH_PE_omit)
7720 {
7721 readp = read_encoded (fde_count_enc, readp, dataend, &fde_count, dbg);
7722 if (unlikely (readp == NULL))
7723 goto invalid_data;
7724
7725 printf (" fde_count: %" PRIu64 "\n", fde_count);
7726 }
7727
7728 if (fde_count == 0 || table_enc == DW_EH_PE_omit)
7729 return;
7730
7731 puts (" Table:");
7732
7733 /* Optimize for the most common case. */
7734 if (table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
7735 while (fde_count > 0 && readp + 8 <= dataend)
7736 {
7737 int32_t initial_location = read_4sbyte_unaligned_inc (dbg, readp);
7738 uint64_t initial_offset = ((uint64_t) shdr->sh_offset
7739 + (int64_t) initial_location);
7740 int32_t address = read_4sbyte_unaligned_inc (dbg, readp);
7741 // XXX Possibly print symbol name or section offset for initial_offset
7742 printf (" %#" PRIx32 " (offset: %#6" PRIx64 ") -> %#" PRIx32
7743 " fde=[%6" PRIx64 "]\n",
7744 initial_location, initial_offset,
7745 address, address - (eh_frame_ptr + 4));
7746 }
7747 else
7748 while (0 && readp < dataend)
7749 {
7750
7751 }
7752}
7753
7754
7755/* Print the content of the exception handling table section
7756 '.eh_frame_hdr'. */
7757static void
7758print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
7759 Ebl *ebl __attribute__ ((unused)),
7760 GElf_Ehdr *ehdr __attribute__ ((unused)),
7761 Elf_Scn *scn,
7762 GElf_Shdr *shdr __attribute__ ((unused)),
7763 Dwarf *dbg __attribute__ ((unused)))
7764{
7765 printf (gettext ("\
7766\nException handling table section [%2zu] '.gcc_except_table':\n"),
7767 elf_ndxscn (scn));
7768
7769 Elf_Data *data = elf_rawdata (scn, NULL);
7770
7771 if (unlikely (data == NULL))
7772 {
7773 error (0, 0, gettext ("cannot get %s content: %s"),
7774 ".gcc_except_table", elf_errmsg (-1));
7775 return;
7776 }
7777
7778 const unsigned char *readp = data->d_buf;
7779 const unsigned char *const dataend = readp + data->d_size;
7780
7781 if (unlikely (readp + 1 > dataend))
7782 {
7783 invalid_data:
7784 error (0, 0, gettext ("invalid data"));
7785 return;
7786 }
7787 unsigned int lpstart_encoding = *readp++;
7788 printf (gettext (" LPStart encoding: %#x "), lpstart_encoding);
7789 print_encoding_base ("", lpstart_encoding);
7790 if (lpstart_encoding != DW_EH_PE_omit)
7791 {
7792 uint64_t lpstart;
7793 readp = read_encoded (lpstart_encoding, readp, dataend, &lpstart, dbg);
7794 printf (" LPStart: %#" PRIx64 "\n", lpstart);
7795 }
7796
7797 if (unlikely (readp + 1 > dataend))
7798 goto invalid_data;
7799 unsigned int ttype_encoding = *readp++;
7800 printf (gettext (" TType encoding: %#x "), ttype_encoding);
7801 print_encoding_base ("", ttype_encoding);
7802 const unsigned char *ttype_base = NULL;
7803 if (ttype_encoding != DW_EH_PE_omit)
7804 {
7805 unsigned int ttype_base_offset;
Elliott Hughes03333822015-02-18 22:19:45 -08007806 get_uleb128 (ttype_base_offset, readp, dataend);
Ben Cheng25b3c042013-11-20 14:45:36 -08007807 printf (" TType base offset: %#x\n", ttype_base_offset);
Elliott Hughes03333822015-02-18 22:19:45 -08007808 if ((size_t) (dataend - readp) > ttype_base_offset)
7809 ttype_base = readp + ttype_base_offset;
Ben Cheng25b3c042013-11-20 14:45:36 -08007810 }
7811
7812 if (unlikely (readp + 1 > dataend))
7813 goto invalid_data;
7814 unsigned int call_site_encoding = *readp++;
7815 printf (gettext (" Call site encoding: %#x "), call_site_encoding);
7816 print_encoding_base ("", call_site_encoding);
7817 unsigned int call_site_table_len;
Elliott Hughes03333822015-02-18 22:19:45 -08007818 get_uleb128 (call_site_table_len, readp, dataend);
Ben Cheng25b3c042013-11-20 14:45:36 -08007819
7820 const unsigned char *const action_table = readp + call_site_table_len;
7821 if (unlikely (action_table > dataend))
7822 goto invalid_data;
7823 unsigned int u = 0;
7824 unsigned int max_action = 0;
7825 while (readp < action_table)
7826 {
7827 if (u == 0)
7828 puts (gettext ("\n Call site table:"));
7829
7830 uint64_t call_site_start;
7831 readp = read_encoded (call_site_encoding, readp, dataend,
7832 &call_site_start, dbg);
7833 uint64_t call_site_length;
7834 readp = read_encoded (call_site_encoding, readp, dataend,
7835 &call_site_length, dbg);
7836 uint64_t landing_pad;
7837 readp = read_encoded (call_site_encoding, readp, dataend,
7838 &landing_pad, dbg);
7839 unsigned int action;
Elliott Hughes03333822015-02-18 22:19:45 -08007840 get_uleb128 (action, readp, dataend);
Ben Cheng25b3c042013-11-20 14:45:36 -08007841 max_action = MAX (action, max_action);
7842 printf (gettext (" [%4u] Call site start: %#" PRIx64 "\n"
7843 " Call site length: %" PRIu64 "\n"
7844 " Landing pad: %#" PRIx64 "\n"
7845 " Action: %u\n"),
7846 u++, call_site_start, call_site_length, landing_pad, action);
7847 }
Elliott Hughes03333822015-02-18 22:19:45 -08007848 if (readp != action_table)
7849 goto invalid_data;
Ben Cheng25b3c042013-11-20 14:45:36 -08007850
7851 unsigned int max_ar_filter = 0;
7852 if (max_action > 0)
7853 {
7854 puts ("\n Action table:");
7855
Elliott Hughes03333822015-02-18 22:19:45 -08007856 if ((size_t) (dataend - action_table) < max_action + 1)
7857 {
7858 fputs (gettext (" <INVALID DATA>\n"), stdout);
7859 return;
7860 }
7861
Ben Cheng25b3c042013-11-20 14:45:36 -08007862 const unsigned char *const action_table_end
7863 = action_table + max_action + 1;
7864
7865 u = 0;
7866 do
7867 {
7868 int ar_filter;
Elliott Hughes03333822015-02-18 22:19:45 -08007869 get_sleb128 (ar_filter, readp, action_table_end);
Ben Cheng25b3c042013-11-20 14:45:36 -08007870 if (ar_filter > 0 && (unsigned int) ar_filter > max_ar_filter)
7871 max_ar_filter = ar_filter;
7872 int ar_disp;
Elliott Hughes03333822015-02-18 22:19:45 -08007873 get_sleb128 (ar_disp, readp, action_table_end);
Ben Cheng25b3c042013-11-20 14:45:36 -08007874
7875 printf (" [%4u] ar_filter: % d\n"
7876 " ar_disp: % -5d",
7877 u, ar_filter, ar_disp);
7878 if (abs (ar_disp) & 1)
7879 printf (" -> [%4u]\n", u + (ar_disp + 1) / 2);
7880 else if (ar_disp != 0)
7881 puts (" -> ???");
7882 else
7883 putchar_unlocked ('\n');
7884 ++u;
7885 }
7886 while (readp < action_table_end);
7887 }
7888
Elliott Hughes03333822015-02-18 22:19:45 -08007889 if (max_ar_filter > 0 && ttype_base != NULL)
Ben Cheng25b3c042013-11-20 14:45:36 -08007890 {
7891 puts ("\n TType table:");
7892
7893 // XXX Not *4, size of encoding;
7894 switch (ttype_encoding & 7)
7895 {
7896 case DW_EH_PE_udata2:
7897 case DW_EH_PE_sdata2:
7898 readp = ttype_base - max_ar_filter * 2;
7899 break;
7900 case DW_EH_PE_udata4:
7901 case DW_EH_PE_sdata4:
7902 readp = ttype_base - max_ar_filter * 4;
7903 break;
7904 case DW_EH_PE_udata8:
7905 case DW_EH_PE_sdata8:
7906 readp = ttype_base - max_ar_filter * 8;
7907 break;
7908 default:
7909 error (1, 0, gettext ("invalid TType encoding"));
7910 }
7911
7912 do
7913 {
7914 uint64_t ttype;
7915 readp = read_encoded (ttype_encoding, readp, ttype_base, &ttype,
7916 dbg);
7917 printf (" [%4u] %#" PRIx64 "\n", max_ar_filter--, ttype);
7918 }
7919 while (readp < ttype_base);
7920 }
7921}
7922
7923/* Print the content of the '.gdb_index' section.
7924 http://sourceware.org/gdb/current/onlinedocs/gdb/Index-Section-Format.html
7925*/
7926static void
7927print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
7928 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
7929{
7930 printf (gettext ("\nGDB section [%2zu] '%s' at offset %#" PRIx64
7931 " contains %" PRId64 " bytes :\n"),
7932 elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
7933 (uint64_t) shdr->sh_offset, (uint64_t) shdr->sh_size);
7934
7935 Elf_Data *data = elf_rawdata (scn, NULL);
7936
7937 if (unlikely (data == NULL))
7938 {
7939 error (0, 0, gettext ("cannot get %s content: %s"),
7940 ".gdb_index", elf_errmsg (-1));
7941 return;
7942 }
7943
7944 // .gdb_index is always in little endian.
7945 Dwarf dummy_dbg = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB };
7946 dbg = &dummy_dbg;
7947
7948 const unsigned char *readp = data->d_buf;
7949 const unsigned char *const dataend = readp + data->d_size;
7950
7951 if (unlikely (readp + 4 > dataend))
7952 {
7953 invalid_data:
7954 error (0, 0, gettext ("invalid data"));
7955 return;
7956 }
7957
7958 int32_t vers = read_4ubyte_unaligned (dbg, readp);
7959 printf (gettext (" Version: %" PRId32 "\n"), vers);
7960
7961 // The only difference between version 4 and version 5 is the
Elliott Hughes03333822015-02-18 22:19:45 -08007962 // hash used for generating the table. Version 6 contains symbols
7963 // for inlined functions, older versions didn't. Version 7 adds
7964 // symbol kinds. Version 8 just indicates that it correctly includes
7965 // TUs for symbols.
7966 if (vers < 4 || vers > 8)
Ben Cheng25b3c042013-11-20 14:45:36 -08007967 {
7968 printf (gettext (" unknown version, cannot parse section\n"));
7969 return;
7970 }
7971
7972 readp += 4;
7973 if (unlikely (readp + 4 > dataend))
7974 goto invalid_data;
7975
7976 uint32_t cu_off = read_4ubyte_unaligned (dbg, readp);
7977 printf (gettext (" CU offset: %#" PRIx32 "\n"), cu_off);
7978
7979 readp += 4;
7980 if (unlikely (readp + 4 > dataend))
7981 goto invalid_data;
7982
7983 uint32_t tu_off = read_4ubyte_unaligned (dbg, readp);
7984 printf (gettext (" TU offset: %#" PRIx32 "\n"), tu_off);
7985
7986 readp += 4;
7987 if (unlikely (readp + 4 > dataend))
7988 goto invalid_data;
7989
7990 uint32_t addr_off = read_4ubyte_unaligned (dbg, readp);
7991 printf (gettext (" address offset: %#" PRIx32 "\n"), addr_off);
7992
7993 readp += 4;
7994 if (unlikely (readp + 4 > dataend))
7995 goto invalid_data;
7996
7997 uint32_t sym_off = read_4ubyte_unaligned (dbg, readp);
7998 printf (gettext (" symbol offset: %#" PRIx32 "\n"), sym_off);
7999
8000 readp += 4;
8001 if (unlikely (readp + 4 > dataend))
8002 goto invalid_data;
8003
8004 uint32_t const_off = read_4ubyte_unaligned (dbg, readp);
8005 printf (gettext (" constant offset: %#" PRIx32 "\n"), const_off);
8006
8007 readp = data->d_buf + cu_off;
8008
8009 const unsigned char *nextp = data->d_buf + tu_off;
Elliott Hughes03333822015-02-18 22:19:45 -08008010 size_t cu_nr = (nextp - readp) / 16;
Ben Cheng25b3c042013-11-20 14:45:36 -08008011
8012 printf (gettext ("\n CU list at offset %#" PRIx32
8013 " contains %zu entries:\n"),
Elliott Hughes03333822015-02-18 22:19:45 -08008014 cu_off, cu_nr);
Ben Cheng25b3c042013-11-20 14:45:36 -08008015
8016 size_t n = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008017 while (readp + 16 <= dataend && n < cu_nr)
Ben Cheng25b3c042013-11-20 14:45:36 -08008018 {
8019 uint64_t off = read_8ubyte_unaligned (dbg, readp);
8020 readp += 8;
8021
8022 uint64_t len = read_8ubyte_unaligned (dbg, readp);
8023 readp += 8;
8024
8025 printf (" [%4zu] start: %0#8" PRIx64
8026 ", length: %5" PRIu64 "\n", n, off, len);
8027 n++;
8028 }
8029
8030 readp = data->d_buf + tu_off;
8031 nextp = data->d_buf + addr_off;
Elliott Hughes03333822015-02-18 22:19:45 -08008032 size_t tu_nr = (nextp - readp) / 24;
Ben Cheng25b3c042013-11-20 14:45:36 -08008033
8034 printf (gettext ("\n TU list at offset %#" PRIx32
8035 " contains %zu entries:\n"),
Elliott Hughes03333822015-02-18 22:19:45 -08008036 tu_off, tu_nr);
Ben Cheng25b3c042013-11-20 14:45:36 -08008037
8038 n = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008039 while (readp + 24 <= dataend && n < tu_nr)
Ben Cheng25b3c042013-11-20 14:45:36 -08008040 {
8041 uint64_t off = read_8ubyte_unaligned (dbg, readp);
8042 readp += 8;
8043
8044 uint64_t type = read_8ubyte_unaligned (dbg, readp);
8045 readp += 8;
8046
8047 uint64_t sig = read_8ubyte_unaligned (dbg, readp);
8048 readp += 8;
8049
8050 printf (" [%4zu] CU offset: %5" PRId64
8051 ", type offset: %5" PRId64
8052 ", signature: %0#8" PRIx64 "\n", n, off, type, sig);
8053 n++;
8054 }
8055
8056 readp = data->d_buf + addr_off;
8057 nextp = data->d_buf + sym_off;
Elliott Hughes03333822015-02-18 22:19:45 -08008058 size_t addr_nr = (nextp - readp) / 20;
Ben Cheng25b3c042013-11-20 14:45:36 -08008059
8060 printf (gettext ("\n Address list at offset %#" PRIx32
8061 " contains %zu entries:\n"),
Elliott Hughes03333822015-02-18 22:19:45 -08008062 addr_off, addr_nr);
Ben Cheng25b3c042013-11-20 14:45:36 -08008063
8064 n = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008065 while (readp + 20 <= dataend && n < addr_nr)
Ben Cheng25b3c042013-11-20 14:45:36 -08008066 {
8067 uint64_t low = read_8ubyte_unaligned (dbg, readp);
8068 readp += 8;
8069
8070 uint64_t high = read_8ubyte_unaligned (dbg, readp);
8071 readp += 8;
8072
8073 uint32_t idx = read_4ubyte_unaligned (dbg, readp);
8074 readp += 4;
8075
Elliott Hughes03333822015-02-18 22:19:45 -08008076 char *l = format_dwarf_addr (dwflmod, 8, low, low);
8077 char *h = format_dwarf_addr (dwflmod, 8, high - 1, high);
Ben Cheng25b3c042013-11-20 14:45:36 -08008078 printf (" [%4zu] %s..%s, CU index: %5" PRId32 "\n",
8079 n, l, h, idx);
Elliott Hughes03333822015-02-18 22:19:45 -08008080 free (l);
8081 free (h);
Ben Cheng25b3c042013-11-20 14:45:36 -08008082 n++;
8083 }
8084
8085 readp = data->d_buf + sym_off;
8086 nextp = data->d_buf + const_off;
Elliott Hughes03333822015-02-18 22:19:45 -08008087 size_t sym_nr = (nextp - readp) / 8;
Ben Cheng25b3c042013-11-20 14:45:36 -08008088
8089 printf (gettext ("\n Symbol table at offset %#" PRIx32
8090 " contains %zu slots:\n"),
Elliott Hughes03333822015-02-18 22:19:45 -08008091 addr_off, sym_nr);
Ben Cheng25b3c042013-11-20 14:45:36 -08008092
8093 n = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008094 while (readp + 8 <= dataend && n < sym_nr)
Ben Cheng25b3c042013-11-20 14:45:36 -08008095 {
8096 uint32_t name = read_4ubyte_unaligned (dbg, readp);
8097 readp += 4;
8098
8099 uint32_t vector = read_4ubyte_unaligned (dbg, readp);
8100 readp += 4;
8101
8102 if (name != 0 || vector != 0)
8103 {
8104 const unsigned char *sym = data->d_buf + const_off + name;
Elliott Hughes03333822015-02-18 22:19:45 -08008105 if (unlikely (sym > dataend
8106 || memchr (sym, '\0', dataend - sym) == NULL))
Ben Cheng25b3c042013-11-20 14:45:36 -08008107 goto invalid_data;
8108
8109 printf (" [%4zu] symbol: %s, CUs: ", n, sym);
8110
8111 const unsigned char *readcus = data->d_buf + const_off + vector;
Elliott Hughes03333822015-02-18 22:19:45 -08008112 if (unlikely (readcus + 4 > dataend))
Ben Cheng25b3c042013-11-20 14:45:36 -08008113 goto invalid_data;
Ben Cheng25b3c042013-11-20 14:45:36 -08008114 uint32_t cus = read_4ubyte_unaligned (dbg, readcus);
8115 while (cus--)
8116 {
Elliott Hughes03333822015-02-18 22:19:45 -08008117 uint32_t cu_kind, cu, kind;
8118 bool is_static;
Ben Cheng25b3c042013-11-20 14:45:36 -08008119 readcus += 4;
Elliott Hughes03333822015-02-18 22:19:45 -08008120 if (unlikely (readcus + 4 > dataend))
8121 goto invalid_data;
8122 cu_kind = read_4ubyte_unaligned (dbg, readcus);
8123 cu = cu_kind & ((1 << 24) - 1);
8124 kind = (cu_kind >> 28) & 7;
8125 is_static = cu_kind & (1U << 31);
8126 if (cu > cu_nr - 1)
8127 printf ("%" PRId32 "T", cu - (uint32_t) cu_nr);
8128 else
8129 printf ("%" PRId32, cu);
8130 if (kind != 0)
8131 {
8132 printf (" (");
8133 switch (kind)
8134 {
8135 case 1:
8136 printf ("type");
8137 break;
8138 case 2:
8139 printf ("var");
8140 break;
8141 case 3:
8142 printf ("func");
8143 break;
8144 case 4:
8145 printf ("other");
8146 break;
8147 default:
8148 printf ("unknown-0x%" PRIx32, kind);
8149 break;
8150 }
8151 printf (":%c)", (is_static ? 'S' : 'G'));
8152 }
8153 if (cus > 0)
8154 printf (", ");
Ben Cheng25b3c042013-11-20 14:45:36 -08008155 }
8156 printf ("\n");
8157 }
8158 n++;
8159 }
8160}
8161
8162static void
8163print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
8164{
8165 /* Before we start the real work get a debug context descriptor. */
8166 Dwarf_Addr dwbias;
8167 Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
8168 Dwarf dummy_dbg =
8169 {
8170 .elf = ebl->elf,
8171 .other_byte_order = MY_ELFDATA != ehdr->e_ident[EI_DATA]
8172 };
8173 if (dbg == NULL)
8174 {
8175 if ((print_debug_sections & ~section_exception) != 0)
8176 error (0, 0, gettext ("cannot get debug context descriptor: %s"),
8177 dwfl_errmsg (-1));
8178 if ((print_debug_sections & section_exception) == 0)
8179 return;
8180 dbg = &dummy_dbg;
8181 }
8182
8183 /* Get the section header string table index. */
8184 size_t shstrndx;
8185 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
8186 error (EXIT_FAILURE, 0,
8187 gettext ("cannot get section header string table index"));
8188
8189 /* Look through all the sections for the debugging sections to print. */
8190 Elf_Scn *scn = NULL;
8191 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
8192 {
8193 GElf_Shdr shdr_mem;
8194 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
8195
8196 if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
8197 {
8198 static const struct
8199 {
8200 const char *name;
8201 enum section_e bitmask;
8202 void (*fp) (Dwfl_Module *, Ebl *,
8203 GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
8204 } debug_sections[] =
8205 {
8206#define NEW_SECTION(name) \
8207 { ".debug_" #name, section_##name, print_debug_##name##_section }
8208 NEW_SECTION (abbrev),
8209 NEW_SECTION (aranges),
8210 NEW_SECTION (frame),
8211 NEW_SECTION (info),
8212 NEW_SECTION (types),
8213 NEW_SECTION (line),
8214 NEW_SECTION (loc),
8215 NEW_SECTION (pubnames),
8216 NEW_SECTION (str),
8217 NEW_SECTION (macinfo),
Elliott Hughes03333822015-02-18 22:19:45 -08008218 NEW_SECTION (macro),
Ben Cheng25b3c042013-11-20 14:45:36 -08008219 NEW_SECTION (ranges),
8220 { ".eh_frame", section_frame | section_exception,
8221 print_debug_frame_section },
8222 { ".eh_frame_hdr", section_frame | section_exception,
8223 print_debug_frame_hdr_section },
8224 { ".gcc_except_table", section_frame | section_exception,
8225 print_debug_exception_table },
8226 { ".gdb_index", section_gdb_index, print_gdb_index_section }
8227 };
8228 const int ndebug_sections = (sizeof (debug_sections)
8229 / sizeof (debug_sections[0]));
8230 const char *name = elf_strptr (ebl->elf, shstrndx,
8231 shdr->sh_name);
Elliott Hughes03333822015-02-18 22:19:45 -08008232 if (name == NULL)
8233 continue;
Ben Cheng25b3c042013-11-20 14:45:36 -08008234
Elliott Hughes03333822015-02-18 22:19:45 -08008235 int n;
Ben Cheng25b3c042013-11-20 14:45:36 -08008236 for (n = 0; n < ndebug_sections; ++n)
8237 if (strcmp (name, debug_sections[n].name) == 0
8238#if USE_ZLIB
8239 || (name[0] == '.' && name[1] == 'z'
8240 && debug_sections[n].name[1] == 'd'
8241 && strcmp (&name[2], &debug_sections[n].name[1]) == 0)
8242#endif
8243 )
8244 {
8245 if ((print_debug_sections | implicit_debug_sections)
8246 & debug_sections[n].bitmask)
8247 debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
8248 break;
8249 }
8250 }
8251 }
8252
8253 reset_listptr (&known_loclistptr);
8254 reset_listptr (&known_rangelistptr);
8255}
8256
8257
8258#define ITEM_INDENT 4
Elliott Hughes03333822015-02-18 22:19:45 -08008259#define WRAP_COLUMN 75
Ben Cheng25b3c042013-11-20 14:45:36 -08008260
Elliott Hughes03333822015-02-18 22:19:45 -08008261/* Print "NAME: FORMAT", wrapping when output text would make the line
8262 exceed WRAP_COLUMN. Unpadded numbers look better for the core items
8263 but this function is also used for registers which should be printed
8264 aligned. Fortunately registers output uses fixed fields width (such
8265 as %11d) for the alignment.
8266
8267 Line breaks should not depend on the particular values although that
8268 may happen in some cases of the core items. */
8269
Ben Cheng25b3c042013-11-20 14:45:36 -08008270static unsigned int
Elliott Hughes03333822015-02-18 22:19:45 -08008271__attribute__ ((format (printf, 6, 7)))
Ben Cheng25b3c042013-11-20 14:45:36 -08008272print_core_item (unsigned int colno, char sep, unsigned int wrap,
Elliott Hughes03333822015-02-18 22:19:45 -08008273 size_t name_width, const char *name, const char *format, ...)
Ben Cheng25b3c042013-11-20 14:45:36 -08008274{
8275 size_t len = strlen (name);
8276 if (name_width < len)
8277 name_width = len;
8278
Elliott Hughes03333822015-02-18 22:19:45 -08008279 char *out;
8280 va_list ap;
8281 va_start (ap, format);
8282 int out_len = vasprintf (&out, format, ap);
8283 va_end (ap);
8284 if (out_len == -1)
8285 error (EXIT_FAILURE, 0, _("memory exhausted"));
8286
8287 size_t n = name_width + sizeof ": " - 1 + out_len;
Ben Cheng25b3c042013-11-20 14:45:36 -08008288
8289 if (colno == 0)
8290 {
8291 printf ("%*s", ITEM_INDENT, "");
8292 colno = ITEM_INDENT + n;
8293 }
8294 else if (colno + 2 + n < wrap)
8295 {
8296 printf ("%c ", sep);
8297 colno += 2 + n;
8298 }
8299 else
8300 {
8301 printf ("\n%*s", ITEM_INDENT, "");
8302 colno = ITEM_INDENT + n;
8303 }
8304
Elliott Hughes03333822015-02-18 22:19:45 -08008305 printf ("%s: %*s%s", name, (int) (name_width - len), "", out);
Ben Cheng25b3c042013-11-20 14:45:36 -08008306
Elliott Hughes03333822015-02-18 22:19:45 -08008307 free (out);
Ben Cheng25b3c042013-11-20 14:45:36 -08008308
8309 return colno;
8310}
8311
8312static const void *
8313convert (Elf *core, Elf_Type type, uint_fast16_t count,
8314 void *value, const void *data, size_t size)
8315{
8316 Elf_Data valuedata =
8317 {
8318 .d_type = type,
8319 .d_buf = value,
8320 .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT),
8321 .d_version = EV_CURRENT,
8322 };
8323 Elf_Data indata =
8324 {
8325 .d_type = type,
8326 .d_buf = (void *) data,
8327 .d_size = valuedata.d_size,
8328 .d_version = EV_CURRENT,
8329 };
8330
8331 Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
8332 ? elf32_xlatetom : elf64_xlatetom)
8333 (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
8334 if (d == NULL)
8335 error (EXIT_FAILURE, 0,
8336 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
8337
8338 return data + indata.d_size;
8339}
8340
8341typedef uint8_t GElf_Byte;
8342
8343static unsigned int
8344handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
8345 unsigned int colno, size_t *repeated_size)
8346{
8347 uint_fast16_t count = item->count ?: 1;
8348
8349#define TYPES \
Elliott Hughes03333822015-02-18 22:19:45 -08008350 DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8); \
8351 DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16); \
8352 DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32); \
8353 DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32); \
8354 DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64); \
8355 DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
Ben Cheng25b3c042013-11-20 14:45:36 -08008356
Elliott Hughes03333822015-02-18 22:19:45 -08008357#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
Ben Cheng25b3c042013-11-20 14:45:36 -08008358 union { TYPES; } value;
8359#undef DO_TYPE
8360
8361 void *data = &value;
8362 size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
8363 size_t convsize = size;
8364 if (repeated_size != NULL)
8365 {
8366 if (*repeated_size > size && (item->format == 'b' || item->format == 'B'))
8367 {
8368 data = alloca (*repeated_size);
8369 count *= *repeated_size / size;
8370 convsize = count * size;
8371 *repeated_size -= convsize;
8372 }
8373 else if (item->count != 0 || item->format != '\n')
8374 *repeated_size -= size;
8375 }
8376
8377 convert (core, item->type, count, data, desc + item->offset, convsize);
8378
8379 Elf_Type type = item->type;
8380 if (type == ELF_T_ADDR)
8381 type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD;
8382
8383 switch (item->format)
8384 {
8385 case 'd':
8386 assert (count == 1);
8387 switch (type)
8388 {
Elliott Hughes03333822015-02-18 22:19:45 -08008389#define DO_TYPE(NAME, Name, hex, dec) \
Ben Cheng25b3c042013-11-20 14:45:36 -08008390 case ELF_T_##NAME: \
Elliott Hughes03333822015-02-18 22:19:45 -08008391 colno = print_core_item (colno, ',', WRAP_COLUMN, \
8392 0, item->name, dec, value.Name[0]); \
Ben Cheng25b3c042013-11-20 14:45:36 -08008393 break
8394 TYPES;
8395#undef DO_TYPE
8396 default:
8397 abort ();
8398 }
8399 break;
8400
8401 case 'x':
8402 assert (count == 1);
8403 switch (type)
8404 {
Elliott Hughes03333822015-02-18 22:19:45 -08008405#define DO_TYPE(NAME, Name, hex, dec) \
Ben Cheng25b3c042013-11-20 14:45:36 -08008406 case ELF_T_##NAME: \
Elliott Hughes03333822015-02-18 22:19:45 -08008407 colno = print_core_item (colno, ',', WRAP_COLUMN, \
8408 0, item->name, hex, value.Name[0]); \
Ben Cheng25b3c042013-11-20 14:45:36 -08008409 break
8410 TYPES;
8411#undef DO_TYPE
8412 default:
8413 abort ();
8414 }
8415 break;
8416
8417 case 'b':
8418 case 'B':
8419 assert (size % sizeof (unsigned int) == 0);
8420 unsigned int nbits = count * size * 8;
8421 unsigned int pop = 0;
8422 for (const unsigned int *i = data; (void *) i < data + count * size; ++i)
8423 pop += __builtin_popcount (*i);
8424 bool negate = pop > nbits / 2;
8425 const unsigned int bias = item->format == 'b';
8426
8427 {
Elliott Hughes03333822015-02-18 22:19:45 -08008428 char printed[(negate ? nbits - pop : pop) * 16 + 1];
Ben Cheng25b3c042013-11-20 14:45:36 -08008429 char *p = printed;
8430 *p = '\0';
8431
8432 if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int))
8433 {
8434 assert (size == sizeof (unsigned int) * 2);
8435 for (unsigned int *i = data;
8436 (void *) i < data + count * size; i += 2)
8437 {
8438 unsigned int w = i[1];
8439 i[1] = i[0];
8440 i[0] = w;
8441 }
8442 }
8443
8444 unsigned int lastbit = 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008445 unsigned int run = 0;
Ben Cheng25b3c042013-11-20 14:45:36 -08008446 for (const unsigned int *i = data;
8447 (void *) i < data + count * size; ++i)
8448 {
8449 unsigned int bit = ((void *) i - data) * 8;
8450 unsigned int w = negate ? ~*i : *i;
Ben Cheng25b3c042013-11-20 14:45:36 -08008451 while (w != 0)
8452 {
8453 int n = ffs (w);
8454 w >>= n;
8455 bit += n;
8456
Elliott Hughes03333822015-02-18 22:19:45 -08008457 if (lastbit != 0 && lastbit + 1 == bit)
Ben Cheng25b3c042013-11-20 14:45:36 -08008458 ++run;
8459 else
8460 {
8461 if (lastbit == 0)
8462 p += sprintf (p, "%u", bit - bias);
8463 else if (run == 0)
8464 p += sprintf (p, ",%u", bit - bias);
8465 else
8466 p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias);
8467 run = 0;
8468 }
8469
8470 lastbit = bit;
8471 }
8472 }
Elliott Hughes03333822015-02-18 22:19:45 -08008473 if (lastbit > 0 && run > 0 && lastbit + 1 != nbits)
8474 p += sprintf (p, "-%u", lastbit - bias);
Ben Cheng25b3c042013-11-20 14:45:36 -08008475
Elliott Hughes03333822015-02-18 22:19:45 -08008476 colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
Ben Cheng25b3c042013-11-20 14:45:36 -08008477 negate ? "~<%s>" : "<%s>", printed);
8478 }
8479 break;
8480
8481 case 'T':
8482 case (char) ('T'|0x80):
8483 assert (count == 2);
8484 Dwarf_Word sec;
8485 Dwarf_Word usec;
Ben Cheng25b3c042013-11-20 14:45:36 -08008486 switch (type)
8487 {
Elliott Hughes03333822015-02-18 22:19:45 -08008488#define DO_TYPE(NAME, Name, hex, dec) \
Ben Cheng25b3c042013-11-20 14:45:36 -08008489 case ELF_T_##NAME: \
8490 sec = value.Name[0]; \
8491 usec = value.Name[1]; \
Ben Cheng25b3c042013-11-20 14:45:36 -08008492 break
8493 TYPES;
8494#undef DO_TYPE
8495 default:
8496 abort ();
8497 }
8498 if (unlikely (item->format == (char) ('T'|0x80)))
8499 {
8500 /* This is a hack for an ill-considered 64-bit ABI where
8501 tv_usec is actually a 32-bit field with 32 bits of padding
8502 rounding out struct timeval. We've already converted it as
8503 a 64-bit field. For little-endian, this just means the
8504 high half is the padding; it's presumably zero, but should
8505 be ignored anyway. For big-endian, it means the 32-bit
8506 field went into the high half of USEC. */
8507 GElf_Ehdr ehdr_mem;
8508 GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
8509 if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
8510 usec >>= 32;
8511 else
8512 usec &= UINT32_MAX;
8513 }
Elliott Hughes03333822015-02-18 22:19:45 -08008514 colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
8515 "%" PRIu64 ".%.6" PRIu64, sec, usec);
Ben Cheng25b3c042013-11-20 14:45:36 -08008516 break;
8517
8518 case 'c':
8519 assert (count == 1);
Elliott Hughes03333822015-02-18 22:19:45 -08008520 colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
8521 "%c", value.Byte[0]);
Ben Cheng25b3c042013-11-20 14:45:36 -08008522 break;
8523
8524 case 's':
Elliott Hughes03333822015-02-18 22:19:45 -08008525 colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
8526 "%.*s", (int) count, value.Byte);
Ben Cheng25b3c042013-11-20 14:45:36 -08008527 break;
8528
8529 case '\n':
8530 /* This is a list of strings separated by '\n'. */
8531 assert (item->count == 0);
8532 assert (repeated_size != NULL);
8533 assert (item->name == NULL);
8534 if (unlikely (item->offset >= *repeated_size))
8535 break;
8536
8537 const char *s = desc + item->offset;
8538 size = *repeated_size - item->offset;
8539 *repeated_size = 0;
8540 while (size > 0)
8541 {
8542 const char *eol = memchr (s, '\n', size);
8543 int len = size;
8544 if (eol != NULL)
8545 len = eol - s;
8546 printf ("%*s%.*s\n", ITEM_INDENT, "", len, s);
8547 if (eol == NULL)
8548 break;
8549 size -= eol + 1 - s;
8550 s = eol + 1;
8551 }
8552
Elliott Hughes03333822015-02-18 22:19:45 -08008553 colno = WRAP_COLUMN;
8554 break;
8555
8556 case 'h':
Ben Cheng25b3c042013-11-20 14:45:36 -08008557 break;
8558
8559 default:
8560 error (0, 0, "XXX not handling format '%c' for %s",
8561 item->format, item->name);
8562 break;
8563 }
8564
8565#undef TYPES
8566
8567 return colno;
8568}
8569
8570
8571/* Sort items by group, and by layout offset within each group. */
8572static int
8573compare_core_items (const void *a, const void *b)
8574{
8575 const Ebl_Core_Item *const *p1 = a;
8576 const Ebl_Core_Item *const *p2 = b;
8577 const Ebl_Core_Item *item1 = *p1;
8578 const Ebl_Core_Item *item2 = *p2;
8579
8580 return ((item1->group == item2->group ? 0
8581 : strcmp (item1->group, item2->group))
8582 ?: (int) item1->offset - (int) item2->offset);
8583}
8584
8585/* Sort item groups by layout offset of the first item in the group. */
8586static int
8587compare_core_item_groups (const void *a, const void *b)
8588{
8589 const Ebl_Core_Item *const *const *p1 = a;
8590 const Ebl_Core_Item *const *const *p2 = b;
8591 const Ebl_Core_Item *const *group1 = *p1;
8592 const Ebl_Core_Item *const *group2 = *p2;
8593 const Ebl_Core_Item *item1 = *group1;
8594 const Ebl_Core_Item *item2 = *group2;
8595
8596 return (int) item1->offset - (int) item2->offset;
8597}
8598
8599static unsigned int
8600handle_core_items (Elf *core, const void *desc, size_t descsz,
8601 const Ebl_Core_Item *items, size_t nitems)
8602{
8603 if (nitems == 0)
8604 return 0;
Elliott Hughes03333822015-02-18 22:19:45 -08008605 unsigned int colno = 0;
8606
8607 /* FORMAT '\n' makes sense to be present only as a single item as it
8608 processes all the data of a note. FORMATs 'b' and 'B' have a special case
8609 if present as a single item but they can be also processed with other
8610 items below. */
8611 if (nitems == 1 && (items[0].format == '\n' || items[0].format == 'b'
8612 || items[0].format == 'B'))
8613 {
8614 assert (items[0].offset == 0);
8615 size_t size = descsz;
8616 colno = handle_core_item (core, items, desc, colno, &size);
8617 /* If SIZE is not zero here there is some remaining data. But we do not
8618 know how to process it anyway. */
8619 return colno;
8620 }
8621 for (size_t i = 0; i < nitems; ++i)
8622 assert (items[i].format != '\n');
Ben Cheng25b3c042013-11-20 14:45:36 -08008623
8624 /* Sort to collect the groups together. */
8625 const Ebl_Core_Item *sorted_items[nitems];
8626 for (size_t i = 0; i < nitems; ++i)
8627 sorted_items[i] = &items[i];
8628 qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
8629
8630 /* Collect the unique groups and sort them. */
8631 const Ebl_Core_Item **groups[nitems];
8632 groups[0] = &sorted_items[0];
8633 size_t ngroups = 1;
8634 for (size_t i = 1; i < nitems; ++i)
8635 if (sorted_items[i]->group != sorted_items[i - 1]->group
8636 && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
8637 groups[ngroups++] = &sorted_items[i];
8638 qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
8639
8640 /* Write out all the groups. */
Ben Cheng25b3c042013-11-20 14:45:36 -08008641 const void *last = desc;
Ben Cheng25b3c042013-11-20 14:45:36 -08008642 do
8643 {
8644 for (size_t i = 0; i < ngroups; ++i)
8645 {
8646 for (const Ebl_Core_Item **item = groups[i];
8647 (item < &sorted_items[nitems]
8648 && ((*item)->group == groups[i][0]->group
8649 || !strcmp ((*item)->group, groups[i][0]->group)));
8650 ++item)
8651 colno = handle_core_item (core, *item, desc, colno, NULL);
8652
8653 /* Force a line break at the end of the group. */
Elliott Hughes03333822015-02-18 22:19:45 -08008654 colno = WRAP_COLUMN;
Ben Cheng25b3c042013-11-20 14:45:36 -08008655 }
8656
8657 if (descsz == 0)
8658 break;
8659
8660 /* This set of items consumed a certain amount of the note's data.
8661 If there is more data there, we have another unit of the same size.
8662 Loop to print that out too. */
8663 const Ebl_Core_Item *item = &items[nitems - 1];
8664 size_t eltsz = item->offset + gelf_fsize (core, item->type,
8665 item->count ?: 1, EV_CURRENT);
8666
8667 int reps = -1;
8668 do
8669 {
8670 ++reps;
8671 desc += eltsz;
8672 descsz -= eltsz;
8673 }
8674 while (descsz >= eltsz && !memcmp (desc, last, eltsz));
8675
8676 if (reps == 1)
8677 {
8678 /* For just one repeat, print it unabridged twice. */
8679 desc -= eltsz;
8680 descsz += eltsz;
8681 }
8682 else if (reps > 1)
8683 printf (gettext ("\n%*s... <repeats %u more times> ..."),
8684 ITEM_INDENT, "", reps);
8685
8686 last = desc;
8687 }
8688 while (descsz > 0);
8689
8690 return colno;
8691}
8692
8693static unsigned int
8694handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
8695 unsigned int colno)
8696{
8697 desc += regloc->offset;
8698
8699 abort (); /* XXX */
8700 return colno;
8701}
8702
8703
8704static unsigned int
8705handle_core_register (Ebl *ebl, Elf *core, int maxregname,
8706 const Ebl_Register_Location *regloc, const void *desc,
8707 unsigned int colno)
8708{
8709 if (regloc->bits % 8 != 0)
8710 return handle_bit_registers (regloc, desc, colno);
8711
8712 desc += regloc->offset;
8713
8714 for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
8715 {
8716 char name[REGNAMESZ];
8717 int bits;
8718 int type;
8719 register_info (ebl, reg, regloc, name, &bits, &type);
8720
8721#define TYPES \
Elliott Hughes03333822015-02-18 22:19:45 -08008722 BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8); \
8723 BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16); \
8724 BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32); \
8725 BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64)
Ben Cheng25b3c042013-11-20 14:45:36 -08008726
Elliott Hughes03333822015-02-18 22:19:45 -08008727#define BITS(bits, xtype, sfmt, ufmt) \
Ben Cheng25b3c042013-11-20 14:45:36 -08008728 uint##bits##_t b##bits; int##bits##_t b##bits##s
8729 union { TYPES; uint64_t b128[2]; } value;
8730#undef BITS
8731
8732 switch (type)
8733 {
8734 case DW_ATE_unsigned:
8735 case DW_ATE_signed:
8736 case DW_ATE_address:
8737 switch (bits)
8738 {
Elliott Hughes03333822015-02-18 22:19:45 -08008739#define BITS(bits, xtype, sfmt, ufmt) \
Ben Cheng25b3c042013-11-20 14:45:36 -08008740 case bits: \
8741 desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0); \
8742 if (type == DW_ATE_signed) \
Elliott Hughes03333822015-02-18 22:19:45 -08008743 colno = print_core_item (colno, ' ', WRAP_COLUMN, \
Ben Cheng25b3c042013-11-20 14:45:36 -08008744 maxregname, name, \
Elliott Hughes03333822015-02-18 22:19:45 -08008745 sfmt, value.b##bits##s); \
Ben Cheng25b3c042013-11-20 14:45:36 -08008746 else \
Elliott Hughes03333822015-02-18 22:19:45 -08008747 colno = print_core_item (colno, ' ', WRAP_COLUMN, \
Ben Cheng25b3c042013-11-20 14:45:36 -08008748 maxregname, name, \
Elliott Hughes03333822015-02-18 22:19:45 -08008749 ufmt, value.b##bits); \
Ben Cheng25b3c042013-11-20 14:45:36 -08008750 break
8751
8752 TYPES;
8753
8754 case 128:
8755 assert (type == DW_ATE_unsigned);
8756 desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0);
8757 int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
Elliott Hughes03333822015-02-18 22:19:45 -08008758 colno = print_core_item (colno, ' ', WRAP_COLUMN,
Ben Cheng25b3c042013-11-20 14:45:36 -08008759 maxregname, name,
Elliott Hughes03333822015-02-18 22:19:45 -08008760 "0x%.16" PRIx64 "%.16" PRIx64,
Ben Cheng25b3c042013-11-20 14:45:36 -08008761 value.b128[!be], value.b128[be]);
8762 break;
8763
8764 default:
8765 abort ();
8766#undef BITS
8767 }
8768 break;
8769
8770 default:
8771 /* Print each byte in hex, the whole thing in native byte order. */
8772 assert (bits % 8 == 0);
8773 const uint8_t *bytes = desc;
8774 desc += bits / 8;
8775 char hex[bits / 4 + 1];
8776 hex[bits / 4] = '\0';
8777 int incr = 1;
8778 if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
8779 {
8780 bytes += bits / 8 - 1;
8781 incr = -1;
8782 }
8783 size_t idx = 0;
8784 for (char *h = hex; bits > 0; bits -= 8, idx += incr)
8785 {
8786 *h++ = "0123456789abcdef"[bytes[idx] >> 4];
8787 *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
8788 }
Elliott Hughes03333822015-02-18 22:19:45 -08008789 colno = print_core_item (colno, ' ', WRAP_COLUMN,
8790 maxregname, name, "0x%s", hex);
Ben Cheng25b3c042013-11-20 14:45:36 -08008791 break;
8792 }
8793 desc += regloc->pad;
8794
8795#undef TYPES
8796 }
8797
8798 return colno;
8799}
8800
8801
8802struct register_info
8803{
8804 const Ebl_Register_Location *regloc;
8805 const char *set;
8806 char name[REGNAMESZ];
8807 int regno;
8808 int bits;
8809 int type;
8810};
8811
8812static int
8813register_bitpos (const struct register_info *r)
8814{
8815 return (r->regloc->offset * 8
8816 + ((r->regno - r->regloc->regno)
8817 * (r->regloc->bits + r->regloc->pad * 8)));
8818}
8819
8820static int
8821compare_sets_by_info (const struct register_info *r1,
8822 const struct register_info *r2)
8823{
8824 return ((int) r2->bits - (int) r1->bits
8825 ?: register_bitpos (r1) - register_bitpos (r2));
8826}
8827
8828/* Sort registers by set, and by size and layout offset within each set. */
8829static int
8830compare_registers (const void *a, const void *b)
8831{
8832 const struct register_info *r1 = a;
8833 const struct register_info *r2 = b;
8834
8835 /* Unused elements sort last. */
8836 if (r1->regloc == NULL)
8837 return r2->regloc == NULL ? 0 : 1;
8838 if (r2->regloc == NULL)
8839 return -1;
8840
8841 return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
8842 ?: compare_sets_by_info (r1, r2));
8843}
8844
8845/* Sort register sets by layout offset of the first register in the set. */
8846static int
8847compare_register_sets (const void *a, const void *b)
8848{
8849 const struct register_info *const *p1 = a;
8850 const struct register_info *const *p2 = b;
8851 return compare_sets_by_info (*p1, *p2);
8852}
8853
8854static unsigned int
8855handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
8856 const Ebl_Register_Location *reglocs, size_t nregloc)
8857{
8858 if (nregloc == 0)
8859 return 0;
8860
8861 ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
8862 if (maxnreg <= 0)
8863 {
8864 for (size_t i = 0; i < nregloc; ++i)
8865 if (maxnreg < reglocs[i].regno + reglocs[i].count)
8866 maxnreg = reglocs[i].regno + reglocs[i].count;
8867 assert (maxnreg > 0);
8868 }
8869
8870 struct register_info regs[maxnreg];
8871 memset (regs, 0, sizeof regs);
8872
8873 /* Sort to collect the sets together. */
8874 int maxreg = 0;
8875 for (size_t i = 0; i < nregloc; ++i)
8876 for (int reg = reglocs[i].regno;
8877 reg < reglocs[i].regno + reglocs[i].count;
8878 ++reg)
8879 {
8880 assert (reg < maxnreg);
8881 if (reg > maxreg)
8882 maxreg = reg;
8883 struct register_info *info = &regs[reg];
8884 info->regloc = &reglocs[i];
8885 info->regno = reg;
8886 info->set = register_info (ebl, reg, &reglocs[i],
8887 info->name, &info->bits, &info->type);
8888 }
8889 qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
8890
8891 /* Collect the unique sets and sort them. */
8892 inline bool same_set (const struct register_info *a,
8893 const struct register_info *b)
8894 {
8895 return (a < &regs[maxnreg] && a->regloc != NULL
8896 && b < &regs[maxnreg] && b->regloc != NULL
8897 && a->bits == b->bits
8898 && (a->set == b->set || !strcmp (a->set, b->set)));
8899 }
8900 struct register_info *sets[maxreg + 1];
8901 sets[0] = &regs[0];
8902 size_t nsets = 1;
8903 for (int i = 1; i <= maxreg; ++i)
8904 if (regs[i].regloc != NULL && !same_set (&regs[i], &regs[i - 1]))
8905 sets[nsets++] = &regs[i];
8906 qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
8907
8908 /* Write out all the sets. */
8909 unsigned int colno = 0;
8910 for (size_t i = 0; i < nsets; ++i)
8911 {
8912 /* Find the longest name of a register in this set. */
8913 size_t maxname = 0;
8914 const struct register_info *end;
8915 for (end = sets[i]; same_set (sets[i], end); ++end)
8916 {
8917 size_t len = strlen (end->name);
8918 if (len > maxname)
8919 maxname = len;
8920 }
8921
8922 for (const struct register_info *reg = sets[i];
8923 reg < end;
8924 reg += reg->regloc->count ?: 1)
8925 colno = handle_core_register (ebl, core, maxname,
8926 reg->regloc, desc, colno);
8927
8928 /* Force a line break at the end of the group. */
Elliott Hughes03333822015-02-18 22:19:45 -08008929 colno = WRAP_COLUMN;
Ben Cheng25b3c042013-11-20 14:45:36 -08008930 }
8931
8932 return colno;
8933}
8934
8935static void
8936handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
8937{
8938 Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV);
8939 if (data == NULL)
8940 elf_error:
8941 error (EXIT_FAILURE, 0,
8942 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
8943
8944 const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT);
8945 for (size_t i = 0; i < nauxv; ++i)
8946 {
8947 GElf_auxv_t av_mem;
8948 GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem);
8949 if (av == NULL)
8950 goto elf_error;
8951
8952 const char *name;
8953 const char *fmt;
8954 if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
8955 {
8956 /* Unknown type. */
8957 if (av->a_un.a_val == 0)
8958 printf (" %" PRIu64 "\n", av->a_type);
8959 else
8960 printf (" %" PRIu64 ": %#" PRIx64 "\n",
8961 av->a_type, av->a_un.a_val);
8962 }
8963 else
8964 switch (fmt[0])
8965 {
8966 case '\0': /* Normally zero. */
8967 if (av->a_un.a_val == 0)
8968 {
8969 printf (" %s\n", name);
8970 break;
8971 }
8972 /* Fall through */
8973 case 'x': /* hex */
8974 case 'p': /* address */
8975 case 's': /* address of string */
8976 printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val);
8977 break;
8978 case 'u':
8979 printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val);
8980 break;
8981 case 'd':
8982 printf (" %s: %" PRId64 "\n", name, av->a_un.a_val);
8983 break;
8984
8985 case 'b':
8986 printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val);
8987 GElf_Xword bit = 1;
8988 const char *pfx = "<";
8989 for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
8990 {
8991 if (av->a_un.a_val & bit)
8992 {
8993 printf ("%s%s", pfx, p);
8994 pfx = " ";
8995 }
8996 bit <<= 1;
8997 }
8998 printf (">\n");
8999 break;
9000
9001 default:
9002 abort ();
9003 }
9004 }
9005}
9006
Elliott Hughes03333822015-02-18 22:19:45 -08009007static bool
9008buf_has_data (unsigned char const *ptr, unsigned char const *end, size_t sz)
9009{
9010 return ptr < end && (size_t) (end - ptr) >= sz;
9011}
9012
9013static bool
9014buf_read_int (Elf *core, unsigned char const **ptrp, unsigned char const *end,
9015 int *retp)
9016{
9017 if (! buf_has_data (*ptrp, end, 4))
9018 return false;
9019
9020 *ptrp = convert (core, ELF_T_WORD, 1, retp, *ptrp, 4);
9021 return true;
9022}
9023
9024static bool
9025buf_read_ulong (Elf *core, unsigned char const **ptrp, unsigned char const *end,
9026 uint64_t *retp)
9027{
9028 size_t sz = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
9029 if (! buf_has_data (*ptrp, end, sz))
9030 return false;
9031
9032 union
9033 {
9034 uint64_t u64;
9035 uint32_t u32;
9036 } u;
9037
9038 *ptrp = convert (core, ELF_T_ADDR, 1, &u, *ptrp, sz);
9039
9040 if (sz == 4)
9041 *retp = u.u32;
9042 else
9043 *retp = u.u64;
9044 return true;
9045}
9046
9047static void
9048handle_siginfo_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
9049{
9050 Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_BYTE);
9051 if (data == NULL)
9052 error (EXIT_FAILURE, 0,
9053 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
9054
9055 unsigned char const *ptr = data->d_buf;
9056 unsigned char const *const end = data->d_buf + data->d_size;
9057
9058 /* Siginfo head is three ints: signal number, error number, origin
9059 code. */
9060 int si_signo, si_errno, si_code;
9061 if (! buf_read_int (core, &ptr, end, &si_signo)
9062 || ! buf_read_int (core, &ptr, end, &si_errno)
9063 || ! buf_read_int (core, &ptr, end, &si_code))
9064 {
9065 fail:
9066 printf (" Not enough data in NT_SIGINFO note.\n");
9067 return;
9068 }
9069
9070 /* Next is a pointer-aligned union of structures. On 64-bit
9071 machines, that implies a word of padding. */
9072 if (gelf_getclass (core) == ELFCLASS64)
9073 ptr += 4;
9074
9075 printf (" si_signo: %d, si_errno: %d, si_code: %d\n",
9076 si_signo, si_errno, si_code);
9077
9078 if (si_code > 0)
9079 switch (si_signo)
9080 {
9081 case SIGILL:
9082 case SIGFPE:
9083 case SIGSEGV:
9084 case SIGBUS:
9085 {
9086 uint64_t addr;
9087 if (! buf_read_ulong (core, &ptr, end, &addr))
9088 goto fail;
9089 printf (" fault address: %#" PRIx64 "\n", addr);
9090 break;
9091 }
9092 default:
9093 ;
9094 }
9095 else if (si_code == SI_USER)
9096 {
9097 int pid, uid;
9098 if (! buf_read_int (core, &ptr, end, &pid)
9099 || ! buf_read_int (core, &ptr, end, &uid))
9100 goto fail;
9101 printf (" sender PID: %d, sender UID: %d\n", pid, uid);
9102 }
9103}
9104
9105static void
9106handle_file_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
9107{
9108 Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_BYTE);
9109 if (data == NULL)
9110 error (EXIT_FAILURE, 0,
9111 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
9112
9113 unsigned char const *ptr = data->d_buf;
9114 unsigned char const *const end = data->d_buf + data->d_size;
9115
9116 uint64_t count, page_size;
9117 if (! buf_read_ulong (core, &ptr, end, &count)
9118 || ! buf_read_ulong (core, &ptr, end, &page_size))
9119 {
9120 fail:
9121 printf (" Not enough data in NT_FILE note.\n");
9122 return;
9123 }
9124
9125 size_t addrsize = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
9126 uint64_t maxcount = (size_t) (end - ptr) / (3 * addrsize);
9127 if (count > maxcount)
9128 goto fail;
9129
9130 /* Where file names are stored. */
9131 unsigned char const *const fstart = ptr + 3 * count * addrsize;
9132 char const *fptr = (char *) fstart;
9133
9134 printf (" %" PRId64 " files:\n", count);
9135 for (uint64_t i = 0; i < count; ++i)
9136 {
9137 uint64_t mstart, mend, moffset;
9138 if (! buf_read_ulong (core, &ptr, fstart, &mstart)
9139 || ! buf_read_ulong (core, &ptr, fstart, &mend)
9140 || ! buf_read_ulong (core, &ptr, fstart, &moffset))
9141 goto fail;
9142
9143 const char *fnext = memchr (fptr, '\0', (char *) end - fptr);
9144 if (fnext == NULL)
9145 goto fail;
9146
9147 int ct = printf (" %08" PRIx64 "-%08" PRIx64
9148 " %08" PRIx64 " %" PRId64,
9149 mstart, mend, moffset * page_size, mend - mstart);
9150 printf ("%*s%s\n", ct > 50 ? 3 : 53 - ct, "", fptr);
9151
9152 fptr = fnext + 1;
9153 }
9154}
9155
Ben Cheng25b3c042013-11-20 14:45:36 -08009156static void
9157handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr,
9158 const char *name, const void *desc)
9159{
9160 GElf_Word regs_offset;
9161 size_t nregloc;
9162 const Ebl_Register_Location *reglocs;
9163 size_t nitems;
9164 const Ebl_Core_Item *items;
9165
9166 if (! ebl_core_note (ebl, nhdr, name,
9167 &regs_offset, &nregloc, &reglocs, &nitems, &items))
9168 return;
9169
9170 /* Pass 0 for DESCSZ when there are registers in the note,
9171 so that the ITEMS array does not describe the whole thing.
9172 For non-register notes, the actual descsz might be a multiple
9173 of the unit size, not just exactly the unit size. */
9174 unsigned int colno = handle_core_items (ebl->elf, desc,
9175 nregloc == 0 ? nhdr->n_descsz : 0,
9176 items, nitems);
9177 if (colno != 0)
9178 putchar_unlocked ('\n');
9179
9180 colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
9181 reglocs, nregloc);
9182 if (colno != 0)
9183 putchar_unlocked ('\n');
9184}
9185
9186static void
9187handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
9188 GElf_Off start, Elf_Data *data)
9189{
9190 fputs_unlocked (gettext (" Owner Data size Type\n"), stdout);
9191
9192 if (data == NULL)
9193 goto bad_note;
9194
9195 size_t offset = 0;
9196 GElf_Nhdr nhdr;
9197 size_t name_offset;
9198 size_t desc_offset;
9199 while (offset < data->d_size
9200 && (offset = gelf_getnote (data, offset,
9201 &nhdr, &name_offset, &desc_offset)) > 0)
9202 {
9203 const char *name = data->d_buf + name_offset;
9204 const char *desc = data->d_buf + desc_offset;
9205
9206 char buf[100];
9207 char buf2[100];
9208 printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
9209 (int) nhdr.n_namesz, name, nhdr.n_descsz,
9210 ehdr->e_type == ET_CORE
9211 ? ebl_core_note_type_name (ebl, nhdr.n_type,
9212 buf, sizeof (buf))
9213 : ebl_object_note_type_name (ebl, name, nhdr.n_type,
9214 buf2, sizeof (buf2)));
9215
9216 /* Filter out invalid entries. */
9217 if (memchr (name, '\0', nhdr.n_namesz) != NULL
9218 /* XXX For now help broken Linux kernels. */
9219 || 1)
9220 {
9221 if (ehdr->e_type == ET_CORE)
9222 {
9223 if (nhdr.n_type == NT_AUXV
9224 && (nhdr.n_namesz == 4 /* Broken old Linux kernels. */
9225 || (nhdr.n_namesz == 5 && name[4] == '\0'))
9226 && !memcmp (name, "CORE", 4))
9227 handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz,
9228 start + desc_offset);
Elliott Hughes03333822015-02-18 22:19:45 -08009229 else if (nhdr.n_namesz == 5 && strcmp (name, "CORE") == 0)
9230 switch (nhdr.n_type)
9231 {
9232 case NT_SIGINFO:
9233 handle_siginfo_note (ebl->elf, nhdr.n_descsz,
9234 start + desc_offset);
9235 break;
9236
9237 case NT_FILE:
9238 handle_file_note (ebl->elf, nhdr.n_descsz,
9239 start + desc_offset);
9240 break;
9241
9242 default:
9243 handle_core_note (ebl, &nhdr, name, desc);
9244 }
Ben Cheng25b3c042013-11-20 14:45:36 -08009245 else
9246 handle_core_note (ebl, &nhdr, name, desc);
9247 }
9248 else
9249 ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
9250 }
9251 }
9252
9253 if (offset == data->d_size)
9254 return;
9255
9256 bad_note:
9257 error (EXIT_FAILURE, 0,
9258 gettext ("cannot get content of note section: %s"),
9259 elf_errmsg (-1));
9260}
9261
9262static void
9263handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
9264{
9265 /* If we have section headers, just look for SHT_NOTE sections.
9266 In a debuginfo file, the program headers are not reliable. */
9267 if (shnum != 0)
9268 {
9269 /* Get the section header string table index. */
9270 size_t shstrndx;
9271 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
9272 error (EXIT_FAILURE, 0,
9273 gettext ("cannot get section header string table index"));
9274
9275 Elf_Scn *scn = NULL;
9276 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
9277 {
9278 GElf_Shdr shdr_mem;
9279 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
9280
9281 if (shdr == NULL || shdr->sh_type != SHT_NOTE)
9282 /* Not what we are looking for. */
9283 continue;
9284
9285 printf (gettext ("\
9286\nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
9287 elf_ndxscn (scn),
9288 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
9289 shdr->sh_size, shdr->sh_offset);
9290
9291 handle_notes_data (ebl, ehdr, shdr->sh_offset,
9292 elf_getdata (scn, NULL));
9293 }
9294 return;
9295 }
9296
9297 /* We have to look through the program header to find the note
9298 sections. There can be more than one. */
9299 for (size_t cnt = 0; cnt < phnum; ++cnt)
9300 {
9301 GElf_Phdr mem;
9302 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
9303
9304 if (phdr == NULL || phdr->p_type != PT_NOTE)
9305 /* Not what we are looking for. */
9306 continue;
9307
9308 printf (gettext ("\
9309\nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
9310 phdr->p_filesz, phdr->p_offset);
9311
9312 handle_notes_data (ebl, ehdr, phdr->p_offset,
9313 elf_getdata_rawchunk (ebl->elf,
9314 phdr->p_offset, phdr->p_filesz,
9315 ELF_T_NHDR));
9316 }
9317}
9318
9319
9320static void
9321hex_dump (const uint8_t *data, size_t len)
9322{
9323 size_t pos = 0;
9324 while (pos < len)
9325 {
9326 printf (" 0x%08Zx ", pos);
9327
9328 const size_t chunk = MIN (len - pos, 16);
9329
9330 for (size_t i = 0; i < chunk; ++i)
9331 if (i % 4 == 3)
9332 printf ("%02x ", data[pos + i]);
9333 else
9334 printf ("%02x", data[pos + i]);
9335
9336 if (chunk < 16)
9337 printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
9338
9339 for (size_t i = 0; i < chunk; ++i)
9340 {
9341 unsigned char b = data[pos + i];
9342 printf ("%c", isprint (b) ? b : '.');
9343 }
9344
9345 putchar ('\n');
9346 pos += chunk;
9347 }
9348}
9349
9350static void
9351dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
9352{
9353 if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
9354 printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
9355 elf_ndxscn (scn), name);
9356 else
9357 {
9358 Elf_Data *data = elf_rawdata (scn, NULL);
9359 if (data == NULL)
9360 error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
9361 elf_ndxscn (scn), name, elf_errmsg (-1));
9362 else
9363 {
9364 printf (gettext ("\nHex dump of section [%Zu] '%s', %" PRIu64
9365 " bytes at offset %#0" PRIx64 ":\n"),
9366 elf_ndxscn (scn), name,
9367 shdr->sh_size, shdr->sh_offset);
9368 hex_dump (data->d_buf, data->d_size);
9369 }
9370 }
9371}
9372
9373static void
9374print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
9375{
9376 if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
9377 printf (gettext ("\nSection [%Zu] '%s' has no strings to dump.\n"),
9378 elf_ndxscn (scn), name);
9379 else
9380 {
9381 Elf_Data *data = elf_rawdata (scn, NULL);
9382 if (data == NULL)
9383 error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
9384 elf_ndxscn (scn), name, elf_errmsg (-1));
9385 else
9386 {
9387 printf (gettext ("\nString section [%Zu] '%s' contains %" PRIu64
9388 " bytes at offset %#0" PRIx64 ":\n"),
9389 elf_ndxscn (scn), name,
9390 shdr->sh_size, shdr->sh_offset);
9391
9392 const char *start = data->d_buf;
9393 const char *const limit = start + data->d_size;
9394 do
9395 {
9396 const char *end = memchr (start, '\0', limit - start);
9397 const size_t pos = start - (const char *) data->d_buf;
9398 if (unlikely (end == NULL))
9399 {
9400 printf (" [%6Zx]- %.*s\n",
9401 pos, (int) (limit - start), start);
9402 break;
9403 }
9404 printf (" [%6Zx] %s\n", pos, start);
9405 start = end + 1;
9406 } while (start < limit);
9407 }
9408 }
9409}
9410
9411static void
9412for_each_section_argument (Elf *elf, const struct section_argument *list,
9413 void (*dump) (Elf_Scn *scn, const GElf_Shdr *shdr,
9414 const char *name))
9415{
9416 /* Get the section header string table index. */
9417 size_t shstrndx;
9418 if (elf_getshdrstrndx (elf, &shstrndx) < 0)
9419 error (EXIT_FAILURE, 0,
9420 gettext ("cannot get section header string table index"));
9421
9422 for (const struct section_argument *a = list; a != NULL; a = a->next)
9423 {
9424 Elf_Scn *scn;
9425 GElf_Shdr shdr_mem;
9426 const char *name = NULL;
9427
9428 char *endp = NULL;
9429 unsigned long int shndx = strtoul (a->arg, &endp, 0);
9430 if (endp != a->arg && *endp == '\0')
9431 {
9432 scn = elf_getscn (elf, shndx);
9433 if (scn == NULL)
9434 {
9435 error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
9436 continue;
9437 }
9438
9439 if (gelf_getshdr (scn, &shdr_mem) == NULL)
9440 error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
9441 elf_errmsg (-1));
9442 name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
9443 }
9444 else
9445 {
9446 /* Need to look up the section by name. */
9447 scn = NULL;
9448 bool found = false;
9449 while ((scn = elf_nextscn (elf, scn)) != NULL)
9450 {
9451 if (gelf_getshdr (scn, &shdr_mem) == NULL)
9452 continue;
9453 name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
9454 if (name == NULL)
9455 continue;
9456 if (!strcmp (name, a->arg))
9457 {
9458 found = true;
9459 (*dump) (scn, &shdr_mem, name);
9460 }
9461 }
9462
9463 if (unlikely (!found) && !a->implicit)
9464 error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
9465 }
9466 }
9467}
9468
9469static void
9470dump_data (Ebl *ebl)
9471{
9472 for_each_section_argument (ebl->elf, dump_data_sections, &dump_data_section);
9473}
9474
9475static void
9476dump_strings (Ebl *ebl)
9477{
9478 for_each_section_argument (ebl->elf, string_sections, &print_string_section);
9479}
9480
9481static void
9482print_strings (Ebl *ebl)
9483{
9484 /* Get the section header string table index. */
9485 size_t shstrndx;
9486 if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
9487 error (EXIT_FAILURE, 0,
9488 gettext ("cannot get section header string table index"));
9489
9490 Elf_Scn *scn;
9491 GElf_Shdr shdr_mem;
9492 const char *name;
9493 scn = NULL;
9494 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
9495 {
9496 if (gelf_getshdr (scn, &shdr_mem) == NULL)
9497 continue;
9498
9499 if (shdr_mem.sh_type != SHT_PROGBITS
9500 || !(shdr_mem.sh_flags & SHF_STRINGS))
9501 continue;
9502
9503 name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
9504 if (name == NULL)
9505 continue;
9506
9507 print_string_section (scn, &shdr_mem, name);
9508 }
9509}
9510
9511static void
9512dump_archive_index (Elf *elf, const char *fname)
9513{
9514 size_t narsym;
9515 const Elf_Arsym *arsym = elf_getarsym (elf, &narsym);
9516 if (arsym == NULL)
9517 {
9518 int result = elf_errno ();
9519 if (unlikely (result != ELF_E_NO_INDEX))
9520 error (EXIT_FAILURE, 0,
9521 gettext ("cannot get symbol index of archive '%s': %s"),
9522 fname, elf_errmsg (result));
9523 else
9524 printf (gettext ("\nArchive '%s' has no symbol index\n"), fname);
9525 return;
9526 }
9527
9528 printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"),
9529 fname, narsym);
9530
9531 size_t as_off = 0;
9532 for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s)
9533 {
9534 if (s->as_off != as_off)
9535 {
9536 as_off = s->as_off;
9537
9538 Elf *subelf;
9539 if (unlikely (elf_rand (elf, as_off) == 0)
9540 || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
9541 == NULL))
9542#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)
9543 while (1)
9544#endif
9545 error (EXIT_FAILURE, 0,
9546 gettext ("cannot extract member at offset %Zu in '%s': %s"),
9547 as_off, fname, elf_errmsg (-1));
9548
9549 const Elf_Arhdr *h = elf_getarhdr (subelf);
9550
9551 printf (gettext ("Archive member '%s' contains:\n"), h->ar_name);
9552
9553 elf_end (subelf);
9554 }
9555
9556 printf ("\t%s\n", s->as_name);
9557 }
9558}
9559
9560#include "debugpred.h"