blob: 1f7faf79af41130eb55e12f419238d41a46cfb8b [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Print information from ELF file in human-readable form.
Ulrich Drepper44173ed2009-01-01 19:00:41 -08002 Copyright (C) 1999-2008, 2009 Red Hat, Inc.
Ulrich Drepper361df7d2006-04-04 21:38:57 +00003 This file is part of Red Hat elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 1999.
5
Ulrich Drepper361df7d2006-04-04 21:38:57 +00006 Red Hat elfutils is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 2 of the License.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00009
Ulrich Drepper361df7d2006-04-04 21:38:57 +000010 Red Hat elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with Red Hat elfutils; if not, write to the Free Software Foundation,
Ulrich Drepper1e9ef502006-04-04 22:29:06 +000017 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
Ulrich Drepper361df7d2006-04-04 21:38:57 +000018
19 Red Hat elfutils is an included package of the Open Invention Network.
20 An included package of the Open Invention Network is a package for which
21 Open Invention Network licensees cross-license their patents. No patent
22 license is granted, either expressly or impliedly, by designation as an
23 included package. Should you wish to participate in the Open Invention
24 Network licensing program, please visit www.openinventionnetwork.com
25 <http://www.openinventionnetwork.com>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000026
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
31#include <argp.h>
32#include <assert.h>
Ulrich Drepperc98bcc72007-08-04 17:06:14 +000033#include <ctype.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000034#include <dwarf.h>
35#include <errno.h>
36#include <error.h>
37#include <fcntl.h>
38#include <gelf.h>
39#include <inttypes.h>
40#include <langinfo.h>
41#include <libdw.h>
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000042#include <libdwfl.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000043#include <libintl.h>
44#include <locale.h>
Roland McGrathcb6d8652007-08-23 08:10:54 +000045#include <stdarg.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000046#include <stdbool.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50#include <unistd.h>
51#include <sys/param.h>
52
53#include <system.h>
Roland McGrath59ea7f32007-10-04 08:50:09 +000054#include "../libelf/libelfP.h"
Roland McGrath059c83e2008-02-21 06:19:39 +000055#include "../libelf/common.h"
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000056#include "../libebl/libeblP.h"
57#include "../libdw/libdwP.h"
Roland McGrathe4c22ea2007-10-23 13:07:39 +000058#include "../libdwfl/libdwflP.h"
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000059#include "../libdw/memory-access.h"
60
61
62/* Name and version of program. */
63static void print_version (FILE *stream, struct argp_state *state);
Ulrich Drepperfdc93e12009-01-17 11:47:10 -080064ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000065
66/* Bug report address. */
Ulrich Drepperfdc93e12009-01-17 11:47:10 -080067ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000068
69/* Definitions of arguments for argp functions. */
70static const struct argp_option options[] =
71{
72 { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
Ulrich Drepperb006fbf2009-01-16 03:08:25 -080073 { "all", 'a', NULL, 0, N_("Equivalent to: -e -h -l"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000074 { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 },
75 { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 },
76 { "histogram", 'I', NULL, 0,
77 N_("Display histogram of bucket list lengths"), 0 },
78 { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
Roland McGrath60fc84c2007-08-03 21:59:15 +000079 { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000080 { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
81 { "section-headers", 'S', NULL, 0, N_("Display the sections' header"), 0 },
Roland McGrath60fc84c2007-08-03 21:59:15 +000082 { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000083 { "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
84 { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
85 { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
86 N_("Display DWARF section content. SECTION can be one of abbrev, "
Ulrich Drepperb006fbf2009-01-16 03:08:25 -080087 "aranges, frame, info, loc, line, ranges, pubnames, str, macinfo, "
88 "or exception"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000089 { "notes", 'n', NULL, 0, N_("Display the core notes"), 0 },
90 { "arch-specific", 'A', NULL, 0,
91 N_("Display architecture specific information (if any)"), 0 },
Roland McGrath60fc84c2007-08-03 21:59:15 +000092 { "hex-dump", 'x', "SECTION", 0,
93 N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
Roland McGrathc76f0b02007-09-27 07:31:33 +000094 { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL,
95 N_("Print string contents of sections"), 0 },
96 { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
Roland McGrath59ea7f32007-10-04 08:50:09 +000097 { "archive-index", 'c', NULL, 0,
98 N_("Display the symbol index of an archive"), 0 },
Ulrich Drepperb006fbf2009-01-16 03:08:25 -080099 { "exception", 'e', NULL, 0, N_("Display sections for exception handling"),
100 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000101
102 { NULL, 0, NULL, 0, N_("Output control:"), 0 },
103
104 { NULL, 0, NULL, 0, NULL, 0 }
105};
106
107/* Short description of program. */
108static const char doc[] = N_("\
109Print information from ELF file in human-readable form.");
110
111/* Strings for arguments in help texts. */
112static const char args_doc[] = N_("FILE...");
113
114/* Prototype for option handler. */
115static error_t parse_opt (int key, char *arg, struct argp_state *state);
116
117/* Data structure to communicate with argp functions. */
118static struct argp argp =
119{
120 options, parse_opt, args_doc, doc, NULL, NULL, NULL
121};
122
123
124/* Flags set by the option controlling the output. */
125
126/* True if dynamic segment should be printed. */
127static bool print_dynamic_table;
128
129/* True if the file header should be printed. */
130static bool print_file_header;
131
132/* True if the program headers should be printed. */
133static bool print_program_header;
134
135/* True if relocations should be printed. */
136static bool print_relocations;
137
138/* True if the section headers should be printed. */
139static bool print_section_header;
140
141/* True if the symbol table should be printed. */
142static bool print_symbol_table;
143
144/* True if the version information should be printed. */
145static bool print_version_info;
146
147/* True if section groups should be printed. */
148static bool print_section_groups;
149
150/* True if bucket list length histogram should be printed. */
151static bool print_histogram;
152
153/* True if the architecture specific data should be printed. */
154static bool print_arch;
155
156/* True if note section content should be printed. */
157static bool print_notes;
158
Roland McGrath60fc84c2007-08-03 21:59:15 +0000159/* True if SHF_STRINGS section content should be printed. */
160static bool print_string_sections;
161
Roland McGrath59ea7f32007-10-04 08:50:09 +0000162/* True if archive index should be printed. */
163static bool print_archive_index;
164
165/* True if any of the control options except print_archive_index is set. */
166static bool any_control_option;
167
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000168/* Select printing of debugging sections. */
169static enum section_e
170{
Ulrich Drepperb006fbf2009-01-16 03:08:25 -0800171 section_abbrev = 1, /* .debug_abbrev */
172 section_aranges = 2, /* .debug_aranges */
173 section_frame = 4, /* .debug_frame or .eh_frame & al. */
174 section_info = 8, /* .debug_info */
175 section_line = 16, /* .debug_line */
176 section_loc = 32, /* .debug_loc */
177 section_pubnames = 64, /* .debug_pubnames */
178 section_str = 128, /* .debug_str */
179 section_macinfo = 256, /* .debug_macinfo */
180 section_ranges = 512, /* .debug_ranges */
181 section_exception = 1024, /* .eh_frame & al. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000182 section_all = (section_abbrev | section_aranges | section_frame
183 | section_info | section_line | section_loc
184 | section_pubnames | section_str | section_macinfo
Ulrich Drepperb006fbf2009-01-16 03:08:25 -0800185 | section_ranges | section_exception)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000186} print_debug_sections;
187
Roland McGrath60fc84c2007-08-03 21:59:15 +0000188/* Select hex dumping of sections. */
189static struct section_argument *dump_data_sections;
190static struct section_argument **dump_data_sections_tail = &dump_data_sections;
191
Roland McGrathc76f0b02007-09-27 07:31:33 +0000192/* Select string dumping of sections. */
193static struct section_argument *string_sections;
194static struct section_argument **string_sections_tail = &string_sections;
195
Roland McGrath60fc84c2007-08-03 21:59:15 +0000196struct section_argument
197{
198 struct section_argument *next;
199 const char *arg;
200};
201
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000202/* Number of sections in the file. */
203static size_t shnum;
204
205
206/* Declarations of local functions. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000207static void process_file (int fd, const char *fname, bool only_one);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000208static void process_elf_file (Dwfl_Module *dwflmod, int fd);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000209static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
210static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
211static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
212static void print_scngrp (Ebl *ebl);
Ulrich Drepperdbace232005-08-06 01:37:23 +0000213static void print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214static void print_relocs (Ebl *ebl);
215static void handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
216static void handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
217static void print_symtab (Ebl *ebl, int type);
218static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
219static void print_verinfo (Ebl *ebl);
220static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
221static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
222static void handle_versym (Ebl *ebl, Elf_Scn *scn,
223 GElf_Shdr *shdr);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000224static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000225static void handle_hash (Ebl *ebl);
226static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
227static void print_liblist (Ebl *ebl);
Roland McGrath059c83e2008-02-21 06:19:39 +0000228static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr);
Roland McGrath60fc84c2007-08-03 21:59:15 +0000229static void dump_data (Ebl *ebl);
Roland McGrathc76f0b02007-09-27 07:31:33 +0000230static void dump_strings (Ebl *ebl);
Roland McGrath60fc84c2007-08-03 21:59:15 +0000231static void print_strings (Ebl *ebl);
Roland McGrath59ea7f32007-10-04 08:50:09 +0000232static void dump_archive_index (Elf *, const char *);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000233
234
235int
236main (int argc, char *argv[])
237{
238 /* Set locale. */
239 setlocale (LC_ALL, "");
240
241 /* Initialize the message catalog. */
Ulrich Drepperb0243862007-06-06 00:09:36 +0000242 textdomain (PACKAGE_TARNAME);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000243
244 /* Parse and process arguments. */
245 int remaining;
246 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
247
248 /* Before we start tell the ELF library which version we are using. */
249 elf_version (EV_CURRENT);
250
251 /* Now process all the files given at the command line. */
252 bool only_one = remaining + 1 == argc;
253 do
254 {
255 /* Open the file. */
256 int fd = open (argv[remaining], O_RDONLY);
257 if (fd == -1)
258 {
259 error (0, errno, gettext ("cannot open input file"));
260 continue;
261 }
262
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000263 process_file (fd, argv[remaining], only_one);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000264
265 close (fd);
266 }
267 while (++remaining < argc);
268
269 return error_message_count != 0;
270}
271
272
273/* Handle program arguments. */
274static error_t
275parse_opt (int key, char *arg,
276 struct argp_state *state __attribute__ ((unused)))
277{
Ulrich Drepperd7285e12009-01-23 16:10:44 -0800278 void add_dump_section (const char *name)
279 {
280 struct section_argument *a = xmalloc (sizeof *a);
281 a->arg = name;
282 a->next = NULL;
283 struct section_argument ***tailp
284 = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
285 **tailp = a;
286 *tailp = &a->next;
287 }
288
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000289 switch (key)
290 {
291 case 'a':
292 print_file_header = true;
293 print_program_header = true;
294 print_relocations = true;
295 print_section_header = true;
296 print_symbol_table = true;
297 print_version_info = true;
298 print_dynamic_table = true;
299 print_section_groups = true;
300 print_histogram = true;
301 print_arch = true;
302 print_notes = true;
Ulrich Drepperb006fbf2009-01-16 03:08:25 -0800303 print_debug_sections |= section_exception;
Ulrich Drepperd7285e12009-01-23 16:10:44 -0800304 add_dump_section (".strtab");
305 add_dump_section (".dynstr");
306 add_dump_section (".comment");
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000307 any_control_option = true;
308 break;
309 case 'A':
310 print_arch = true;
311 any_control_option = true;
312 break;
313 case 'd':
314 print_dynamic_table = true;
315 any_control_option = true;
316 break;
Ulrich Drepperb006fbf2009-01-16 03:08:25 -0800317 case 'e':
318 print_debug_sections |= section_exception;
319 any_control_option = true;
320 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000321 case 'g':
322 print_section_groups = true;
323 any_control_option = true;
324 break;
325 case 'h':
326 print_file_header = true;
327 any_control_option = true;
328 break;
329 case 'I':
330 print_histogram = true;
331 any_control_option = true;
332 break;
333 case 'l':
334 print_program_header = true;
335 any_control_option = true;
336 break;
337 case 'n':
338 print_notes = true;
339 any_control_option = true;
340 break;
341 case 'r':
342 print_relocations = true;
343 any_control_option = true;
344 break;
345 case 'S':
346 print_section_header = true;
347 any_control_option = true;
348 break;
349 case 's':
350 print_symbol_table = true;
351 any_control_option = true;
352 break;
353 case 'V':
354 print_version_info = true;
355 any_control_option = true;
356 break;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000357 case 'c':
358 print_archive_index = true;
359 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000360 case 'w':
361 if (arg == NULL)
362 print_debug_sections = section_all;
363 else if (strcmp (arg, "abbrev") == 0)
364 print_debug_sections |= section_abbrev;
365 else if (strcmp (arg, "aranges") == 0)
366 print_debug_sections |= section_aranges;
367 else if (strcmp (arg, "ranges") == 0)
368 print_debug_sections |= section_ranges;
Ulrich Drepperac194d02009-01-06 00:30:01 -0800369 else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000370 print_debug_sections |= section_frame;
371 else if (strcmp (arg, "info") == 0)
372 print_debug_sections |= section_info;
373 else if (strcmp (arg, "loc") == 0)
374 print_debug_sections |= section_loc;
375 else if (strcmp (arg, "line") == 0)
376 print_debug_sections |= section_line;
377 else if (strcmp (arg, "pubnames") == 0)
378 print_debug_sections |= section_pubnames;
379 else if (strcmp (arg, "str") == 0)
380 print_debug_sections |= section_str;
381 else if (strcmp (arg, "macinfo") == 0)
382 print_debug_sections |= section_macinfo;
Ulrich Drepperb006fbf2009-01-16 03:08:25 -0800383 else if (strcmp (arg, "exception") == 0)
384 print_debug_sections |= section_exception;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000385 else
386 {
387 fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"),
388 arg);
389 argp_help (&argp, stderr, ARGP_HELP_SEE,
390 program_invocation_short_name);
391 exit (1);
392 }
393 any_control_option = true;
394 break;
Roland McGrathc76f0b02007-09-27 07:31:33 +0000395 case 'p':
396 any_control_option = true;
397 if (arg == NULL)
398 {
399 print_string_sections = true;
400 break;
401 }
402 /* Fall through. */
Roland McGrath60fc84c2007-08-03 21:59:15 +0000403 case 'x':
Ulrich Drepperd7285e12009-01-23 16:10:44 -0800404 add_dump_section (arg);
Roland McGrath60fc84c2007-08-03 21:59:15 +0000405 any_control_option = true;
406 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000407 case ARGP_KEY_NO_ARGS:
408 fputs (gettext ("Missing file name.\n"), stderr);
409 goto do_argp_help;
410 case ARGP_KEY_FINI:
Roland McGrath59ea7f32007-10-04 08:50:09 +0000411 if (! any_control_option && ! print_archive_index)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000412 {
413 fputs (gettext ("No operation specified.\n"), stderr);
414 do_argp_help:
415 argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
416 program_invocation_short_name);
417 exit (1);
418 }
419 break;
420 default:
421 return ARGP_ERR_UNKNOWN;
422 }
423 return 0;
424}
425
426
427/* Print the version information. */
428static void
429print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
430{
Ulrich Drepperb0243862007-06-06 00:09:36 +0000431 fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000432 fprintf (stream, gettext ("\
433Copyright (C) %s Red Hat, Inc.\n\
434This is free software; see the source for copying conditions. There is NO\n\
435warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
Ulrich Drepper44173ed2009-01-01 19:00:41 -0800436"), "2009");
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000437 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
438}
439
440
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000441/* Check if the file is an archive, and if so dump its index. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000442static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000443check_archive_index (int fd, const char *fname, bool only_one)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000444{
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000445 /* Create an `Elf' descriptor. */
446 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
447 if (elf == NULL)
448 error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
449 elf_errmsg (-1));
450 else
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000451 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000452 if (elf_kind (elf) == ELF_K_AR)
453 {
454 if (!only_one)
455 printf ("\n%s:\n\n", fname);
456 dump_archive_index (elf, fname);
457 }
458 else
Roland McGrath59ea7f32007-10-04 08:50:09 +0000459 error (0, 0,
460 gettext ("'%s' is not an archive, cannot print archive index"),
461 fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000462
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000463 /* Now we can close the descriptor. */
464 if (elf_end (elf) != 0)
465 error (0, 0, gettext ("error while closing Elf descriptor: %s"),
466 elf_errmsg (-1));
467 }
468}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000469
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000470/* Trivial callback used for checking if we opened an archive. */
471static int
472count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
473 void **userdata __attribute__ ((unused)),
474 const char *name __attribute__ ((unused)),
475 Dwarf_Addr base __attribute__ ((unused)),
476 void *arg)
477{
Roland McGratha845f682008-12-03 03:41:58 +0000478 if (*(bool *) arg)
479 return DWARF_CB_ABORT;
480 *(bool *) arg = true;
481 return DWARF_CB_OK;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000482}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000483
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000484struct process_dwflmod_args
485{
486 int fd;
487 bool only_one;
488};
489
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000490static int
491process_dwflmod (Dwfl_Module *dwflmod,
492 void **userdata __attribute__ ((unused)),
493 const char *name __attribute__ ((unused)),
494 Dwarf_Addr base __attribute__ ((unused)),
495 void *arg)
496{
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000497 const struct process_dwflmod_args *a = arg;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000498
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000499 /* Print the file name. */
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000500 if (!a->only_one)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000501 {
502 const char *fname;
503 dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000504
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000505 printf ("\n%s:\n\n", fname);
506 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000507
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000508 process_elf_file (dwflmod, a->fd);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000509
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000510 return DWARF_CB_OK;
511}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000512
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000513/* Stub libdwfl callback, only the ELF handle already open is ever used. */
514static int
515find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
516 void **userdata __attribute__ ((unused)),
517 const char *modname __attribute__ ((unused)),
518 Dwarf_Addr base __attribute__ ((unused)),
519 const char *file_name __attribute__ ((unused)),
520 const char *debuglink_file __attribute__ ((unused)),
521 GElf_Word debuglink_crc __attribute__ ((unused)),
522 char **debuginfo_file_name __attribute__ ((unused)))
523{
524 return -1;
525}
526
527/* Process one input file. */
528static void
529process_file (int fd, const char *fname, bool only_one)
530{
531 if (print_archive_index)
532 check_archive_index (fd, fname, only_one);
533
534 if (!any_control_option)
535 return;
536
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000537 /* Duplicate an fd for dwfl_report_offline to swallow. */
538 int dwfl_fd = dup (fd);
539 if (unlikely (dwfl_fd < 0))
540 error (EXIT_FAILURE, errno, "dup");
541
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000542 /* Use libdwfl in a trivial way to open the libdw handle for us.
543 This takes care of applying relocations to DWARF data in ET_REL files. */
544 static const Dwfl_Callbacks callbacks =
545 {
546 .section_address = dwfl_offline_section_address,
547 .find_debuginfo = find_no_debuginfo
548 };
549 Dwfl *dwfl = dwfl_begin (&callbacks);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000550 if (likely (dwfl != NULL))
551 /* Let 0 be the logical address of the file (or first in archive). */
552 dwfl->offline_next_address = 0;
553 if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000554 {
555 struct stat64 st;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000556 if (fstat64 (fd, &st) != 0)
557 error (0, errno, gettext ("cannot stat input file"));
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000558 else if (unlikely (st.st_size == 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000559 error (0, 0, gettext ("input file is empty"));
560 else
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000561 error (0, 0, gettext ("failed reading '%s': %s"),
562 fname, dwfl_errmsg (-1));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000563 }
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000564 else
565 {
566 dwfl_report_end (dwfl, NULL, NULL);
567
568 if (only_one)
Roland McGratha845f682008-12-03 03:41:58 +0000569 {
570 /* Clear ONLY_ONE if we have multiple modules, from an archive. */
571 bool seen = false;
572 only_one = dwfl_getmodules (dwfl, &count_dwflmod, &seen, 0) == 0;
573 }
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000574
575 /* Process the one or more modules gleaned from this file. */
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000576 struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
577 dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000578 }
579 dwfl_end (dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000580}
581
582
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000583/* Process one ELF file. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000584static void
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000585process_elf_file (Dwfl_Module *dwflmod, int fd)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000586{
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000587 GElf_Addr dwflbias;
588 Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
589
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000590 GElf_Ehdr ehdr_mem;
591 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000592
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000593 if (ehdr == NULL)
594 {
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000595 elf_error:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000596 error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
597 return;
598 }
599
Ulrich Drepperd0449522005-09-03 07:23:52 +0000600 Ebl *ebl = ebl_openbackend (elf);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000601 if (unlikely (ebl == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000602 {
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000603 ebl_error:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000604 error (0, errno, gettext ("cannot create EBL handle"));
605 return;
606 }
607
608 /* Determine the number of sections. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000609 if (unlikely (elf_getshnum (ebl->elf, &shnum) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000610 error (EXIT_FAILURE, 0,
611 gettext ("cannot determine number of sections: %s"),
612 elf_errmsg (-1));
613
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000614 /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
615 and may have applied relocation to some sections.
616 So we need to get a fresh Elf handle on the file to display those. */
617 bool print_unrelocated = (print_section_header
618 || print_relocations
619 || dump_data_sections != NULL
620 || print_notes);
621
622 Elf *pure_elf = NULL;
623 Ebl *pure_ebl = ebl;
624 if (ehdr->e_type == ET_REL && print_unrelocated)
625 {
626 /* Read the file afresh. */
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000627 off64_t aroff = elf_getaroff (elf);
Ulrich Drepperfbc708d2008-01-21 18:44:55 +0000628 pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000629 if (aroff > 0)
630 {
631 /* Archive member. */
632 (void) elf_rand (pure_elf, aroff);
633 Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
634 elf_end (pure_elf);
635 pure_elf = armem;
636 }
637 if (pure_elf == NULL)
638 goto elf_error;
639 pure_ebl = ebl_openbackend (pure_elf);
640 if (pure_ebl == NULL)
641 goto ebl_error;
642 }
643
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000644 if (print_file_header)
645 print_ehdr (ebl, ehdr);
646 if (print_section_header)
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000647 print_shdr (pure_ebl, ehdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000648 if (print_program_header)
649 print_phdr (ebl, ehdr);
650 if (print_section_groups)
651 print_scngrp (ebl);
652 if (print_dynamic_table)
Ulrich Drepperdbace232005-08-06 01:37:23 +0000653 print_dynamic (ebl, ehdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000654 if (print_relocations)
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000655 print_relocs (pure_ebl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000656 if (print_histogram)
657 handle_hash (ebl);
658 if (print_symbol_table)
659 print_symtab (ebl, SHT_DYNSYM);
660 if (print_version_info)
661 print_verinfo (ebl);
662 if (print_symbol_table)
663 print_symtab (ebl, SHT_SYMTAB);
664 if (print_arch)
665 print_liblist (ebl);
Roland McGrath059c83e2008-02-21 06:19:39 +0000666 if (print_arch)
667 print_attributes (ebl, ehdr);
Roland McGrath60fc84c2007-08-03 21:59:15 +0000668 if (dump_data_sections != NULL)
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000669 dump_data (pure_ebl);
Roland McGrathc76f0b02007-09-27 07:31:33 +0000670 if (string_sections != NULL)
671 dump_strings (ebl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000672 if (print_debug_sections != 0)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000673 print_debug (dwflmod, ebl, ehdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000674 if (print_notes)
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000675 handle_notes (pure_ebl, ehdr);
Roland McGrath60fc84c2007-08-03 21:59:15 +0000676 if (print_string_sections)
677 print_strings (ebl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000678
679 ebl_closebackend (ebl);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000680
681 if (pure_ebl != ebl)
682 {
683 ebl_closebackend (pure_ebl);
684 elf_end (pure_elf);
685 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000686}
687
688
689/* Print file type. */
690static void
691print_file_type (unsigned short int e_type)
692{
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000693 if (likely (e_type <= ET_CORE))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000694 {
Ulrich Drepper8b383102007-02-16 00:31:57 +0000695 static const char *const knowntypes[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000696 {
697 N_("NONE (None)"),
698 N_("REL (Relocatable file)"),
699 N_("EXEC (Executable file)"),
700 N_("DYN (Shared object file)"),
701 N_("CORE (Core file)")
702 };
703 puts (gettext (knowntypes[e_type]));
704 }
705 else if (e_type >= ET_LOOS && e_type <= ET_HIOS)
706 printf (gettext ("OS Specific: (%x)\n"), e_type);
707 else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */)
708 printf (gettext ("Processor Specific: (%x)\n"), e_type);
709 else
710 puts ("???");
711}
712
713
714/* Print ELF header. */
715static void
716print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
717{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000718 fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout);
Ulrich Drepperd0449522005-09-03 07:23:52 +0000719 for (size_t cnt = 0; cnt < EI_NIDENT; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000720 printf (" %02hhx", ehdr->e_ident[cnt]);
721
722 printf (gettext ("\n Class: %s\n"),
723 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32"
724 : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64"
725 : "\?\?\?");
726
727 printf (gettext (" Data: %s\n"),
728 ehdr->e_ident[EI_DATA] == ELFDATA2LSB
729 ? "2's complement, little endian"
730 : ehdr->e_ident[EI_DATA] == ELFDATA2MSB
731 ? "2's complement, big endian" : "\?\?\?");
732
Ulrich Drepper41a99082006-05-28 00:01:43 +0000733 printf (gettext (" Ident Version: %hhd %s\n"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000734 ehdr->e_ident[EI_VERSION],
735 ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)")
736 : "(\?\?\?)");
737
Ulrich Drepperd0449522005-09-03 07:23:52 +0000738 char buf[512];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000739 printf (gettext (" OS/ABI: %s\n"),
740 ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
741
742 printf (gettext (" ABI Version: %hhd\n"),
743 ehdr->e_ident[EI_ABIVERSION]);
744
745 fputs_unlocked (gettext (" Type: "), stdout);
746 print_file_type (ehdr->e_type);
747
748 printf (gettext (" Machine: %s\n"), ebl->name);
749
750 printf (gettext (" Version: %d %s\n"),
751 ehdr->e_version,
752 ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)");
753
754 printf (gettext (" Entry point address: %#" PRIx64 "\n"),
755 ehdr->e_entry);
756
757 printf (gettext (" Start of program headers: %" PRId64 " %s\n"),
758 ehdr->e_phoff, gettext ("(bytes into file)"));
759
760 printf (gettext (" Start of section headers: %" PRId64 " %s\n"),
761 ehdr->e_shoff, gettext ("(bytes into file)"));
762
763 printf (gettext (" Flags: %s\n"),
764 ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
765
766 printf (gettext (" Size of this header: %" PRId16 " %s\n"),
767 ehdr->e_ehsize, gettext ("(bytes)"));
768
769 printf (gettext (" Size of program header entries: %" PRId16 " %s\n"),
770 ehdr->e_phentsize, gettext ("(bytes)"));
771
772 printf (gettext (" Number of program headers entries: %" PRId16 "\n"),
773 ehdr->e_phnum);
774
775 printf (gettext (" Size of section header entries: %" PRId16 " %s\n"),
776 ehdr->e_shentsize, gettext ("(bytes)"));
777
778 printf (gettext (" Number of section headers entries: %" PRId16),
779 ehdr->e_shnum);
780 if (ehdr->e_shnum == 0)
781 {
782 GElf_Shdr shdr_mem;
Ulrich Drepperd0449522005-09-03 07:23:52 +0000783 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000784 if (shdr != NULL)
785 printf (gettext (" (%" PRIu32 " in [0].sh_size)"),
786 (uint32_t) shdr->sh_size);
787 else
788 fputs_unlocked (gettext (" ([0] not available)"), stdout);
789 }
790 fputc_unlocked ('\n', stdout);
791
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000792 if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000793 {
794 GElf_Shdr shdr_mem;
Ulrich Drepperd0449522005-09-03 07:23:52 +0000795 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000796 if (shdr != NULL)
797 /* We managed to get the zeroth section. */
798 snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"),
799 (uint32_t) shdr->sh_link);
800 else
801 {
802 strncpy (buf, gettext (" ([0] not available)"), sizeof (buf));
803 buf[sizeof (buf) - 1] = '\0';
804 }
805
806 printf (gettext (" Section header string table index: XINDEX%s\n\n"),
807 buf);
808 }
809 else
810 printf (gettext (" Section header string table index: %" PRId16 "\n\n"),
811 ehdr->e_shstrndx);
812}
813
814
815static const char *
816get_visibility_type (int value)
817{
818 switch (value)
819 {
820 case STV_DEFAULT:
821 return "DEFAULT";
822 case STV_INTERNAL:
823 return "INTERNAL";
824 case STV_HIDDEN:
825 return "HIDDEN";
826 case STV_PROTECTED:
827 return "PROTECTED";
828 default:
829 return "???";
830 }
831}
832
833
834/* Print the section headers. */
835static void
836print_shdr (Ebl *ebl, GElf_Ehdr *ehdr)
837{
838 size_t cnt;
839 size_t shstrndx;
840
841 if (! print_file_header)
842 printf (gettext ("\
843There are %d section headers, starting at offset %#" PRIx64 ":\n\
844\n"),
845 ehdr->e_shnum, ehdr->e_shoff);
846
847 /* Get the section header string table index. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000848 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000849 error (EXIT_FAILURE, 0,
850 gettext ("cannot get section header string table index"));
851
852 puts (gettext ("Section Headers:"));
853
854 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
855 puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
856 else
857 puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al"));
858
859 for (cnt = 0; cnt < shnum; ++cnt)
860 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000861 Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000862
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000863 if (unlikely (scn == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000864 error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
865 elf_errmsg (-1));
866
867 /* Get the section header. */
Ulrich Drepperd0449522005-09-03 07:23:52 +0000868 GElf_Shdr shdr_mem;
869 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000870 if (unlikely (shdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000871 error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
872 elf_errmsg (-1));
873
Ulrich Drepperd0449522005-09-03 07:23:52 +0000874 char flagbuf[20];
875 char *cp = flagbuf;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000876 if (shdr->sh_flags & SHF_WRITE)
877 *cp++ = 'W';
878 if (shdr->sh_flags & SHF_ALLOC)
879 *cp++ = 'A';
880 if (shdr->sh_flags & SHF_EXECINSTR)
881 *cp++ = 'X';
882 if (shdr->sh_flags & SHF_MERGE)
883 *cp++ = 'M';
884 if (shdr->sh_flags & SHF_STRINGS)
885 *cp++ = 'S';
886 if (shdr->sh_flags & SHF_INFO_LINK)
887 *cp++ = 'I';
888 if (shdr->sh_flags & SHF_LINK_ORDER)
889 *cp++ = 'L';
890 if (shdr->sh_flags & SHF_OS_NONCONFORMING)
891 *cp++ = 'N';
892 if (shdr->sh_flags & SHF_GROUP)
893 *cp++ = 'G';
894 if (shdr->sh_flags & SHF_TLS)
895 *cp++ = 'T';
896 if (shdr->sh_flags & SHF_ORDERED)
897 *cp++ = 'O';
898 if (shdr->sh_flags & SHF_EXCLUDE)
899 *cp++ = 'E';
900 *cp = '\0';
901
Ulrich Drepperd0449522005-09-03 07:23:52 +0000902 char buf[128];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000903 printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64
904 " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32
905 " %2" PRId64 "\n",
906 cnt,
907 elf_strptr (ebl->elf, shstrndx, shdr->sh_name)
908 ?: "<corrupt>",
909 ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)),
910 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr,
911 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset,
912 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size,
913 shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info,
914 shdr->sh_addralign);
915 }
916
917 fputc_unlocked ('\n', stdout);
918}
919
920
921/* Print the program header. */
922static void
923print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
924{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000925 if (ehdr->e_phnum == 0)
926 /* No program header, this is OK in relocatable objects. */
927 return;
928
929 puts (gettext ("Program Headers:"));
930 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
931 puts (gettext ("\
932 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
933 else
934 puts (gettext ("\
935 Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align"));
936
937 /* Process all program headers. */
938 bool has_relro = false;
939 GElf_Addr relro_from = 0;
940 GElf_Addr relro_to = 0;
Ulrich Drepperd0449522005-09-03 07:23:52 +0000941 for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000942 {
943 char buf[128];
944 GElf_Phdr mem;
945 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
946
947 /* If for some reason the header cannot be returned show this. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000948 if (unlikely (phdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000949 {
950 puts (" ???");
951 continue;
952 }
953
954 printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64
955 " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n",
956 ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)),
957 phdr->p_offset,
958 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr,
959 ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr,
960 phdr->p_filesz,
961 phdr->p_memsz,
962 phdr->p_flags & PF_R ? 'R' : ' ',
963 phdr->p_flags & PF_W ? 'W' : ' ',
964 phdr->p_flags & PF_X ? 'E' : ' ',
965 phdr->p_align);
966
967 if (phdr->p_type == PT_INTERP)
968 {
969 /* We can show the user the name of the interpreter. */
970 size_t maxsize;
971 char *filedata = elf_rawfile (ebl->elf, &maxsize);
972
973 if (filedata != NULL && phdr->p_offset < maxsize)
974 printf (gettext ("\t[Requesting program interpreter: %s]\n"),
975 filedata + phdr->p_offset);
976 }
977 else if (phdr->p_type == PT_GNU_RELRO)
978 {
979 has_relro = true;
980 relro_from = phdr->p_vaddr;
981 relro_to = relro_from + phdr->p_memsz;
982 }
983 }
984
Roland McGrath9a847e12009-01-22 19:55:00 -0800985 if (ehdr->e_shnum == 0)
986 /* No sections in the file. Punt. */
987 return;
988
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000989 /* Get the section header string table index. */
Ulrich Drepperd0449522005-09-03 07:23:52 +0000990 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000991 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000992 error (EXIT_FAILURE, 0,
993 gettext ("cannot get section header string table index"));
994
995 puts (gettext ("\n Section to Segment mapping:\n Segment Sections..."));
996
Ulrich Drepperd0449522005-09-03 07:23:52 +0000997 for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000998 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000999 /* Print the segment number. */
1000 printf (" %2.2zu ", cnt);
1001
Ulrich Drepperd0449522005-09-03 07:23:52 +00001002 GElf_Phdr phdr_mem;
1003 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001004 /* This must not happen. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001005 if (unlikely (phdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001006 error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
1007 elf_errmsg (-1));
1008
1009 /* Iterate over the sections. */
1010 bool in_relro = false;
1011 bool in_ro = false;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001012 for (size_t inner = 1; inner < shnum; ++inner)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001013 {
1014 Elf_Scn *scn = elf_getscn (ebl->elf, inner);
Ulrich Drepperd0449522005-09-03 07:23:52 +00001015 /* This should not happen. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001016 if (unlikely (scn == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001017 error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
1018 elf_errmsg (-1));
1019
1020 /* Get the section header. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001021 GElf_Shdr shdr_mem;
1022 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001023 if (unlikely (shdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001024 error (EXIT_FAILURE, 0,
1025 gettext ("cannot get section header: %s"),
1026 elf_errmsg (-1));
1027
1028 if (shdr->sh_size > 0
1029 /* Compare allocated sections by VMA, unallocated
1030 sections by file offset. */
1031 && (shdr->sh_flags & SHF_ALLOC
1032 ? (shdr->sh_addr >= phdr->p_vaddr
1033 && (shdr->sh_addr + shdr->sh_size
1034 <= phdr->p_vaddr + phdr->p_memsz))
1035 : (shdr->sh_offset >= phdr->p_offset
1036 && (shdr->sh_offset + shdr->sh_size
1037 <= phdr->p_offset + phdr->p_filesz))))
1038 {
1039 if (has_relro && !in_relro
1040 && shdr->sh_addr >= relro_from
1041 && shdr->sh_addr + shdr->sh_size <= relro_to)
1042 {
1043 fputs_unlocked (" [RELRO:", stdout);
1044 in_relro = true;
1045 }
1046 else if (has_relro && in_relro && shdr->sh_addr >= relro_to)
1047 {
1048 fputs_unlocked ("]", stdout);
1049 in_relro = false;
1050 }
1051 else if (has_relro && in_relro
1052 && shdr->sh_addr + shdr->sh_size > relro_to)
1053 fputs_unlocked ("] <RELRO:", stdout);
1054 else if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
1055 {
1056 if (!in_ro)
1057 {
1058 fputs_unlocked (" [RO:", stdout);
1059 in_ro = true;
1060 }
1061 }
1062 else
1063 {
1064 /* Determine the segment this section is part of. */
1065 size_t cnt2;
1066 GElf_Phdr *phdr2 = NULL;
1067 for (cnt2 = 0; cnt2 < ehdr->e_phnum; ++cnt2)
1068 {
1069 GElf_Phdr phdr2_mem;
1070 phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
1071
1072 if (phdr2 != NULL && phdr2->p_type == PT_LOAD
1073 && shdr->sh_addr >= phdr2->p_vaddr
1074 && (shdr->sh_addr + shdr->sh_size
1075 <= phdr2->p_vaddr + phdr2->p_memsz))
1076 break;
1077 }
1078
1079 if (cnt2 < ehdr->e_phnum)
1080 {
1081 if ((phdr2->p_flags & PF_W) == 0 && !in_ro)
1082 {
1083 fputs_unlocked (" [RO:", stdout);
1084 in_ro = true;
1085 }
1086 else if ((phdr2->p_flags & PF_W) != 0 && in_ro)
1087 {
1088 fputs_unlocked ("]", stdout);
1089 in_ro = false;
1090 }
1091 }
1092 }
1093
1094 printf (" %s",
1095 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1096
1097 /* Signal that this sectin is only partially covered. */
1098 if (has_relro && in_relro
1099 && shdr->sh_addr + shdr->sh_size > relro_to)
1100 {
1101 fputs_unlocked (">", stdout);
1102 in_relro = false;
1103 }
1104 }
1105 }
1106 if (in_relro || in_ro)
1107 fputs_unlocked ("]", stdout);
1108
1109 /* Finish the line. */
1110 fputc_unlocked ('\n', stdout);
1111 }
1112}
1113
1114
1115static void
1116handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1117{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001118 /* Get the data of the section. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001119 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001120
Ulrich Drepperd0449522005-09-03 07:23:52 +00001121 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1122 GElf_Shdr symshdr_mem;
1123 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1124 Elf_Data *symdata = elf_getdata (symscn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001125
1126 if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL
1127 || symdata == NULL)
1128 return;
1129
1130 /* Get the section header string table index. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001131 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001132 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001133 error (EXIT_FAILURE, 0,
1134 gettext ("cannot get section header string table index"));
1135
Ulrich Drepperd0449522005-09-03 07:23:52 +00001136 Elf32_Word *grpref = (Elf32_Word *) data->d_buf;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001137
Ulrich Drepperd0449522005-09-03 07:23:52 +00001138 GElf_Sym sym_mem;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001139 printf ((grpref[0] & GRP_COMDAT)
1140 ? ngettext ("\
1141\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n",
1142 "\
1143\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1144 data->d_size / sizeof (Elf32_Word) - 1)
1145 : ngettext ("\
1146\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\
1147\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
1148 data->d_size / sizeof (Elf32_Word) - 1),
1149 elf_ndxscn (scn),
1150 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1151 elf_strptr (ebl->elf, symshdr->sh_link,
1152 gelf_getsym (symdata, shdr->sh_info, &sym_mem)->st_name)
1153 ?: gettext ("<INVALID SYMBOL>"),
1154 data->d_size / sizeof (Elf32_Word) - 1);
1155
Ulrich Drepperd0449522005-09-03 07:23:52 +00001156 for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001157 {
1158 GElf_Shdr grpshdr_mem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001159 GElf_Shdr *grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
1160 &grpshdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001161
Ulrich Drepperd0449522005-09-03 07:23:52 +00001162 const char *str;
1163 printf (" [%2u] %s\n",
1164 grpref[cnt],
1165 grpshdr != NULL
1166 && (str = elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name))
1167 ? str : gettext ("<INVALID SECTION>"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001168 }
1169}
1170
1171
1172static void
1173print_scngrp (Ebl *ebl)
1174{
1175 /* Find all relocation sections and handle them. */
1176 Elf_Scn *scn = NULL;
1177
1178 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1179 {
1180 /* Handle the section if it is a symbol table. */
1181 GElf_Shdr shdr_mem;
1182 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1183
1184 if (shdr != NULL && shdr->sh_type == SHT_GROUP)
1185 handle_scngrp (ebl, scn, shdr);
1186 }
1187}
1188
1189
1190static const struct flags
1191{
1192 int mask;
1193 const char *str;
1194} dt_flags[] =
1195 {
1196 { DF_ORIGIN, "ORIGIN" },
1197 { DF_SYMBOLIC, "SYMBOLIC" },
1198 { DF_TEXTREL, "TEXTREL" },
1199 { DF_BIND_NOW, "BIND_NOW" },
1200 { DF_STATIC_TLS, "STATIC_TLS" }
1201 };
1202static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]);
1203
1204static const struct flags dt_flags_1[] =
1205 {
1206 { DF_1_NOW, "NOW" },
1207 { DF_1_GLOBAL, "GLOBAL" },
1208 { DF_1_GROUP, "GROUP" },
1209 { DF_1_NODELETE, "NODELETE" },
1210 { DF_1_LOADFLTR, "LOADFLTR" },
1211 { DF_1_INITFIRST, "INITFIRST" },
1212 { DF_1_NOOPEN, "NOOPEN" },
1213 { DF_1_ORIGIN, "ORIGIN" },
1214 { DF_1_DIRECT, "DIRECT" },
1215 { DF_1_TRANS, "TRANS" },
1216 { DF_1_INTERPOSE, "INTERPOSE" },
1217 { DF_1_NODEFLIB, "NODEFLIB" },
1218 { DF_1_NODUMP, "NODUMP" },
1219 { DF_1_CONFALT, "CONFALT" },
1220 { DF_1_ENDFILTEE, "ENDFILTEE" },
1221 { DF_1_DISPRELDNE, "DISPRELDNE" },
1222 { DF_1_DISPRELPND, "DISPRELPND" },
1223 };
1224static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]);
1225
1226static const struct flags dt_feature_1[] =
1227 {
1228 { DTF_1_PARINIT, "PARINIT" },
1229 { DTF_1_CONFEXP, "CONFEXP" }
1230 };
1231static const int ndt_feature_1 = (sizeof (dt_feature_1)
1232 / sizeof (dt_feature_1[0]));
1233
1234static const struct flags dt_posflag_1[] =
1235 {
1236 { DF_P1_LAZYLOAD, "LAZYLOAD" },
1237 { DF_P1_GROUPPERM, "GROUPPERM" }
1238 };
1239static const int ndt_posflag_1 = (sizeof (dt_posflag_1)
1240 / sizeof (dt_posflag_1[0]));
1241
1242
1243static void
1244print_flags (int class, GElf_Xword d_val, const struct flags *flags,
1245 int nflags)
1246{
1247 bool first = true;
1248 int cnt;
1249
1250 for (cnt = 0; cnt < nflags; ++cnt)
1251 if (d_val & flags[cnt].mask)
1252 {
1253 if (!first)
1254 putchar_unlocked (' ');
1255 fputs_unlocked (flags[cnt].str, stdout);
1256 d_val &= ~flags[cnt].mask;
1257 first = false;
1258 }
1259
1260 if (d_val != 0)
1261 {
1262 if (!first)
1263 putchar_unlocked (' ');
1264 printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val);
1265 }
1266
1267 putchar_unlocked ('\n');
1268}
1269
1270
1271static void
1272print_dt_flags (int class, GElf_Xword d_val)
1273{
1274 print_flags (class, d_val, dt_flags, ndt_flags);
1275}
1276
1277
1278static void
1279print_dt_flags_1 (int class, GElf_Xword d_val)
1280{
1281 print_flags (class, d_val, dt_flags_1, ndt_flags_1);
1282}
1283
1284
1285static void
1286print_dt_feature_1 (int class, GElf_Xword d_val)
1287{
1288 print_flags (class, d_val, dt_feature_1, ndt_feature_1);
1289}
1290
1291
1292static void
1293print_dt_posflag_1 (int class, GElf_Xword d_val)
1294{
1295 print_flags (class, d_val, dt_posflag_1, ndt_posflag_1);
1296}
1297
1298
1299static void
1300handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1301{
1302 int class = gelf_getclass (ebl->elf);
1303 GElf_Shdr glink;
1304 Elf_Data *data;
1305 size_t cnt;
1306 size_t shstrndx;
1307
1308 /* Get the data of the section. */
1309 data = elf_getdata (scn, NULL);
1310 if (data == NULL)
1311 return;
1312
1313 /* Get the section header string table index. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001314 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001315 error (EXIT_FAILURE, 0,
1316 gettext ("cannot get section header string table index"));
1317
1318 printf (ngettext ("\
1319\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
1320 "\
1321\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
1322 shdr->sh_size / shdr->sh_entsize),
1323 (unsigned long int) (shdr->sh_size / shdr->sh_entsize),
1324 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
1325 shdr->sh_offset,
1326 (int) shdr->sh_link,
1327 elf_strptr (ebl->elf, shstrndx,
1328 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
1329 &glink)->sh_name));
1330 fputs_unlocked (gettext (" Type Value\n"), stdout);
1331
1332 for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
1333 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001334 GElf_Dyn dynmem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001335 GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001336 if (dyn == NULL)
1337 break;
1338
Ulrich Drepperd0449522005-09-03 07:23:52 +00001339 char buf[64];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001340 printf (" %-17s ",
1341 ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));
1342
1343 switch (dyn->d_tag)
1344 {
1345 case DT_NULL:
1346 case DT_DEBUG:
1347 case DT_BIND_NOW:
1348 case DT_TEXTREL:
1349 /* No further output. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001350 fputc_unlocked ('\n', stdout);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001351 break;
1352
1353 case DT_NEEDED:
1354 printf (gettext ("Shared library: [%s]\n"),
1355 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1356 break;
1357
1358 case DT_SONAME:
1359 printf (gettext ("Library soname: [%s]\n"),
1360 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1361 break;
1362
1363 case DT_RPATH:
1364 printf (gettext ("Library rpath: [%s]\n"),
1365 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1366 break;
1367
1368 case DT_RUNPATH:
1369 printf (gettext ("Library runpath: [%s]\n"),
1370 elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
1371 break;
1372
1373 case DT_PLTRELSZ:
1374 case DT_RELASZ:
1375 case DT_STRSZ:
1376 case DT_RELSZ:
1377 case DT_RELAENT:
1378 case DT_SYMENT:
1379 case DT_RELENT:
1380 case DT_PLTPADSZ:
1381 case DT_MOVEENT:
1382 case DT_MOVESZ:
1383 case DT_INIT_ARRAYSZ:
1384 case DT_FINI_ARRAYSZ:
1385 case DT_SYMINSZ:
1386 case DT_SYMINENT:
1387 case DT_GNU_CONFLICTSZ:
1388 case DT_GNU_LIBLISTSZ:
1389 printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val);
1390 break;
1391
1392 case DT_VERDEFNUM:
1393 case DT_VERNEEDNUM:
1394 case DT_RELACOUNT:
1395 case DT_RELCOUNT:
1396 printf ("%" PRId64 "\n", dyn->d_un.d_val);
1397 break;
1398
1399 case DT_PLTREL:
1400 puts (ebl_dynamic_tag_name (ebl, dyn->d_un.d_val, NULL, 0));
1401 break;
1402
1403 case DT_FLAGS:
1404 print_dt_flags (class, dyn->d_un.d_val);
1405 break;
1406
1407 case DT_FLAGS_1:
1408 print_dt_flags_1 (class, dyn->d_un.d_val);
1409 break;
1410
1411 case DT_FEATURE_1:
1412 print_dt_feature_1 (class, dyn->d_un.d_val);
1413 break;
1414
1415 case DT_POSFLAG_1:
1416 print_dt_posflag_1 (class, dyn->d_un.d_val);
1417 break;
1418
1419 default:
1420 printf ("%#0*" PRIx64 "\n",
1421 class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val);
1422 break;
1423 }
1424 }
1425}
1426
1427
1428/* Print the dynamic segment. */
1429static void
Ulrich Drepperdbace232005-08-06 01:37:23 +00001430print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001431{
Ulrich Drepperdbace232005-08-06 01:37:23 +00001432 for (int i = 0; i < ehdr->e_phnum; ++i)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001433 {
Ulrich Drepperdbace232005-08-06 01:37:23 +00001434 GElf_Phdr phdr_mem;
1435 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001436
Ulrich Drepperdbace232005-08-06 01:37:23 +00001437 if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001438 {
Ulrich Drepperdbace232005-08-06 01:37:23 +00001439 Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
1440 GElf_Shdr shdr_mem;
1441 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1442 if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
1443 handle_dynamic (ebl, scn, shdr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001444 break;
1445 }
1446 }
1447}
1448
1449
1450/* Print relocations. */
1451static void
1452print_relocs (Ebl *ebl)
1453{
1454 /* Find all relocation sections and handle them. */
1455 Elf_Scn *scn = NULL;
1456
1457 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1458 {
1459 /* Handle the section if it is a symbol table. */
1460 GElf_Shdr shdr_mem;
1461 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1462
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001463 if (likely (shdr != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001464 {
1465 if (shdr->sh_type == SHT_REL)
1466 handle_relocs_rel (ebl, scn, shdr);
1467 else if (shdr->sh_type == SHT_RELA)
1468 handle_relocs_rela (ebl, scn, shdr);
1469 }
1470 }
1471}
1472
1473
1474/* Handle a relocation section. */
1475static void
1476handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1477{
1478 int class = gelf_getclass (ebl->elf);
1479 int nentries = shdr->sh_size / shdr->sh_entsize;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001480
1481 /* Get the data of the section. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001482 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001483 if (data == NULL)
1484 return;
1485
1486 /* Get the symbol table information. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001487 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1488 GElf_Shdr symshdr_mem;
1489 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1490 Elf_Data *symdata = elf_getdata (symscn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001491
1492 /* Get the section header of the section the relocations are for. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001493 GElf_Shdr destshdr_mem;
1494 GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1495 &destshdr_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001496
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001497 if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001498 {
1499 printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1500 shdr->sh_offset);
1501 return;
1502 }
1503
1504 /* Search for the optional extended section index table. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001505 Elf_Data *xndxdata = NULL;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001506 int xndxscnidx = elf_scnshndx (scn);
1507 if (unlikely (xndxscnidx > 0))
1508 xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001509
1510 /* Get the section header string table index. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001511 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001512 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001513 error (EXIT_FAILURE, 0,
1514 gettext ("cannot get section header string table index"));
1515
1516 if (shdr->sh_info != 0)
1517 printf (ngettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08001518\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001519 "\
Ulrich Drepper351bf202009-01-15 20:18:40 -08001520\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001521 nentries),
Ulrich Drepper351bf202009-01-15 20:18:40 -08001522 elf_ndxscn (scn),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001523 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1524 (unsigned int) shdr->sh_info,
1525 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1526 shdr->sh_offset,
1527 nentries);
1528 else
1529 /* The .rel.dyn section does not refer to a specific section but
1530 instead of section index zero. Do not try to print a section
1531 name. */
1532 printf (ngettext ("\
1533\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1534 "\
1535\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1536 nentries),
1537 (unsigned int) elf_ndxscn (scn),
1538 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1539 shdr->sh_offset,
1540 nentries);
1541 fputs_unlocked (class == ELFCLASS32
1542 ? gettext ("\
1543 Offset Type Value Name\n")
1544 : gettext ("\
1545 Offset Type Value Name\n"),
1546 stdout);
1547
Ulrich Drepperd0449522005-09-03 07:23:52 +00001548 for (int cnt = 0; cnt < nentries; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001549 {
1550 GElf_Rel relmem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001551 GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001552 if (likely (rel != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001553 {
1554 char buf[128];
1555 GElf_Sym symmem;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001556 Elf32_Word xndx;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001557 GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
1558 GELF_R_SYM (rel->r_info),
1559 &symmem, &xndx);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001560 if (unlikely (sym == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001561 printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
1562 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1563 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1564 /* Avoid the leading R_ which isn't carrying any
1565 information. */
1566 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1567 buf, sizeof (buf)) + 2
1568 : gettext ("<INVALID RELOC>"),
1569 gettext ("INVALID SYMBOL"),
1570 (long int) GELF_R_SYM (rel->r_info));
1571 else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
1572 printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
1573 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001574 likely (ebl_reloc_type_check (ebl,
1575 GELF_R_TYPE (rel->r_info)))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001576 /* Avoid the leading R_ which isn't carrying any
1577 information. */
1578 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1579 buf, sizeof (buf)) + 2
1580 : gettext ("<INVALID RELOC>"),
1581 class == ELFCLASS32 ? 10 : 18, sym->st_value,
1582 elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
1583 else
1584 {
1585 destshdr = gelf_getshdr (elf_getscn (ebl->elf,
1586 sym->st_shndx == SHN_XINDEX
1587 ? xndx : sym->st_shndx),
1588 &destshdr_mem);
1589
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001590 if (unlikely (destshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001591 printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
1592 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1593 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1594 /* Avoid the leading R_ which isn't carrying any
1595 information. */
1596 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1597 buf, sizeof (buf)) + 2
1598 : gettext ("<INVALID RELOC>"),
1599 gettext ("INVALID SECTION"),
1600 (long int) (sym->st_shndx == SHN_XINDEX
1601 ? xndx : sym->st_shndx));
1602 else
1603 printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
1604 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1605 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1606 /* Avoid the leading R_ which isn't carrying any
1607 information. */
1608 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1609 buf, sizeof (buf)) + 2
1610 : gettext ("<INVALID RELOC>"),
1611 class == ELFCLASS32 ? 10 : 18, sym->st_value,
1612 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1613 }
1614 }
1615 }
1616}
1617
1618
1619/* Handle a relocation section. */
1620static void
1621handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1622{
1623 int class = gelf_getclass (ebl->elf);
1624 int nentries = shdr->sh_size / shdr->sh_entsize;
1625
1626 /* Get the data of the section. */
1627 Elf_Data *data = elf_getdata (scn, NULL);
1628 if (data == NULL)
1629 return;
1630
1631 /* Get the symbol table information. */
1632 Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1633 GElf_Shdr symshdr_mem;
1634 GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1635 Elf_Data *symdata = elf_getdata (symscn, NULL);
1636
1637 /* Get the section header of the section the relocations are for. */
1638 GElf_Shdr destshdr_mem;
1639 GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1640 &destshdr_mem);
1641
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001642 if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001643 {
1644 printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
1645 shdr->sh_offset);
1646 return;
1647 }
1648
1649 /* Search for the optional extended section index table. */
1650 Elf_Data *xndxdata = NULL;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001651 int xndxscnidx = elf_scnshndx (scn);
1652 if (unlikely (xndxscnidx > 0))
1653 xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001654
1655 /* Get the section header string table index. */
1656 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001657 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001658 error (EXIT_FAILURE, 0,
1659 gettext ("cannot get section header string table index"));
1660
1661 printf (ngettext ("\
1662\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
1663 "\
1664\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
1665 nentries),
1666 elf_ndxscn (scn),
1667 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
1668 (unsigned int) shdr->sh_info,
1669 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
1670 shdr->sh_offset,
1671 nentries);
1672 fputs_unlocked (class == ELFCLASS32
1673 ? gettext ("\
1674 Offset Type Value Addend Name\n")
1675 : gettext ("\
1676 Offset Type Value Addend Name\n"),
1677 stdout);
1678
1679 for (int cnt = 0; cnt < nentries; ++cnt)
1680 {
1681 GElf_Rela relmem;
1682 GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001683 if (likely (rel != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001684 {
1685 char buf[64];
1686 GElf_Sym symmem;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001687 Elf32_Word xndx;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001688 GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
1689 GELF_R_SYM (rel->r_info),
1690 &symmem, &xndx);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001691
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001692 if (unlikely (sym == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001693 printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
1694 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1695 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1696 /* Avoid the leading R_ which isn't carrying any
1697 information. */
1698 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1699 buf, sizeof (buf)) + 2
1700 : gettext ("<INVALID RELOC>"),
1701 gettext ("INVALID SYMBOL"),
1702 (long int) GELF_R_SYM (rel->r_info));
1703 else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
1704 printf ("\
Ulrich Drepper2cb8e732006-05-27 21:57:27 +00001705 %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001706 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001707 likely (ebl_reloc_type_check (ebl,
1708 GELF_R_TYPE (rel->r_info)))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001709 /* Avoid the leading R_ which isn't carrying any
1710 information. */
1711 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1712 buf, sizeof (buf)) + 2
1713 : gettext ("<INVALID RELOC>"),
1714 class == ELFCLASS32 ? 10 : 18, sym->st_value,
1715 rel->r_addend,
1716 elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
1717 else
1718 {
1719 destshdr = gelf_getshdr (elf_getscn (ebl->elf,
1720 sym->st_shndx == SHN_XINDEX
1721 ? xndx : sym->st_shndx),
1722 &destshdr_mem);
1723
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001724 if (unlikely (shdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001725 printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
1726 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1727 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1728 /* Avoid the leading R_ which isn't carrying any
1729 information. */
1730 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1731 buf, sizeof (buf)) + 2
1732 : gettext ("<INVALID RELOC>"),
1733 gettext ("INVALID SECTION"),
1734 (long int) (sym->st_shndx == SHN_XINDEX
1735 ? xndx : sym->st_shndx));
1736 else
1737 printf ("\
Ulrich Drepper2cb8e732006-05-27 21:57:27 +00001738 %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001739 class == ELFCLASS32 ? 10 : 18, rel->r_offset,
1740 ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
1741 /* Avoid the leading R_ which isn't carrying any
1742 information. */
1743 ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
1744 buf, sizeof (buf)) + 2
1745 : gettext ("<INVALID RELOC>"),
1746 class == ELFCLASS32 ? 10 : 18, sym->st_value,
1747 rel->r_addend,
1748 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
1749 }
1750 }
1751 }
1752}
1753
1754
1755/* Print the program header. */
1756static void
1757print_symtab (Ebl *ebl, int type)
1758{
1759 /* Find the symbol table(s). For this we have to search through the
1760 section table. */
1761 Elf_Scn *scn = NULL;
1762
1763 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1764 {
1765 /* Handle the section if it is a symbol table. */
1766 GElf_Shdr shdr_mem;
1767 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1768
1769 if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
1770 handle_symtab (ebl, scn, shdr);
1771 }
1772}
1773
1774
1775static void
1776handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
1777{
1778 Elf_Data *versym_data = NULL;
1779 Elf_Data *verneed_data = NULL;
1780 Elf_Data *verdef_data = NULL;
1781 Elf_Data *xndx_data = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001782 int class = gelf_getclass (ebl->elf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001783 Elf32_Word verneed_stridx = 0;
1784 Elf32_Word verdef_stridx = 0;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001785
1786 /* Get the data of the section. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001787 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001788 if (data == NULL)
1789 return;
1790
1791 /* Find out whether we have other sections we might need. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001792 Elf_Scn *runscn = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001793 while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL)
1794 {
1795 GElf_Shdr runshdr_mem;
1796 GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
1797
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001798 if (likely (runshdr != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001799 {
1800 if (runshdr->sh_type == SHT_GNU_versym
1801 && runshdr->sh_link == elf_ndxscn (scn))
1802 /* Bingo, found the version information. Now get the data. */
1803 versym_data = elf_getdata (runscn, NULL);
1804 else if (runshdr->sh_type == SHT_GNU_verneed)
1805 {
1806 /* This is the information about the needed versions. */
1807 verneed_data = elf_getdata (runscn, NULL);
1808 verneed_stridx = runshdr->sh_link;
1809 }
1810 else if (runshdr->sh_type == SHT_GNU_verdef)
1811 {
1812 /* This is the information about the defined versions. */
1813 verdef_data = elf_getdata (runscn, NULL);
1814 verdef_stridx = runshdr->sh_link;
1815 }
1816 else if (runshdr->sh_type == SHT_SYMTAB_SHNDX
1817 && runshdr->sh_link == elf_ndxscn (scn))
1818 /* Extended section index. */
1819 xndx_data = elf_getdata (runscn, NULL);
1820 }
1821 }
1822
1823 /* Get the section header string table index. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001824 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001825 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001826 error (EXIT_FAILURE, 0,
1827 gettext ("cannot get section header string table index"));
1828
1829 /* Now we can compute the number of entries in the section. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00001830 unsigned int nsyms = data->d_size / (class == ELFCLASS32
1831 ? sizeof (Elf32_Sym)
1832 : sizeof (Elf64_Sym));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001833
1834 printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n",
1835 "\nSymbol table [%2u] '%s' contains %u entries:\n",
1836 nsyms),
1837 (unsigned int) elf_ndxscn (scn),
1838 elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms);
Ulrich Drepperd0449522005-09-03 07:23:52 +00001839 GElf_Shdr glink;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001840 printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n",
1841 " %lu local symbols String table: [%2u] '%s'\n",
1842 shdr->sh_info),
1843 (unsigned long int) shdr->sh_info,
1844 (unsigned int) shdr->sh_link,
1845 elf_strptr (ebl->elf, shstrndx,
1846 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
1847 &glink)->sh_name));
1848
1849 fputs_unlocked (class == ELFCLASS32
1850 ? gettext ("\
1851 Num: Value Size Type Bind Vis Ndx Name\n")
1852 : gettext ("\
1853 Num: Value Size Type Bind Vis Ndx Name\n"),
1854 stdout);
1855
Ulrich Drepperd0449522005-09-03 07:23:52 +00001856 for (unsigned int cnt = 0; cnt < nsyms; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001857 {
1858 char typebuf[64];
1859 char bindbuf[64];
1860 char scnbuf[64];
1861 Elf32_Word xndx;
1862 GElf_Sym sym_mem;
1863 GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
1864
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001865 if (unlikely (sym == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001866 continue;
1867
1868 /* Determine the real section index. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001869 if (likely (sym->st_shndx != SHN_XINDEX))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001870 xndx = sym->st_shndx;
1871
1872 printf (gettext ("\
1873%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"),
1874 cnt,
1875 class == ELFCLASS32 ? 8 : 16,
1876 sym->st_value,
1877 sym->st_size,
1878 ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
1879 typebuf, sizeof (typebuf)),
1880 ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info),
1881 bindbuf, sizeof (bindbuf)),
1882 get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)),
1883 ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf,
1884 sizeof (scnbuf), NULL, shnum),
1885 elf_strptr (ebl->elf, shdr->sh_link, sym->st_name));
1886
1887 if (versym_data != NULL)
1888 {
1889 /* Get the version information. */
1890 GElf_Versym versym_mem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001891 GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001892
1893 if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1))
1894 {
1895 bool is_nobits = false;
1896 bool check_def = xndx != SHN_UNDEF;
1897
1898 if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX)
1899 {
1900 GElf_Shdr symshdr_mem;
1901 GElf_Shdr *symshdr =
1902 gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem);
1903
1904 is_nobits = (symshdr != NULL
1905 && symshdr->sh_type == SHT_NOBITS);
1906 }
1907
1908 if (is_nobits || ! check_def)
1909 {
1910 /* We must test both. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001911 GElf_Vernaux vernaux_mem;
1912 GElf_Vernaux *vernaux = NULL;
1913 size_t vn_offset = 0;
1914
Ulrich Drepperd0449522005-09-03 07:23:52 +00001915 GElf_Verneed verneed_mem;
1916 GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0,
1917 &verneed_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001918 while (verneed != NULL)
1919 {
1920 size_t vna_offset = vn_offset;
1921
1922 vernaux = gelf_getvernaux (verneed_data,
1923 vna_offset += verneed->vn_aux,
1924 &vernaux_mem);
1925 while (vernaux != NULL
1926 && vernaux->vna_other != *versym
1927 && vernaux->vna_next != 0)
1928 {
1929 /* Update the offset. */
1930 vna_offset += vernaux->vna_next;
1931
1932 vernaux = (vernaux->vna_next == 0
1933 ? NULL
1934 : gelf_getvernaux (verneed_data,
1935 vna_offset,
1936 &vernaux_mem));
1937 }
1938
1939 /* Check whether we found the version. */
1940 if (vernaux != NULL && vernaux->vna_other == *versym)
1941 /* Found it. */
1942 break;
1943
1944 vn_offset += verneed->vn_next;
1945 verneed = (verneed->vn_next == 0
1946 ? NULL
1947 : gelf_getverneed (verneed_data, vn_offset,
1948 &verneed_mem));
1949 }
1950
1951 if (vernaux != NULL && vernaux->vna_other == *versym)
1952 {
1953 printf ("@%s (%u)",
1954 elf_strptr (ebl->elf, verneed_stridx,
1955 vernaux->vna_name),
1956 (unsigned int) vernaux->vna_other);
1957 check_def = 0;
1958 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001959 else if (unlikely (! is_nobits))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001960 error (0, 0, gettext ("bad dynamic symbol"));
1961 else
1962 check_def = 1;
1963 }
1964
1965 if (check_def && *versym != 0x8001)
1966 {
1967 /* We must test both. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001968 size_t vd_offset = 0;
1969
Ulrich Drepperd0449522005-09-03 07:23:52 +00001970 GElf_Verdef verdef_mem;
1971 GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0,
1972 &verdef_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001973 while (verdef != NULL)
1974 {
1975 if (verdef->vd_ndx == (*versym & 0x7fff))
1976 /* Found the definition. */
1977 break;
1978
1979 vd_offset += verdef->vd_next;
1980 verdef = (verdef->vd_next == 0
1981 ? NULL
1982 : gelf_getverdef (verdef_data, vd_offset,
1983 &verdef_mem));
1984 }
1985
1986 if (verdef != NULL)
1987 {
1988 GElf_Verdaux verdaux_mem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00001989 GElf_Verdaux *verdaux
1990 = gelf_getverdaux (verdef_data,
1991 vd_offset + verdef->vd_aux,
1992 &verdaux_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001993
1994 if (verdaux != NULL)
1995 printf ((*versym & 0x8000) ? "@%s" : "@@%s",
1996 elf_strptr (ebl->elf, verdef_stridx,
1997 verdaux->vda_name));
1998 }
1999 }
2000 }
2001 }
2002
Ulrich Drepperd0449522005-09-03 07:23:52 +00002003 putchar_unlocked ('\n');
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002004 }
2005}
2006
2007
2008/* Print version information. */
2009static void
2010print_verinfo (Ebl *ebl)
2011{
2012 /* Find the version information sections. For this we have to
2013 search through the section table. */
2014 Elf_Scn *scn = NULL;
2015
2016 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2017 {
2018 /* Handle the section if it is part of the versioning handling. */
2019 GElf_Shdr shdr_mem;
2020 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2021
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002022 if (likely (shdr != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002023 {
2024 if (shdr->sh_type == SHT_GNU_verneed)
2025 handle_verneed (ebl, scn, shdr);
2026 else if (shdr->sh_type == SHT_GNU_verdef)
2027 handle_verdef (ebl, scn, shdr);
2028 else if (shdr->sh_type == SHT_GNU_versym)
2029 handle_versym (ebl, scn, shdr);
2030 }
2031 }
2032}
2033
2034
2035static const char *
2036get_ver_flags (unsigned int flags)
2037{
2038 static char buf[32];
2039 char *endp;
2040
2041 if (flags == 0)
2042 return gettext ("none");
2043
2044 if (flags & VER_FLG_BASE)
2045 endp = stpcpy (buf, "BASE ");
2046 else
2047 endp = buf;
2048
2049 if (flags & VER_FLG_WEAK)
2050 {
2051 if (endp != buf)
2052 endp = stpcpy (endp, "| ");
2053
2054 endp = stpcpy (endp, "WEAK ");
2055 }
2056
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002057 if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002058 {
2059 strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
2060 buf[sizeof (buf) - 1] = '\0';
2061 }
2062
2063 return buf;
2064}
2065
2066
2067static void
2068handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2069{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002070 int class = gelf_getclass (ebl->elf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002071
2072 /* Get the data of the section. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002073 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002074 if (data == NULL)
2075 return;
2076
2077 /* Get the section header string table index. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002078 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002079 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002080 error (EXIT_FAILURE, 0,
2081 gettext ("cannot get section header string table index"));
2082
Ulrich Drepperdbace232005-08-06 01:37:23 +00002083 GElf_Shdr glink;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002084 printf (ngettext ("\
2085\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2086 "\
2087\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2088 shdr->sh_info),
2089 (unsigned int) elf_ndxscn (scn),
2090 elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info,
2091 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2092 shdr->sh_offset,
2093 (unsigned int) shdr->sh_link,
2094 elf_strptr (ebl->elf, shstrndx,
2095 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2096 &glink)->sh_name));
2097
Ulrich Drepperdbace232005-08-06 01:37:23 +00002098 unsigned int offset = 0;
2099 for (int cnt = shdr->sh_info; --cnt >= 0; )
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002100 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002101 /* Get the data at the next offset. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002102 GElf_Verneed needmem;
2103 GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002104 if (unlikely (need == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002105 break;
2106
2107 printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"),
2108 offset, (unsigned short int) need->vn_version,
2109 elf_strptr (ebl->elf, shdr->sh_link, need->vn_file),
2110 (unsigned short int) need->vn_cnt);
2111
Ulrich Drepperdbace232005-08-06 01:37:23 +00002112 unsigned int auxoffset = offset + need->vn_aux;
2113 for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002114 {
2115 GElf_Vernaux auxmem;
Ulrich Drepperdbace232005-08-06 01:37:23 +00002116 GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002117 if (unlikely (aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002118 break;
2119
2120 printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"),
2121 auxoffset,
2122 elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name),
2123 get_ver_flags (aux->vna_flags),
2124 (unsigned short int) aux->vna_other);
2125
2126 auxoffset += aux->vna_next;
2127 }
2128
2129 /* Find the next offset. */
2130 offset += need->vn_next;
2131 }
2132}
2133
2134
2135static void
2136handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2137{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002138 /* Get the data of the section. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002139 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002140 if (data == NULL)
2141 return;
2142
2143 /* Get the section header string table index. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002144 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002145 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002146 error (EXIT_FAILURE, 0,
2147 gettext ("cannot get section header string table index"));
2148
Ulrich Drepperdbace232005-08-06 01:37:23 +00002149 int class = gelf_getclass (ebl->elf);
2150 GElf_Shdr glink;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002151 printf (ngettext ("\
2152\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2153 "\
2154\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
2155 shdr->sh_info),
2156 (unsigned int) elf_ndxscn (scn),
2157 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2158 shdr->sh_info,
2159 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2160 shdr->sh_offset,
2161 (unsigned int) shdr->sh_link,
2162 elf_strptr (ebl->elf, shstrndx,
2163 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2164 &glink)->sh_name));
2165
Ulrich Drepperdbace232005-08-06 01:37:23 +00002166 unsigned int offset = 0;
2167 for (int cnt = shdr->sh_info; --cnt >= 0; )
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002168 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002169 /* Get the data at the next offset. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002170 GElf_Verdef defmem;
2171 GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002172 if (unlikely (def == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002173 break;
2174
Ulrich Drepperdbace232005-08-06 01:37:23 +00002175 unsigned int auxoffset = offset + def->vd_aux;
2176 GElf_Verdaux auxmem;
2177 GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002178 if (unlikely (aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002179 break;
2180
2181 printf (gettext ("\
2182 %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"),
2183 offset, def->vd_version,
2184 get_ver_flags (def->vd_flags),
2185 def->vd_ndx,
2186 def->vd_cnt,
2187 elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2188
2189 auxoffset += aux->vda_next;
Ulrich Drepperdbace232005-08-06 01:37:23 +00002190 for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002191 {
2192 aux = gelf_getverdaux (data, auxoffset, &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002193 if (unlikely (aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002194 break;
2195
2196 printf (gettext (" %#06x: Parent %d: %s\n"),
2197 auxoffset, cnt2,
2198 elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
2199
2200 auxoffset += aux->vda_next;
2201 }
2202
2203 /* Find the next offset. */
2204 offset += def->vd_next;
2205 }
2206}
2207
2208
2209static void
2210handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
2211{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002212 int class = gelf_getclass (ebl->elf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002213 const char **vername;
2214 const char **filename;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002215
2216 /* Get the data of the section. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002217 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002218 if (data == NULL)
2219 return;
2220
2221 /* Get the section header string table index. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002222 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002223 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002224 error (EXIT_FAILURE, 0,
2225 gettext ("cannot get section header string table index"));
2226
2227 /* We have to find the version definition section and extract the
2228 version names. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002229 Elf_Scn *defscn = NULL;
2230 Elf_Scn *needscn = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002231
Ulrich Drepperdbace232005-08-06 01:37:23 +00002232 Elf_Scn *verscn = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002233 while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL)
2234 {
2235 GElf_Shdr vershdr_mem;
2236 GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
2237
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002238 if (likely (vershdr != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002239 {
2240 if (vershdr->sh_type == SHT_GNU_verdef)
2241 defscn = verscn;
2242 else if (vershdr->sh_type == SHT_GNU_verneed)
2243 needscn = verscn;
2244 }
2245 }
2246
Ulrich Drepperdbace232005-08-06 01:37:23 +00002247 size_t nvername;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002248 if (defscn != NULL || needscn != NULL)
2249 {
2250 /* We have a version information (better should have). Now get
2251 the version names. First find the maximum version number. */
2252 nvername = 0;
2253 if (defscn != NULL)
2254 {
2255 /* Run through the version definitions and find the highest
2256 index. */
2257 unsigned int offset = 0;
2258 Elf_Data *defdata;
2259 GElf_Shdr defshdrmem;
2260 GElf_Shdr *defshdr;
2261
2262 defdata = elf_getdata (defscn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002263 if (unlikely (defdata == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002264 return;
2265
2266 defshdr = gelf_getshdr (defscn, &defshdrmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002267 if (unlikely (defshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002268 return;
2269
Ulrich Drepperdbace232005-08-06 01:37:23 +00002270 for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002271 {
2272 GElf_Verdef defmem;
2273 GElf_Verdef *def;
2274
2275 /* Get the data at the next offset. */
2276 def = gelf_getverdef (defdata, offset, &defmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002277 if (unlikely (def == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002278 break;
2279
2280 nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
2281
2282 offset += def->vd_next;
2283 }
2284 }
2285 if (needscn != NULL)
2286 {
2287 unsigned int offset = 0;
2288 Elf_Data *needdata;
2289 GElf_Shdr needshdrmem;
2290 GElf_Shdr *needshdr;
2291
2292 needdata = elf_getdata (needscn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002293 if (unlikely (needdata == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002294 return;
2295
2296 needshdr = gelf_getshdr (needscn, &needshdrmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002297 if (unlikely (needshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002298 return;
2299
Ulrich Drepperdbace232005-08-06 01:37:23 +00002300 for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002301 {
2302 GElf_Verneed needmem;
2303 GElf_Verneed *need;
2304 unsigned int auxoffset;
2305 int cnt2;
2306
2307 /* Get the data at the next offset. */
2308 need = gelf_getverneed (needdata, offset, &needmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002309 if (unlikely (need == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002310 break;
2311
2312 /* Run through the auxiliary entries. */
2313 auxoffset = offset + need->vn_aux;
2314 for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
2315 {
2316 GElf_Vernaux auxmem;
2317 GElf_Vernaux *aux;
2318
2319 aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002320 if (unlikely (aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002321 break;
2322
2323 nvername = MAX (nvername,
2324 (size_t) (aux->vna_other & 0x7fff));
2325
2326 auxoffset += aux->vna_next;
2327 }
2328
2329 offset += need->vn_next;
2330 }
2331 }
2332
2333 /* This is the number of versions we know about. */
2334 ++nvername;
2335
2336 /* Allocate the array. */
2337 vername = (const char **) alloca (nvername * sizeof (const char *));
2338 filename = (const char **) alloca (nvername * sizeof (const char *));
2339
2340 /* Run through the data structures again and collect the strings. */
2341 if (defscn != NULL)
2342 {
2343 /* Run through the version definitions and find the highest
2344 index. */
2345 unsigned int offset = 0;
2346 Elf_Data *defdata;
2347 GElf_Shdr defshdrmem;
2348 GElf_Shdr *defshdr;
2349
2350 defdata = elf_getdata (defscn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002351 if (unlikely (defdata == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002352 return;
2353
2354 defshdr = gelf_getshdr (defscn, &defshdrmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002355 if (unlikely (defshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002356 return;
2357
Ulrich Drepperdbace232005-08-06 01:37:23 +00002358 for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002359 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002360
2361 /* Get the data at the next offset. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00002362 GElf_Verdef defmem;
2363 GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
2364 GElf_Verdaux auxmem;
2365 GElf_Verdaux *aux = gelf_getverdaux (defdata,
2366 offset + def->vd_aux,
2367 &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002368 if (unlikely (def == NULL || aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002369 break;
2370
2371 vername[def->vd_ndx & 0x7fff]
2372 = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name);
2373 filename[def->vd_ndx & 0x7fff] = NULL;
2374
2375 offset += def->vd_next;
2376 }
2377 }
2378 if (needscn != NULL)
2379 {
2380 unsigned int offset = 0;
Ulrich Drepperd0449522005-09-03 07:23:52 +00002381
2382 Elf_Data *needdata = elf_getdata (needscn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002383 GElf_Shdr needshdrmem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00002384 GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002385 if (unlikely (needdata == NULL || needshdr == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002386 return;
2387
Ulrich Drepperdbace232005-08-06 01:37:23 +00002388 for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002389 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002390 /* Get the data at the next offset. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00002391 GElf_Verneed needmem;
2392 GElf_Verneed *need = gelf_getverneed (needdata, offset,
2393 &needmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002394 if (unlikely (need == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002395 break;
2396
2397 /* Run through the auxiliary entries. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00002398 unsigned int auxoffset = offset + need->vn_aux;
2399 for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002400 {
2401 GElf_Vernaux auxmem;
Ulrich Drepperd0449522005-09-03 07:23:52 +00002402 GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
2403 &auxmem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002404 if (unlikely (aux == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002405 break;
2406
2407 vername[aux->vna_other & 0x7fff]
2408 = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name);
2409 filename[aux->vna_other & 0x7fff]
2410 = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file);
2411
2412 auxoffset += aux->vna_next;
2413 }
2414
2415 offset += need->vn_next;
2416 }
2417 }
2418 }
2419 else
2420 {
2421 vername = NULL;
2422 nvername = 1;
2423 filename = NULL;
2424 }
2425
2426 /* Print the header. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00002427 GElf_Shdr glink;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002428 printf (ngettext ("\
2429\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
2430 "\
2431\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'",
2432 shdr->sh_size / shdr->sh_entsize),
2433 (unsigned int) elf_ndxscn (scn),
2434 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2435 (int) (shdr->sh_size / shdr->sh_entsize),
2436 class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
2437 shdr->sh_offset,
2438 (unsigned int) shdr->sh_link,
2439 elf_strptr (ebl->elf, shstrndx,
2440 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2441 &glink)->sh_name));
2442
2443 /* Now we can finally look at the actual contents of this section. */
Ulrich Drepperdbace232005-08-06 01:37:23 +00002444 for (unsigned int cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002445 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002446 if (cnt % 2 == 0)
2447 printf ("\n %4d:", cnt);
2448
Ulrich Drepperd0449522005-09-03 07:23:52 +00002449 GElf_Versym symmem;
2450 GElf_Versym *sym = gelf_getversym (data, cnt, &symmem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002451 if (sym == NULL)
2452 break;
2453
2454 switch (*sym)
2455 {
Ulrich Drepperd0449522005-09-03 07:23:52 +00002456 ssize_t n;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002457 case 0:
2458 fputs_unlocked (gettext (" 0 *local* "),
2459 stdout);
2460 break;
2461
2462 case 1:
2463 fputs_unlocked (gettext (" 1 *global* "),
2464 stdout);
2465 break;
2466
2467 default:
2468 n = printf ("%4d%c%s",
2469 *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ',
2470 (unsigned int) (*sym & 0x7fff) < nvername
2471 ? vername[*sym & 0x7fff] : "???");
2472 if ((unsigned int) (*sym & 0x7fff) < nvername
2473 && filename[*sym & 0x7fff] != NULL)
2474 n += printf ("(%s)", filename[*sym & 0x7fff]);
2475 printf ("%*s", MAX (0, 33 - (int) n), " ");
2476 break;
2477 }
2478 }
Ulrich Drepperd0449522005-09-03 07:23:52 +00002479 putchar_unlocked ('\n');
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002480}
2481
2482
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002483static void
2484print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
2485 uint_fast32_t maxlength, Elf32_Word nbucket,
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002486 uint_fast32_t nsyms, uint32_t *lengths, const char *extrastr)
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002487{
2488 uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
2489
2490 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2491 ++counts[lengths[cnt]];
2492
2493 GElf_Shdr glink;
2494 printf (ngettext ("\
2495\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",
2496 "\
2497\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",
2498 nbucket),
2499 (unsigned int) elf_ndxscn (scn),
2500 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2501 (int) nbucket,
2502 gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
2503 shdr->sh_addr,
2504 shdr->sh_offset,
2505 (unsigned int) shdr->sh_link,
2506 elf_strptr (ebl->elf, shstrndx,
2507 gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2508 &glink)->sh_name));
2509
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002510 if (extrastr != NULL)
2511 fputs (extrastr, stdout);
2512
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002513 if (likely (nbucket > 0))
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002514 {
2515 uint64_t success = 0;
2516
2517 fputs_unlocked (gettext ("\
2518 Length Number % of total Coverage\n"), stdout);
2519 printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
2520 counts[0], (counts[0] * 100.0) / nbucket);
2521
2522 uint64_t nzero_counts = 0;
2523 for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2524 {
2525 nzero_counts += counts[cnt] * cnt;
2526 printf (gettext ("\
2527%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
2528 (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
2529 (nzero_counts * 100.0) / nsyms);
2530 }
2531
2532 Elf32_Word acc = 0;
2533 for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
2534 {
2535 acc += cnt;
2536 success += counts[cnt] * acc;
2537 }
2538
2539 printf (gettext ("\
2540 Average number of tests: successful lookup: %f\n\
2541 unsuccessful lookup: %f\n"),
2542 (double) success / (double) nzero_counts,
2543 (double) nzero_counts / (double) nbucket);
2544 }
2545
2546 free (counts);
2547}
2548
2549
2550/* This function handles the traditional System V-style hash table format. */
2551static void
2552handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2553{
2554 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002555 if (unlikely (data == NULL))
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002556 {
2557 error (0, 0, gettext ("cannot get data for section %d: %s"),
2558 (int) elf_ndxscn (scn), elf_errmsg (-1));
2559 return;
2560 }
2561
2562 Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
2563 Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
2564 Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
2565 Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
2566
2567 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2568
2569 uint_fast32_t maxlength = 0;
2570 uint_fast32_t nsyms = 0;
2571 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2572 {
2573 Elf32_Word inner = bucket[cnt];
2574 while (inner > 0 && inner < nchain)
2575 {
2576 ++nsyms;
2577 if (maxlength < ++lengths[cnt])
2578 ++maxlength;
2579
2580 inner = chain[inner];
2581 }
2582 }
2583
2584 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002585 lengths, NULL);
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002586
2587 free (lengths);
2588}
2589
2590
2591/* This function handles the incorrect, System V-style hash table
2592 format some 64-bit architectures use. */
2593static void
2594handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2595{
2596 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002597 if (unlikely (data == NULL))
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002598 {
2599 error (0, 0, gettext ("cannot get data for section %d: %s"),
2600 (int) elf_ndxscn (scn), elf_errmsg (-1));
2601 return;
2602 }
2603
2604 Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
2605 Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
2606 Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
2607 Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
2608
2609 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2610
2611 uint_fast32_t maxlength = 0;
2612 uint_fast32_t nsyms = 0;
2613 for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
2614 {
2615 Elf64_Xword inner = bucket[cnt];
2616 while (inner > 0 && inner < nchain)
2617 {
2618 ++nsyms;
2619 if (maxlength < ++lengths[cnt])
2620 ++maxlength;
2621
2622 inner = chain[inner];
2623 }
2624 }
2625
2626 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002627 lengths, NULL);
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002628
2629 free (lengths);
2630}
2631
2632
2633/* This function handles the GNU-style hash table format. */
2634static void
2635handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
2636{
2637 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002638 if (unlikely (data == NULL))
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002639 {
2640 error (0, 0, gettext ("cannot get data for section %d: %s"),
2641 (int) elf_ndxscn (scn), elf_errmsg (-1));
2642 return;
2643 }
2644
2645 Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
2646 Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002647
2648 /* Next comes the size of the bitmap. It's measured in words for
2649 the architecture. It's 32 bits for 32 bit archs, and 64 bits for
2650 64 bit archs. */
2651 Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
2652 if (gelf_getclass (ebl->elf) == ELFCLASS64)
2653 bitmask_words *= 2;
2654
2655 Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002656
2657 uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
2658
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002659 Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
2660 Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
2661 Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[4 + bitmask_words
2662 + nbucket];
2663
2664 /* Compute distribution of chain lengths. */
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002665 uint_fast32_t maxlength = 0;
2666 uint_fast32_t nsyms = 0;
2667 for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002668 if (bucket[cnt] != 0)
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002669 {
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002670 Elf32_Word inner = bucket[cnt] - symbias;
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002671 do
2672 {
2673 ++nsyms;
2674 if (maxlength < ++lengths[cnt])
2675 ++maxlength;
2676 }
2677 while ((chain[inner++] & 1) == 0);
2678 }
2679
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002680 /* Count bits in bitmask. */
2681 uint_fast32_t nbits = 0;
2682 for (Elf32_Word cnt = 0; cnt < bitmask_words; ++cnt)
2683 {
2684 uint_fast32_t word = bitmask[cnt];
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002685
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002686 word = (word & 0x55555555) + ((word >> 1) & 0x55555555);
2687 word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
2688 word = (word & 0x0f0f0f0f) + ((word >> 4) & 0x0f0f0f0f);
2689 word = (word & 0x00ff00ff) + ((word >> 8) & 0x00ff00ff);
2690 nbits += (word & 0x0000ffff) + ((word >> 16) & 0x0000ffff);
2691 }
2692
2693 char *str;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002694 if (unlikely (asprintf (&str, gettext ("\
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002695 Symbol Bias: %u\n\
2696 Bitmask Size: %zu bytes %" PRIuFAST32 "%% bits set 2nd hash shift: %u\n"),
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002697 (unsigned int) symbias,
2698 bitmask_words * sizeof (Elf32_Word),
2699 ((nbits * 100 + 50)
2700 / (uint_fast32_t) (bitmask_words
2701 * sizeof (Elf32_Word) * 8)),
2702 (unsigned int) shift) == -1))
Ulrich Drepper8ae58142006-07-12 05:22:32 +00002703 error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
2704
2705 print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
2706 lengths, str);
2707
2708 free (str);
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002709 free (lengths);
2710}
2711
2712
Ulrich Drepperd0449522005-09-03 07:23:52 +00002713/* Find the symbol table(s). For this we have to search through the
2714 section table. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002715static void
2716handle_hash (Ebl *ebl)
2717{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002718 /* Get the section header string table index. */
Ulrich Drepperd0449522005-09-03 07:23:52 +00002719 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002720 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002721 error (EXIT_FAILURE, 0,
2722 gettext ("cannot get section header string table index"));
2723
Ulrich Drepperd0449522005-09-03 07:23:52 +00002724 Elf_Scn *scn = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002725 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2726 {
2727 /* Handle the section if it is a symbol table. */
2728 GElf_Shdr shdr_mem;
2729 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2730
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002731 if (likely (shdr != NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002732 {
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002733 if (shdr->sh_type == SHT_HASH)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002734 {
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002735 if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
2736 handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
2737 else
2738 handle_sysv_hash (ebl, scn, shdr, shstrndx);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002739 }
Ulrich Drepper28ed8952006-07-07 03:43:47 +00002740 else if (shdr->sh_type == SHT_GNU_HASH)
2741 handle_gnu_hash (ebl, scn, shdr, shstrndx);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002742 }
2743 }
2744}
2745
2746
2747static void
2748print_liblist (Ebl *ebl)
2749{
2750 /* Find the library list sections. For this we have to search
2751 through the section table. */
2752 Elf_Scn *scn = NULL;
2753
2754 /* Get the section header string table index. */
2755 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002756 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002757 error (EXIT_FAILURE, 0,
2758 gettext ("cannot get section header string table index"));
2759
2760 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2761 {
2762 GElf_Shdr shdr_mem;
2763 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2764
2765 if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST)
2766 {
2767 int nentries = shdr->sh_size / shdr->sh_entsize;
2768 printf (ngettext ("\
2769\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
2770 "\
2771\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
2772 nentries),
2773 elf_ndxscn (scn),
2774 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2775 shdr->sh_offset,
2776 nentries);
2777
2778 Elf_Data *data = elf_getdata (scn, NULL);
2779 if (data == NULL)
2780 return;
2781
2782 puts (gettext ("\
2783 Library Time Stamp Checksum Version Flags"));
2784
2785 for (int cnt = 0; cnt < nentries; ++cnt)
2786 {
2787 GElf_Lib lib_mem;
2788 GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002789 if (unlikely (lib == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002790 continue;
2791
2792 time_t t = (time_t) lib->l_time_stamp;
2793 struct tm *tm = gmtime (&t);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00002794 if (unlikely (tm == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002795 continue;
2796
2797 printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
2798 cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name),
2799 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
2800 tm->tm_hour, tm->tm_min, tm->tm_sec,
2801 (unsigned int) lib->l_checksum,
2802 (unsigned int) lib->l_version,
2803 (unsigned int) lib->l_flags);
2804 }
2805 }
2806 }
2807}
2808
Roland McGrath059c83e2008-02-21 06:19:39 +00002809static void
2810print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
2811{
2812 /* Find the object attributes sections. For this we have to search
2813 through the section table. */
2814 Elf_Scn *scn = NULL;
2815
2816 /* Get the section header string table index. */
2817 size_t shstrndx;
2818 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
2819 error (EXIT_FAILURE, 0,
2820 gettext ("cannot get section header string table index"));
2821
2822 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2823 {
2824 GElf_Shdr shdr_mem;
2825 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2826
2827 if (shdr == NULL || shdr->sh_type != SHT_GNU_ATTRIBUTES)
2828 continue;
2829
2830 printf (gettext ("\
2831\nObject attributes section [%2zu] '%s' of %" PRIu64
2832 " bytes at offset %#0" PRIx64 ":\n"),
2833 elf_ndxscn (scn),
2834 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
2835 shdr->sh_size, shdr->sh_offset);
2836
2837 Elf_Data *data = elf_rawdata (scn, NULL);
2838 if (data == NULL)
2839 return;
2840
2841 const unsigned char *p = data->d_buf;
2842
2843 if (unlikely (*p++ != 'A'))
2844 return;
2845
2846 fputs_unlocked (gettext (" Owner Size\n"), stdout);
2847
2848 inline size_t left (void)
2849 {
2850 return (const unsigned char *) data->d_buf + data->d_size - p;
2851 }
2852
2853 while (left () >= 4)
2854 {
2855 uint32_t len;
2856 memcpy (&len, p, sizeof len);
2857
2858 if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
2859 CONVERT (len);
2860
2861 if (unlikely (len > left ()))
2862 break;
2863
2864 const unsigned char *name = p + sizeof len;
2865 p += len;
2866
2867 unsigned const char *q = memchr (name, '\0', len);
2868 if (unlikely (q == NULL))
2869 continue;
2870 ++q;
2871
2872 printf (gettext (" %-13s %4" PRIu32 "\n"), name, len);
2873
2874 if (q - name == sizeof "gnu"
2875 && !memcmp (name, "gnu", sizeof "gnu"))
2876 while (q < p)
2877 {
2878 const unsigned char *const sub = q;
2879
2880 unsigned int subsection_tag;
2881 get_uleb128 (subsection_tag, q);
2882 if (unlikely (q >= p))
2883 break;
2884
2885 uint32_t subsection_len;
2886 if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len))
2887 break;
2888
2889 memcpy (&subsection_len, q, sizeof subsection_len);
2890
2891 if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
2892 CONVERT (subsection_len);
2893
Roland McGrath47c5c352008-02-29 10:17:16 +00002894 if (unlikely (p - sub < (ptrdiff_t) subsection_len))
Roland McGrath059c83e2008-02-21 06:19:39 +00002895 break;
2896
2897 const unsigned char *r = q + sizeof subsection_len;
2898 q = sub + subsection_len;
2899
2900 switch (subsection_tag)
2901 {
2902 default:
2903 printf (gettext (" %-4u %12" PRIu32 "\n"),
2904 subsection_tag, subsection_len);
2905 break;
2906
2907 case 1: /* Tag_File */
2908 printf (gettext (" File: %11" PRIu32 "\n"),
2909 subsection_len);
2910
2911 while (r < q)
2912 {
2913 unsigned int tag;
2914 get_uleb128 (tag, r);
2915 if (unlikely (r >= q))
2916 break;
2917
2918 uint64_t value = 0;
2919 const char *string = NULL;
2920 if (tag == 32 || (tag & 1) == 0)
2921 {
2922 get_uleb128 (value, r);
2923 if (r > q)
2924 break;
2925 }
2926 if (tag == 32 || (tag & 1) != 0)
2927 {
2928 r = memchr (r, '\0', q - r);
2929 if (r == NULL)
2930 break;
2931 ++r;
2932 }
2933
2934 const char *tag_name = NULL;
2935 const char *value_name = NULL;
2936 ebl_check_object_attribute (ebl, (const char *) name,
2937 tag, value,
2938 &tag_name, &value_name);
2939
2940 if (tag_name != NULL)
2941 {
2942 if (tag == 32)
2943 printf (gettext (" %s: %" PRId64 ", %s\n"),
2944 tag_name, value, string);
2945 else if (string == NULL && value_name == NULL)
2946 printf (gettext (" %s: %" PRId64 "\n"),
2947 tag_name, value);
2948 else
2949 printf (gettext (" %s: %s\n"),
2950 tag_name, string ?: value_name);
2951 }
2952 else
2953 {
2954 assert (tag != 32);
2955 if (string == NULL)
2956 printf (gettext (" %u: %" PRId64 "\n"),
2957 tag, value);
2958 else
2959 printf (gettext (" %u: %s\n"),
2960 tag, string);
2961 }
2962 }
2963 }
2964 }
2965 }
2966 }
2967}
2968
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00002969
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00002970static char *
2971format_dwarf_addr (Dwfl_Module *dwflmod,
2972 int address_size, Dwarf_Addr address)
2973{
2974 /* See if there is a name we can give for this address. */
2975 GElf_Sym sym;
2976 const char *name = dwfl_module_addrsym (dwflmod, address, &sym, NULL);
2977 if (name != NULL)
2978 sym.st_value = address - sym.st_value;
2979
2980 /* Relativize the address. */
2981 int n = dwfl_module_relocations (dwflmod);
2982 int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
2983
2984 /* In an ET_REL file there is a section name to refer to. */
2985 const char *scn = (i < 0 ? NULL
2986 : dwfl_module_relocation_info (dwflmod, i, NULL));
2987
2988 char *result;
2989 if ((name != NULL
2990 ? (sym.st_value != 0
2991 ? (scn != NULL
2992 ? (address_size == 0
2993 ? asprintf (&result,
2994 gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
2995 scn, address, name, sym.st_value)
2996 : asprintf (&result,
2997 gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
2998 scn, 2 + address_size * 2, address,
2999 name, sym.st_value))
3000 : (address_size == 0
3001 ? asprintf (&result,
3002 gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
3003 address, name, sym.st_value)
3004 : asprintf (&result,
3005 gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
3006 2 + address_size * 2, address,
3007 name, sym.st_value)))
3008 : (scn != NULL
3009 ? (address_size == 0
3010 ? asprintf (&result,
3011 gettext ("%s+%#" PRIx64 " <%s>"),
3012 scn, address, name)
3013 : asprintf (&result,
3014 gettext ("%s+%#0*" PRIx64 " <%s>"),
3015 scn, 2 + address_size * 2, address, name))
3016 : (address_size == 0
3017 ? asprintf (&result,
3018 gettext ("%#" PRIx64 " <%s>"),
3019 address, name)
3020 : asprintf (&result,
3021 gettext ("%#0*" PRIx64 " <%s>"),
3022 2 + address_size * 2, address, name))))
3023 : (scn != NULL
3024 ? (address_size == 0
3025 ? asprintf (&result,
3026 gettext ("%s+%#" PRIx64),
3027 scn, address)
3028 : asprintf (&result,
3029 gettext ("%s+%#0*" PRIx64),
3030 scn, 2 + address_size * 2, address))
3031 : (address_size == 0
3032 ? asprintf (&result,
3033 "%#" PRIx64,
3034 address)
3035 : asprintf (&result,
3036 "%#0*" PRIx64,
3037 2 + address_size * 2, address)))) < 0)
3038 error (EXIT_FAILURE, 0, _("memory exhausted"));
3039
3040 return result;
3041}
3042
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003043static const char *
3044dwarf_tag_string (unsigned int tag)
3045{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003046 static const char *const known_tags[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003047 {
3048 [DW_TAG_array_type] = "array_type",
3049 [DW_TAG_class_type] = "class_type",
3050 [DW_TAG_entry_point] = "entry_point",
3051 [DW_TAG_enumeration_type] = "enumeration_type",
3052 [DW_TAG_formal_parameter] = "formal_parameter",
3053 [DW_TAG_imported_declaration] = "imported_declaration",
3054 [DW_TAG_label] = "label",
3055 [DW_TAG_lexical_block] = "lexical_block",
3056 [DW_TAG_member] = "member",
3057 [DW_TAG_pointer_type] = "pointer_type",
3058 [DW_TAG_reference_type] = "reference_type",
3059 [DW_TAG_compile_unit] = "compile_unit",
3060 [DW_TAG_string_type] = "string_type",
3061 [DW_TAG_structure_type] = "structure_type",
3062 [DW_TAG_subroutine_type] = "subroutine_type",
3063 [DW_TAG_typedef] = "typedef",
3064 [DW_TAG_union_type] = "union_type",
3065 [DW_TAG_unspecified_parameters] = "unspecified_parameters",
3066 [DW_TAG_variant] = "variant",
3067 [DW_TAG_common_block] = "common_block",
3068 [DW_TAG_common_inclusion] = "common_inclusion",
3069 [DW_TAG_inheritance] = "inheritance",
3070 [DW_TAG_inlined_subroutine] = "inlined_subroutine",
3071 [DW_TAG_module] = "module",
3072 [DW_TAG_ptr_to_member_type] = "ptr_to_member_type",
3073 [DW_TAG_set_type] = "set_type",
3074 [DW_TAG_subrange_type] = "subrange_type",
3075 [DW_TAG_with_stmt] = "with_stmt",
3076 [DW_TAG_access_declaration] = "access_declaration",
3077 [DW_TAG_base_type] = "base_type",
3078 [DW_TAG_catch_block] = "catch_block",
3079 [DW_TAG_const_type] = "const_type",
3080 [DW_TAG_constant] = "constant",
3081 [DW_TAG_enumerator] = "enumerator",
3082 [DW_TAG_file_type] = "file_type",
3083 [DW_TAG_friend] = "friend",
3084 [DW_TAG_namelist] = "namelist",
3085 [DW_TAG_namelist_item] = "namelist_item",
3086 [DW_TAG_packed_type] = "packed_type",
3087 [DW_TAG_subprogram] = "subprogram",
Roland McGrath060fa052006-03-02 07:51:50 +00003088 [DW_TAG_template_type_parameter] = "template_type_parameter",
3089 [DW_TAG_template_value_parameter] = "template_value_parameter",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003090 [DW_TAG_thrown_type] = "thrown_type",
3091 [DW_TAG_try_block] = "try_block",
3092 [DW_TAG_variant_part] = "variant_part",
3093 [DW_TAG_variable] = "variable",
3094 [DW_TAG_volatile_type] = "volatile_type",
3095 [DW_TAG_dwarf_procedure] = "dwarf_procedure",
3096 [DW_TAG_restrict_type] = "restrict_type",
3097 [DW_TAG_interface_type] = "interface_type",
3098 [DW_TAG_namespace] = "namespace",
3099 [DW_TAG_imported_module] = "imported_module",
3100 [DW_TAG_unspecified_type] = "unspecified_type",
3101 [DW_TAG_partial_unit] = "partial_unit",
3102 [DW_TAG_imported_unit] = "imported_unit",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003103 [DW_TAG_mutable_type] = "mutable_type",
Roland McGrath060fa052006-03-02 07:51:50 +00003104 [DW_TAG_condition] = "condition",
3105 [DW_TAG_shared_type] = "shared_type",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003106 };
3107 const unsigned int nknown_tags = (sizeof (known_tags)
3108 / sizeof (known_tags[0]));
3109 static char buf[40];
3110 const char *result = NULL;
3111
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003112 if (likely (tag < nknown_tags))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003113 result = known_tags[tag];
3114
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003115 if (unlikely (result == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003116 /* There are a few known extensions. */
3117 switch (tag)
3118 {
3119 case DW_TAG_MIPS_loop:
3120 result = "MIPS_loop";
3121 break;
3122
3123 case DW_TAG_format_label:
3124 result = "format_label";
3125 break;
3126
3127 case DW_TAG_function_template:
3128 result = "function_template";
3129 break;
3130
3131 case DW_TAG_class_template:
3132 result = "class_template";
3133 break;
3134
3135 default:
3136 if (tag < DW_TAG_lo_user)
3137 snprintf (buf, sizeof buf, gettext ("unknown tag %hx"), tag);
3138 else
3139 snprintf (buf, sizeof buf, gettext ("unknown user tag %hx"), tag);
3140 result = buf;
3141 break;
3142 }
3143
3144 return result;
3145}
3146
3147
3148static const char *
3149dwarf_attr_string (unsigned int attrnum)
3150{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003151 static const char *const known_attrs[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003152 {
3153 [DW_AT_sibling] = "sibling",
3154 [DW_AT_location] = "location",
3155 [DW_AT_name] = "name",
3156 [DW_AT_ordering] = "ordering",
3157 [DW_AT_subscr_data] = "subscr_data",
3158 [DW_AT_byte_size] = "byte_size",
3159 [DW_AT_bit_offset] = "bit_offset",
3160 [DW_AT_bit_size] = "bit_size",
3161 [DW_AT_element_list] = "element_list",
3162 [DW_AT_stmt_list] = "stmt_list",
3163 [DW_AT_low_pc] = "low_pc",
3164 [DW_AT_high_pc] = "high_pc",
3165 [DW_AT_language] = "language",
3166 [DW_AT_member] = "member",
3167 [DW_AT_discr] = "discr",
3168 [DW_AT_discr_value] = "discr_value",
3169 [DW_AT_visibility] = "visibility",
3170 [DW_AT_import] = "import",
3171 [DW_AT_string_length] = "string_length",
3172 [DW_AT_common_reference] = "common_reference",
3173 [DW_AT_comp_dir] = "comp_dir",
3174 [DW_AT_const_value] = "const_value",
3175 [DW_AT_containing_type] = "containing_type",
3176 [DW_AT_default_value] = "default_value",
3177 [DW_AT_inline] = "inline",
3178 [DW_AT_is_optional] = "is_optional",
3179 [DW_AT_lower_bound] = "lower_bound",
3180 [DW_AT_producer] = "producer",
3181 [DW_AT_prototyped] = "prototyped",
3182 [DW_AT_return_addr] = "return_addr",
3183 [DW_AT_start_scope] = "start_scope",
Roland McGrath060fa052006-03-02 07:51:50 +00003184 [DW_AT_bit_stride] = "bit_stride",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003185 [DW_AT_upper_bound] = "upper_bound",
3186 [DW_AT_abstract_origin] = "abstract_origin",
3187 [DW_AT_accessibility] = "accessibility",
3188 [DW_AT_address_class] = "address_class",
3189 [DW_AT_artificial] = "artificial",
3190 [DW_AT_base_types] = "base_types",
3191 [DW_AT_calling_convention] = "calling_convention",
3192 [DW_AT_count] = "count",
3193 [DW_AT_data_member_location] = "data_member_location",
3194 [DW_AT_decl_column] = "decl_column",
3195 [DW_AT_decl_file] = "decl_file",
3196 [DW_AT_decl_line] = "decl_line",
3197 [DW_AT_declaration] = "declaration",
3198 [DW_AT_discr_list] = "discr_list",
3199 [DW_AT_encoding] = "encoding",
3200 [DW_AT_external] = "external",
3201 [DW_AT_frame_base] = "frame_base",
3202 [DW_AT_friend] = "friend",
3203 [DW_AT_identifier_case] = "identifier_case",
3204 [DW_AT_macro_info] = "macro_info",
Roland McGrath060fa052006-03-02 07:51:50 +00003205 [DW_AT_namelist_item] = "namelist_item",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003206 [DW_AT_priority] = "priority",
3207 [DW_AT_segment] = "segment",
3208 [DW_AT_specification] = "specification",
3209 [DW_AT_static_link] = "static_link",
3210 [DW_AT_type] = "type",
3211 [DW_AT_use_location] = "use_location",
3212 [DW_AT_variable_parameter] = "variable_parameter",
3213 [DW_AT_virtuality] = "virtuality",
3214 [DW_AT_vtable_elem_location] = "vtable_elem_location",
3215 [DW_AT_allocated] = "allocated",
3216 [DW_AT_associated] = "associated",
3217 [DW_AT_data_location] = "data_location",
Roland McGrath060fa052006-03-02 07:51:50 +00003218 [DW_AT_byte_stride] = "byte_stride",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003219 [DW_AT_entry_pc] = "entry_pc",
3220 [DW_AT_use_UTF8] = "use_UTF8",
3221 [DW_AT_extension] = "extension",
3222 [DW_AT_ranges] = "ranges",
3223 [DW_AT_trampoline] = "trampoline",
3224 [DW_AT_call_column] = "call_column",
3225 [DW_AT_call_file] = "call_file",
3226 [DW_AT_call_line] = "call_line",
Roland McGrath060fa052006-03-02 07:51:50 +00003227 [DW_AT_description] = "description",
3228 [DW_AT_binary_scale] = "binary_scale",
3229 [DW_AT_decimal_scale] = "decimal_scale",
3230 [DW_AT_small] = "small",
3231 [DW_AT_decimal_sign] = "decimal_sign",
3232 [DW_AT_digit_count] = "digit_count",
3233 [DW_AT_picture_string] = "picture_string",
3234 [DW_AT_mutable] = "mutable",
3235 [DW_AT_threads_scaled] = "threads_scaled",
3236 [DW_AT_explicit] = "explicit",
3237 [DW_AT_object_pointer] = "object_pointer",
3238 [DW_AT_endianity] = "endianity",
3239 [DW_AT_elemental] = "elemental",
3240 [DW_AT_pure] = "pure",
3241 [DW_AT_recursive] = "recursive",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003242 };
3243 const unsigned int nknown_attrs = (sizeof (known_attrs)
3244 / sizeof (known_attrs[0]));
3245 static char buf[40];
3246 const char *result = NULL;
3247
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003248 if (likely (attrnum < nknown_attrs))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003249 result = known_attrs[attrnum];
3250
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003251 if (unlikely (result == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003252 /* There are a few known extensions. */
3253 switch (attrnum)
3254 {
3255 case DW_AT_MIPS_fde:
3256 result = "MIPS_fde";
3257 break;
3258
3259 case DW_AT_MIPS_loop_begin:
3260 result = "MIPS_loop_begin";
3261 break;
3262
3263 case DW_AT_MIPS_tail_loop_begin:
3264 result = "MIPS_tail_loop_begin";
3265 break;
3266
3267 case DW_AT_MIPS_epilog_begin:
3268 result = "MIPS_epilog_begin";
3269 break;
3270
3271 case DW_AT_MIPS_loop_unroll_factor:
3272 result = "MIPS_loop_unroll_factor";
3273 break;
3274
3275 case DW_AT_MIPS_software_pipeline_depth:
3276 result = "MIPS_software_pipeline_depth";
3277 break;
3278
3279 case DW_AT_MIPS_linkage_name:
3280 result = "MIPS_linkage_name";
3281 break;
3282
3283 case DW_AT_MIPS_stride:
3284 result = "MIPS_stride";
3285 break;
3286
3287 case DW_AT_MIPS_abstract_name:
3288 result = "MIPS_abstract_name";
3289 break;
3290
3291 case DW_AT_MIPS_clone_origin:
3292 result = "MIPS_clone_origin";
3293 break;
3294
3295 case DW_AT_MIPS_has_inlines:
3296 result = "MIPS_has_inlines";
3297 break;
3298
3299 case DW_AT_MIPS_stride_byte:
3300 result = "MIPS_stride_byte";
3301 break;
3302
3303 case DW_AT_MIPS_stride_elem:
3304 result = "MIPS_stride_elem";
3305 break;
3306
3307 case DW_AT_MIPS_ptr_dopetype:
3308 result = "MIPS_ptr_dopetype";
3309 break;
3310
3311 case DW_AT_MIPS_allocatable_dopetype:
3312 result = "MIPS_allocatable_dopetype";
3313 break;
3314
3315 case DW_AT_MIPS_assumed_shape_dopetype:
3316 result = "MIPS_assumed_shape_dopetype";
3317 break;
3318
3319 case DW_AT_MIPS_assumed_size:
3320 result = "MIPS_assumed_size";
3321 break;
3322
3323 case DW_AT_sf_names:
3324 result = "sf_names";
3325 break;
3326
3327 case DW_AT_src_info:
3328 result = "src_info";
3329 break;
3330
3331 case DW_AT_mac_info:
3332 result = "mac_info";
3333 break;
3334
3335 case DW_AT_src_coords:
3336 result = "src_coords";
3337 break;
3338
3339 case DW_AT_body_begin:
3340 result = "body_begin";
3341 break;
3342
3343 case DW_AT_body_end:
3344 result = "body_end";
3345 break;
3346
3347 default:
3348 if (attrnum < DW_AT_lo_user)
3349 snprintf (buf, sizeof buf, gettext ("unknown attribute %hx"),
3350 attrnum);
3351 else
3352 snprintf (buf, sizeof buf, gettext ("unknown user attribute %hx"),
3353 attrnum);
3354 result = buf;
3355 break;
3356 }
3357
3358 return result;
3359}
3360
3361
3362static const char *
3363dwarf_form_string (unsigned int form)
3364{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003365 static const char *const known_forms[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003366 {
3367 [DW_FORM_addr] = "addr",
3368 [DW_FORM_block2] = "block2",
3369 [DW_FORM_block4] = "block4",
3370 [DW_FORM_data2] = "data2",
3371 [DW_FORM_data4] = "data4",
3372 [DW_FORM_data8] = "data8",
3373 [DW_FORM_string] = "string",
3374 [DW_FORM_block] = "block",
3375 [DW_FORM_block1] = "block1",
3376 [DW_FORM_data1] = "data1",
3377 [DW_FORM_flag] = "flag",
3378 [DW_FORM_sdata] = "sdata",
3379 [DW_FORM_strp] = "strp",
3380 [DW_FORM_udata] = "udata",
3381 [DW_FORM_ref_addr] = "ref_addr",
3382 [DW_FORM_ref1] = "ref1",
3383 [DW_FORM_ref2] = "ref2",
3384 [DW_FORM_ref4] = "ref4",
3385 [DW_FORM_ref8] = "ref8",
3386 [DW_FORM_ref_udata] = "ref_udata",
3387 [DW_FORM_indirect] = "indirect"
3388 };
3389 const unsigned int nknown_forms = (sizeof (known_forms)
3390 / sizeof (known_forms[0]));
3391 static char buf[40];
3392 const char *result = NULL;
3393
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003394 if (likely (form < nknown_forms))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003395 result = known_forms[form];
3396
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003397 if (unlikely (result == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003398 snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64),
3399 (uint64_t) form);
3400
3401 return result;
3402}
3403
3404
3405static const char *
3406dwarf_lang_string (unsigned int lang)
3407{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003408 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003409 {
3410 [DW_LANG_C89] = "ISO C89",
3411 [DW_LANG_C] = "C",
3412 [DW_LANG_Ada83] = "Ada83",
Roland McGrath060fa052006-03-02 07:51:50 +00003413 [DW_LANG_C_plus_plus] = "C++",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003414 [DW_LANG_Cobol74] = "Cobol74",
3415 [DW_LANG_Cobol85] = "Cobol85",
3416 [DW_LANG_Fortran77] = "Fortran77",
3417 [DW_LANG_Fortran90] = "Fortran90",
3418 [DW_LANG_Pascal83] = "Pascal83",
3419 [DW_LANG_Modula2] = "Modula2",
3420 [DW_LANG_Java] = "Java",
3421 [DW_LANG_C99] = "ISO C99",
3422 [DW_LANG_Ada95] = "Ada95",
3423 [DW_LANG_Fortran95] = "Fortran95",
Roland McGrath060fa052006-03-02 07:51:50 +00003424 [DW_LANG_PL1] = "PL1",
3425 [DW_LANG_Objc] = "Objective C",
3426 [DW_LANG_ObjC_plus_plus] = "Objective C++",
3427 [DW_LANG_UPC] = "UPC",
3428 [DW_LANG_D] = "D",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003429 };
3430
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003431 if (likely (lang < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003432 return known[lang];
3433 else if (lang == DW_LANG_Mips_Assembler)
3434 /* This language tag is used for assembler in general. */
3435 return "Assembler";
3436
3437 if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user)
3438 {
3439 static char buf[30];
3440 snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user);
3441 return buf;
3442 }
3443
3444 return "???";
3445}
3446
3447
3448static const char *
3449dwarf_inline_string (unsigned int code)
3450{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003451 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003452 {
3453 [DW_INL_not_inlined] = "not_inlined",
3454 [DW_INL_inlined] = "inlined",
3455 [DW_INL_declared_not_inlined] = "declared_not_inlined",
3456 [DW_INL_declared_inlined] = "declared_inlined"
3457 };
3458
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003459 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003460 return known[code];
3461
3462 return "???";
3463}
3464
3465
3466static const char *
3467dwarf_encoding_string (unsigned int code)
3468{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003469 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003470 {
3471 [DW_ATE_void] = "void",
3472 [DW_ATE_address] = "address",
3473 [DW_ATE_boolean] = "boolean",
3474 [DW_ATE_complex_float] = "complex_float",
3475 [DW_ATE_float] = "float",
3476 [DW_ATE_signed] = "signed",
3477 [DW_ATE_signed_char] = "signed_char",
3478 [DW_ATE_unsigned] = "unsigned",
3479 [DW_ATE_unsigned_char] = "unsigned_char",
Roland McGrath060fa052006-03-02 07:51:50 +00003480 [DW_ATE_imaginary_float] = "imaginary_float",
3481 [DW_ATE_packed_decimal] = "packed_decimal",
3482 [DW_ATE_numeric_string] = "numeric_string",
3483 [DW_ATE_edited] = "edited",
3484 [DW_ATE_signed_fixed] = "signed_fixed",
3485 [DW_ATE_unsigned_fixed] = "unsigned_fixed",
3486 [DW_ATE_decimal_float] = "decimal_float",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003487 };
3488
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003489 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003490 return known[code];
3491
3492 if (code >= DW_ATE_lo_user && code <= DW_ATE_hi_user)
3493 {
3494 static char buf[30];
3495 snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_ATE_lo_user);
3496 return buf;
3497 }
3498
3499 return "???";
3500}
3501
3502
3503static const char *
3504dwarf_access_string (unsigned int code)
3505{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003506 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003507 {
3508 [DW_ACCESS_public] = "public",
3509 [DW_ACCESS_protected] = "protected",
3510 [DW_ACCESS_private] = "private"
3511 };
3512
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003513 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003514 return known[code];
3515
3516 return "???";
3517}
3518
3519
3520static const char *
3521dwarf_visibility_string (unsigned int code)
3522{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003523 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003524 {
3525 [DW_VIS_local] = "local",
3526 [DW_VIS_exported] = "exported",
3527 [DW_VIS_qualified] = "qualified"
3528 };
3529
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003530 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003531 return known[code];
3532
3533 return "???";
3534}
3535
3536
3537static const char *
3538dwarf_virtuality_string (unsigned int code)
3539{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003540 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003541 {
3542 [DW_VIRTUALITY_none] = "none",
3543 [DW_VIRTUALITY_virtual] = "virtual",
3544 [DW_VIRTUALITY_pure_virtual] = "pure_virtual"
3545 };
3546
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003547 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003548 return known[code];
3549
3550 return "???";
3551}
3552
3553
3554static const char *
3555dwarf_identifier_case_string (unsigned int code)
3556{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003557 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003558 {
3559 [DW_ID_case_sensitive] = "sensitive",
3560 [DW_ID_up_case] = "up_case",
3561 [DW_ID_down_case] = "down_case",
3562 [DW_ID_case_insensitive] = "insensitive"
3563 };
3564
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003565 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003566 return known[code];
3567
3568 return "???";
3569}
3570
3571
3572static const char *
3573dwarf_calling_convention_string (unsigned int code)
3574{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003575 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003576 {
3577 [DW_CC_normal] = "normal",
3578 [DW_CC_program] = "program",
3579 [DW_CC_nocall] = "nocall",
3580 };
3581
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003582 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003583 return known[code];
3584
3585 if (code >= DW_CC_lo_user && code <= DW_CC_hi_user)
3586 {
3587 static char buf[30];
3588 snprintf (buf, sizeof (buf), "lo_user+%u", code - DW_CC_lo_user);
3589 return buf;
3590 }
3591
3592 return "???";
3593}
3594
3595
3596static const char *
3597dwarf_ordering_string (unsigned int code)
3598{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003599 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003600 {
3601 [DW_ORD_row_major] = "row_major",
3602 [DW_ORD_col_major] = "col_major"
3603 };
3604
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003605 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003606 return known[code];
3607
3608 return "???";
3609}
3610
3611
3612static const char *
3613dwarf_discr_list_string (unsigned int code)
3614{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003615 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003616 {
3617 [DW_DSC_label] = "label",
3618 [DW_DSC_range] = "range"
3619 };
3620
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00003621 if (likely (code < sizeof (known) / sizeof (known[0])))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003622 return known[code];
3623
3624 return "???";
3625}
3626
3627
3628static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00003629print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003630 unsigned int addrsize, Dwarf_Word len, const unsigned char *data)
3631{
Ulrich Drepper8b383102007-02-16 00:31:57 +00003632 static const char *const known[] =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003633 {
3634 [DW_OP_addr] = "addr",
3635 [DW_OP_deref] = "deref",
3636 [DW_OP_const1u] = "const1u",
3637 [DW_OP_const1s] = "const1s",
3638 [DW_OP_const2u] = "const2u",
3639 [DW_OP_const2s] = "const2s",
3640 [DW_OP_const4u] = "const4u",
3641 [DW_OP_const4s] = "const4s",
3642 [DW_OP_const8u] = "const8u",
3643 [DW_OP_const8s] = "const8s",
3644 [DW_OP_constu] = "constu",
3645 [DW_OP_consts] = "consts",
3646 [DW_OP_dup] = "dup",
3647 [DW_OP_drop] = "drop",
3648 [DW_OP_over] = "over",
3649 [DW_OP_pick] = "pick",
3650 [DW_OP_swap] = "swap",
3651 [DW_OP_rot] = "rot",
3652 [DW_OP_xderef] = "xderef",
3653 [DW_OP_abs] = "abs",
3654 [DW_OP_and] = "and",
3655 [DW_OP_div] = "div",
3656 [DW_OP_minus] = "minus",
3657 [DW_OP_mod] = "mod",
3658 [DW_OP_mul] = "mul",
3659 [DW_OP_neg] = "neg",
3660 [DW_OP_not] = "not",
3661 [DW_OP_or] = "or",
3662 [DW_OP_plus] = "plus",
3663 [DW_OP_plus_uconst] = "plus_uconst",
3664 [DW_OP_shl] = "shl",
3665 [DW_OP_shr] = "shr",
3666 [DW_OP_shra] = "shra",
3667 [DW_OP_xor] = "xor",
3668 [DW_OP_bra] = "bra",
3669 [DW_OP_eq] = "eq",
3670 [DW_OP_ge] = "ge",
3671 [DW_OP_gt] = "gt",
3672 [DW_OP_le] = "le",
3673 [DW_OP_lt] = "lt",
3674 [DW_OP_ne] = "ne",
3675 [DW_OP_skip] = "skip",
3676 [DW_OP_lit0] = "lit0",
3677 [DW_OP_lit1] = "lit1",
3678 [DW_OP_lit2] = "lit2",
3679 [DW_OP_lit3] = "lit3",
3680 [DW_OP_lit4] = "lit4",
3681 [DW_OP_lit5] = "lit5",
3682 [DW_OP_lit6] = "lit6",
3683 [DW_OP_lit7] = "lit7",
3684 [DW_OP_lit8] = "lit8",
3685 [DW_OP_lit9] = "lit9",
3686 [DW_OP_lit10] = "lit10",
3687 [DW_OP_lit11] = "lit11",
3688 [DW_OP_lit12] = "lit12",
3689 [DW_OP_lit13] = "lit13",
3690 [DW_OP_lit14] = "lit14",
3691 [DW_OP_lit15] = "lit15",
3692 [DW_OP_lit16] = "lit16",
3693 [DW_OP_lit17] = "lit17",
3694 [DW_OP_lit18] = "lit18",
3695 [DW_OP_lit19] = "lit19",
3696 [DW_OP_lit20] = "lit20",
3697 [DW_OP_lit21] = "lit21",
3698 [DW_OP_lit22] = "lit22",
3699 [DW_OP_lit23] = "lit23",
3700 [DW_OP_lit24] = "lit24",
3701 [DW_OP_lit25] = "lit25",
3702 [DW_OP_lit26] = "lit26",
3703 [DW_OP_lit27] = "lit27",
3704 [DW_OP_lit28] = "lit28",
3705 [DW_OP_lit29] = "lit29",
3706 [DW_OP_lit30] = "lit30",
3707 [DW_OP_lit31] = "lit31",
3708 [DW_OP_reg0] = "reg0",
3709 [DW_OP_reg1] = "reg1",
3710 [DW_OP_reg2] = "reg2",
3711 [DW_OP_reg3] = "reg3",
3712 [DW_OP_reg4] = "reg4",
3713 [DW_OP_reg5] = "reg5",
3714 [DW_OP_reg6] = "reg6",
3715 [DW_OP_reg7] = "reg7",
3716 [DW_OP_reg8] = "reg8",
3717 [DW_OP_reg9] = "reg9",
3718 [DW_OP_reg10] = "reg10",
3719 [DW_OP_reg11] = "reg11",
3720 [DW_OP_reg12] = "reg12",
3721 [DW_OP_reg13] = "reg13",
3722 [DW_OP_reg14] = "reg14",
3723 [DW_OP_reg15] = "reg15",
3724 [DW_OP_reg16] = "reg16",
3725 [DW_OP_reg17] = "reg17",
3726 [DW_OP_reg18] = "reg18",
3727 [DW_OP_reg19] = "reg19",
3728 [DW_OP_reg20] = "reg20",
3729 [DW_OP_reg21] = "reg21",
3730 [DW_OP_reg22] = "reg22",
3731 [DW_OP_reg23] = "reg23",
3732 [DW_OP_reg24] = "reg24",
3733 [DW_OP_reg25] = "reg25",
3734 [DW_OP_reg26] = "reg26",
3735 [DW_OP_reg27] = "reg27",
3736 [DW_OP_reg28] = "reg28",
3737 [DW_OP_reg29] = "reg29",
3738 [DW_OP_reg30] = "reg30",
3739 [DW_OP_reg31] = "reg31",
3740 [DW_OP_breg0] = "breg0",
3741 [DW_OP_breg1] = "breg1",
3742 [DW_OP_breg2] = "breg2",
3743 [DW_OP_breg3] = "breg3",
3744 [DW_OP_breg4] = "breg4",
3745 [DW_OP_breg5] = "breg5",
3746 [DW_OP_breg6] = "breg6",
3747 [DW_OP_breg7] = "breg7",
3748 [DW_OP_breg8] = "breg8",
3749 [DW_OP_breg9] = "breg9",
3750 [DW_OP_breg10] = "breg10",
3751 [DW_OP_breg11] = "breg11",
3752 [DW_OP_breg12] = "breg12",
3753 [DW_OP_breg13] = "breg13",
3754 [DW_OP_breg14] = "breg14",
3755 [DW_OP_breg15] = "breg15",
3756 [DW_OP_breg16] = "breg16",
3757 [DW_OP_breg17] = "breg17",
3758 [DW_OP_breg18] = "breg18",
3759 [DW_OP_breg19] = "breg19",
3760 [DW_OP_breg20] = "breg20",
3761 [DW_OP_breg21] = "breg21",
3762 [DW_OP_breg22] = "breg22",
3763 [DW_OP_breg23] = "breg23",
3764 [DW_OP_breg24] = "breg24",
3765 [DW_OP_breg25] = "breg25",
3766 [DW_OP_breg26] = "breg26",
3767 [DW_OP_breg27] = "breg27",
3768 [DW_OP_breg28] = "breg28",
3769 [DW_OP_breg29] = "breg29",
3770 [DW_OP_breg30] = "breg30",
3771 [DW_OP_breg31] = "breg31",
3772 [DW_OP_regx] = "regx",
3773 [DW_OP_fbreg] = "fbreg",
3774 [DW_OP_bregx] = "bregx",
3775 [DW_OP_piece] = "piece",
3776 [DW_OP_deref_size] = "deref_size",
3777 [DW_OP_xderef_size] = "xderef_size",
3778 [DW_OP_nop] = "nop",
3779 [DW_OP_push_object_address] = "push_object_address",
3780 [DW_OP_call2] = "call2",
3781 [DW_OP_call4] = "call4",
3782 [DW_OP_call_ref] = "call_ref",
Roland McGrath060fa052006-03-02 07:51:50 +00003783 [DW_OP_form_tls_address] = "form_tls_address",
3784 [DW_OP_call_frame_cfa] = "call_frame_cfa",
3785 [DW_OP_bit_piece] = "bit_piece",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003786 };
3787
Roland McGrath51f01282009-01-27 17:08:03 -08003788 if (len == 0)
3789 {
3790 printf ("%*s(empty)\n", indent, "");
3791 return;
3792 }
3793
3794#define NEED(n) if (len < n) goto invalid;
3795
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003796 Dwarf_Word offset = 0;
3797 while (len-- > 0)
3798 {
Roland McGrath1a2e8f42007-12-15 23:39:34 +00003799 uint_fast8_t op = *data++;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003800
3801 switch (op)
3802 {
3803 case DW_OP_call_ref:
3804 case DW_OP_addr:;
3805 /* Address operand. */
3806 Dwarf_Word addr;
Roland McGrath51f01282009-01-27 17:08:03 -08003807 NEED (addrsize);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003808 if (addrsize == 4)
3809 addr = read_4ubyte_unaligned (dbg, data);
3810 else
3811 {
3812 assert (addrsize == 8);
3813 addr = read_8ubyte_unaligned (dbg, data);
3814 }
3815 data += addrsize;
3816 len -= addrsize;
3817
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00003818 if (op == DW_OP_addr)
3819 {
3820 char *a = format_dwarf_addr (dwflmod, 0, addr);
3821 printf ("%*s[%4" PRIuMAX "] %s %s\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003822 indent, "", (uintmax_t) offset, known[op], a);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00003823 free (a);
3824 }
3825 else
3826 printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
3827 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003828 known[op], (uintmax_t) addr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003829 offset += 1 + addrsize;
3830 break;
3831
Roland McGrath060fa052006-03-02 07:51:50 +00003832 case DW_OP_deref_size:
3833 case DW_OP_xderef_size:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003834 case DW_OP_pick:
3835 case DW_OP_const1u:
Ulrich Drepperac194d02009-01-06 00:30:01 -08003836 // XXX value might be modified by relocation
Roland McGrath51f01282009-01-27 17:08:03 -08003837 NEED (1);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003838 printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
3839 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003840 known[op], *((uint8_t *) data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003841 ++data;
3842 --len;
3843 offset += 2;
3844 break;
3845
3846 case DW_OP_const2u:
Roland McGrath51f01282009-01-27 17:08:03 -08003847 NEED (2);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003848 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003849 printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
3850 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003851 known[op], read_2ubyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003852 len -= 2;
3853 data += 2;
3854 offset += 3;
3855 break;
3856
3857 case DW_OP_const4u:
Roland McGrath51f01282009-01-27 17:08:03 -08003858 NEED (4);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003859 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003860 printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
3861 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003862 known[op], read_4ubyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003863 len -= 4;
3864 data += 4;
3865 offset += 5;
3866 break;
3867
3868 case DW_OP_const8u:
Roland McGrath51f01282009-01-27 17:08:03 -08003869 NEED (8);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003870 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003871 printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
3872 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003873 known[op], read_8ubyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003874 len -= 8;
3875 data += 8;
3876 offset += 9;
3877 break;
3878
3879 case DW_OP_const1s:
Roland McGrath51f01282009-01-27 17:08:03 -08003880 NEED (1);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003881 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003882 printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
3883 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003884 known[op], *((int8_t *) data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003885 ++data;
3886 --len;
3887 offset += 2;
3888 break;
3889
3890 case DW_OP_const2s:
Roland McGrath51f01282009-01-27 17:08:03 -08003891 NEED (2);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003892 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003893 printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
3894 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003895 known[op], read_2sbyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003896 len -= 2;
3897 data += 2;
3898 offset += 3;
3899 break;
3900
3901 case DW_OP_const4s:
Roland McGrath51f01282009-01-27 17:08:03 -08003902 NEED (4);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003903 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003904 printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
3905 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003906 known[op], read_4sbyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003907 len -= 4;
3908 data += 4;
3909 offset += 5;
3910 break;
3911
3912 case DW_OP_const8s:
Roland McGrath51f01282009-01-27 17:08:03 -08003913 NEED (8);
Ulrich Drepperac194d02009-01-06 00:30:01 -08003914 // XXX value might be modified by relocation
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003915 printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
3916 indent, "", (uintmax_t) offset,
Ulrich Drepperac194d02009-01-06 00:30:01 -08003917 known[op], read_8sbyte_unaligned (dbg, data));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003918 len -= 8;
3919 data += 8;
3920 offset += 9;
3921 break;
3922
Roland McGrath060fa052006-03-02 07:51:50 +00003923 case DW_OP_piece:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003924 case DW_OP_regx:
3925 case DW_OP_plus_uconst:
3926 case DW_OP_constu:;
3927 const unsigned char *start = data;
3928 unsigned int uleb;
Roland McGrath51f01282009-01-27 17:08:03 -08003929 get_uleb128 (uleb, data); /* XXX check overrun */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003930 printf ("%*s[%4" PRIuMAX "] %s %u\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003931 indent, "", (uintmax_t) offset, known[op], uleb);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003932 len -= data - start;
3933 offset += 1 + (data - start);
3934 break;
3935
Roland McGrath060fa052006-03-02 07:51:50 +00003936 case DW_OP_bit_piece:
3937 start = data;
3938 unsigned int uleb2;
Roland McGrath51f01282009-01-27 17:08:03 -08003939 get_uleb128 (uleb, data); /* XXX check overrun */
3940 get_uleb128 (uleb2, data); /* XXX check overrun */
Roland McGrath060fa052006-03-02 07:51:50 +00003941 printf ("%*s[%4" PRIuMAX "] %s %u, %u\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003942 indent, "", (uintmax_t) offset, known[op], uleb, uleb2);
Roland McGrath060fa052006-03-02 07:51:50 +00003943 len -= data - start;
3944 offset += 1 + (data - start);
3945 break;
3946
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003947 case DW_OP_fbreg:
3948 case DW_OP_breg0 ... DW_OP_breg31:
3949 case DW_OP_consts:
3950 start = data;
3951 unsigned int sleb;
Roland McGrath51f01282009-01-27 17:08:03 -08003952 get_sleb128 (sleb, data); /* XXX check overrun */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003953 printf ("%*s[%4" PRIuMAX "] %s %d\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003954 indent, "", (uintmax_t) offset, known[op], sleb);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003955 len -= data - start;
3956 offset += 1 + (data - start);
3957 break;
3958
3959 case DW_OP_bregx:
3960 start = data;
Roland McGrath51f01282009-01-27 17:08:03 -08003961 get_uleb128 (uleb, data); /* XXX check overrun */
3962 get_sleb128 (sleb, data); /* XXX check overrun */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003963 printf ("%*s[%4" PRIuMAX "] %s %u %d\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003964 indent, "", (uintmax_t) offset, known[op], uleb, sleb);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003965 len -= data - start;
3966 offset += 1 + (data - start);
3967 break;
3968
3969 case DW_OP_call2:
Roland McGrath51f01282009-01-27 17:08:03 -08003970 NEED (2);
3971 printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
3972 indent, "", (uintmax_t) offset, known[op],
3973 read_2ubyte_unaligned (dbg, data));
3974 len -= 2;
3975 offset += 3;
3976 break;
3977
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003978 case DW_OP_call4:
Roland McGrath51f01282009-01-27 17:08:03 -08003979 NEED (4);
3980 printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
3981 indent, "", (uintmax_t) offset, known[op],
3982 read_4ubyte_unaligned (dbg, data));
3983 len -= 4;
3984 offset += 5;
3985 break;
3986
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003987 case DW_OP_skip:
3988 case DW_OP_bra:
Roland McGrath51f01282009-01-27 17:08:03 -08003989 NEED (2);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003990 printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
Ulrich Drepperac194d02009-01-06 00:30:01 -08003991 indent, "", (uintmax_t) offset, known[op],
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00003992 (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data)));
3993 len -= 2;
3994 data += 2;
3995 offset += 3;
3996 break;
3997
3998 default:
3999 /* No Operand. */
Roland McGrath1a2e8f42007-12-15 23:39:34 +00004000 if (op < sizeof known / sizeof known[0] && known[op] != NULL)
4001 printf ("%*s[%4" PRIuMAX "] %s\n",
4002 indent, "", (uintmax_t) offset, known[op]);
4003 else
4004 printf ("%*s[%4" PRIuMAX "] %#x\n",
4005 indent, "", (uintmax_t) offset, op);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004006 ++offset;
4007 break;
4008 }
4009
4010 indent = indentrest;
Roland McGrath51f01282009-01-27 17:08:03 -08004011 continue;
4012
4013 invalid:
4014 printf (gettext ("%*s[%4" PRIuMAX "] %s <TRUNCATED>\n"),
4015 indent, "", (uintmax_t) offset, known[op]);
4016 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004017 }
4018}
4019
4020
4021static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004022print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4023 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004024 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepper351bf202009-01-15 20:18:40 -08004025 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004026{
Ulrich Drepper351bf202009-01-15 20:18:40 -08004027 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004028 " [ Code]\n"),
Ulrich Drepper351bf202009-01-15 20:18:40 -08004029 elf_ndxscn (scn), ".debug_abbrev", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004030
4031 Dwarf_Off offset = 0;
4032 while (offset < shdr->sh_size)
4033 {
4034 printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
4035 offset);
4036
4037 while (1)
4038 {
4039 size_t length;
4040 Dwarf_Abbrev abbrev;
4041
4042 int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
4043 if (res != 0)
4044 {
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004045 if (unlikely (res < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004046 {
4047 printf (gettext ("\
4048 *** error while reading abbreviation: %s\n"),
4049 dwarf_errmsg (-1));
4050 return;
4051 }
4052
4053 /* This is the NUL byte at the end of the section. */
4054 ++offset;
4055 break;
4056 }
4057
4058 /* We know these calls can never fail. */
4059 unsigned int code = dwarf_getabbrevcode (&abbrev);
4060 unsigned int tag = dwarf_getabbrevtag (&abbrev);
4061 int has_children = dwarf_abbrevhaschildren (&abbrev);
4062
4063 printf (gettext (" [%5u] offset: %" PRId64
4064 ", children: %s, tag: %s\n"),
4065 code, (int64_t) offset,
4066 has_children ? gettext ("yes") : gettext ("no"),
4067 dwarf_tag_string (tag));
4068
4069 size_t cnt = 0;
4070 unsigned int name;
4071 unsigned int form;
4072 Dwarf_Off enoffset;
4073 while (dwarf_getabbrevattr (&abbrev, cnt,
4074 &name, &form, &enoffset) == 0)
4075 {
4076 printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n",
4077 dwarf_attr_string (name), dwarf_form_string (form),
4078 (uint64_t) enoffset);
4079
4080 ++cnt;
4081 }
4082
4083 offset += length;
4084 }
4085 }
4086}
4087
4088
4089/* Print content of DWARF .debug_aranges section. We fortunately do
4090 not have to know a bit about the structure of the section, libdwarf
4091 takes care of it. */
4092static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004093print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
4094 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepper351bf202009-01-15 20:18:40 -08004095 GElf_Ehdr *ehdr, Elf_Scn *scn,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004096 GElf_Shdr *shdr, Dwarf *dbg)
4097{
4098 Dwarf_Aranges *aranges;
4099 size_t cnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004100 if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004101 {
4102 error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
4103 dwarf_errmsg (-1));
4104 return;
4105 }
4106
4107 printf (ngettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08004108\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004109 "\
Ulrich Drepper351bf202009-01-15 20:18:40 -08004110\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004111 cnt),
Ulrich Drepper351bf202009-01-15 20:18:40 -08004112 elf_ndxscn (scn), ".debug_aranges", (uint64_t) shdr->sh_offset, cnt);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004113
4114 /* Compute floor(log16(cnt)). */
4115 size_t tmp = cnt;
4116 int digits = 1;
4117 while (tmp >= 16)
4118 {
4119 ++digits;
4120 tmp >>= 4;
4121 }
4122
4123 for (size_t n = 0; n < cnt; ++n)
4124 {
4125 Dwarf_Arange *runp = dwarf_onearange (aranges, n);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004126 if (unlikely (runp == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004127 {
4128 printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
4129 return;
4130 }
4131
4132 Dwarf_Addr start;
4133 Dwarf_Word length;
4134 Dwarf_Off offset;
4135
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004136 if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004137 printf (gettext (" [%*zu] ???\n"), digits, n);
4138 else
4139 printf (gettext (" [%*zu] start: %0#*" PRIx64
4140 ", length: %5" PRIu64 ", CU DIE offset: %6"
4141 PRId64 "\n"),
4142 digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18,
4143 (uint64_t) start, (uint64_t) length, (int64_t) offset);
4144 }
4145}
4146
4147/* Print content of DWARF .debug_ranges section. */
4148static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004149print_debug_ranges_section (Dwfl_Module *dwflmod,
4150 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004151 GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr,
4152 Dwarf *dbg)
4153{
4154 Elf_Data *data = elf_rawdata (scn, NULL);
4155
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004156 if (unlikely (data == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004157 {
4158 error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
4159 elf_errmsg (-1));
4160 return;
4161 }
4162
4163 printf (gettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08004164\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4165 elf_ndxscn (scn), ".debug_ranges", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004166
4167 size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4168
4169 bool first = true;
4170 unsigned char *readp = data->d_buf;
4171 while (readp < (unsigned char *) data->d_buf + data->d_size)
4172 {
4173 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
4174
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00004175 if (unlikely (data->d_size - offset < address_size * 2))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004176 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004177 printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004178 break;
4179 }
4180
4181 Dwarf_Addr begin;
4182 Dwarf_Addr end;
4183 if (address_size == 8)
4184 {
4185 begin = read_8ubyte_unaligned_inc (dbg, readp);
4186 end = read_8ubyte_unaligned_inc (dbg, readp);
4187 }
4188 else
4189 {
4190 begin = read_4ubyte_unaligned_inc (dbg, readp);
4191 end = read_4ubyte_unaligned_inc (dbg, readp);
4192 if (begin == (Dwarf_Addr) (uint32_t) -1)
4193 begin = (Dwarf_Addr) -1l;
4194 }
4195
4196 if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004197 {
4198 char *b = format_dwarf_addr (dwflmod, address_size, end);
4199 printf (gettext (" [%6tx] base address %s\n"), offset, b);
4200 free (b);
4201 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004202 else if (begin == 0 && end == 0) /* End of list entry. */
4203 first = true;
4204 else
4205 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004206 char *b = format_dwarf_addr (dwflmod, address_size, begin);
4207 char *e = format_dwarf_addr (dwflmod, address_size, end);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004208 /* We have an address range entry. */
4209 if (first) /* First address range entry in a list. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004210 printf (gettext (" [%6tx] %s..%s\n"), offset, b, e);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004211 else
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004212 printf (gettext (" %s..%s\n"), b, e);
4213 free (b);
4214 free (e);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004215
4216 first = false;
4217 }
4218 }
4219}
4220
4221
4222static void
Ulrich Drepperac194d02009-01-06 00:30:01 -08004223print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
4224 Dwarf_Word vma_base, unsigned int code_align,
4225 int data_align, unsigned int ptr_size, Dwfl_Module *dwflmod,
4226 Ebl *ebl, Dwarf *dbg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004227{
Ulrich Drepperac194d02009-01-06 00:30:01 -08004228 char regnamebuf[16];
4229 const char *regname (unsigned int regno)
4230 {
4231 const char *str;
4232 int i;
4233 return (ebl_register_info (ebl, regno, regnamebuf, sizeof (regnamebuf),
4234 &str, &str, &i, &i) < 0
4235 ? "???" : regnamebuf);
4236 }
4237
4238 puts ("\n Program:");
4239 Dwarf_Word pc = vma_base;
4240 while (readp < endp)
4241 {
4242 unsigned int opcode = *readp++;
4243
4244 if (opcode < DW_CFA_advance_loc)
4245 /* Extended opcode. */
4246 switch (opcode)
4247 {
4248 uint64_t op1;
4249 int64_t sop1;
4250 uint64_t op2;
4251 int64_t sop2;
4252
4253 case DW_CFA_nop:
4254 puts (" nop");
4255 break;
4256 case DW_CFA_set_loc:
4257 // XXX overflow check
4258 get_uleb128 (op1, readp);
4259 op1 += vma_base;
4260 printf (" set_loc %" PRIu64 "\n", op1 * code_align);
4261 break;
4262 case DW_CFA_advance_loc1:
4263 printf (" advance_loc1 %u to %#" PRIx64 "\n",
4264 *readp, pc += *readp * code_align);
4265 ++readp;
4266 break;
4267 case DW_CFA_advance_loc2:
4268 op1 = read_2ubyte_unaligned_inc (dbg, readp);
4269 printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n",
4270 op1, pc += op1 * code_align);
4271 break;
4272 case DW_CFA_advance_loc4:
4273 op1 = read_4ubyte_unaligned_inc (dbg, readp);
4274 printf (" advance_loc4 %" PRIu64 " to %#" PRIx64 "\n",
4275 op1, pc += op1 * code_align);
4276 break;
4277 case DW_CFA_offset_extended:
4278 // XXX overflow check
4279 get_uleb128 (op1, readp);
4280 get_uleb128 (op2, readp);
4281 printf (" offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64
4282 "\n",
4283 op1, regname (op1), op2 * data_align);
4284 break;
4285 case DW_CFA_restore_extended:
4286 // XXX overflow check
4287 get_uleb128 (op1, readp);
4288 printf (" restore_extended r%" PRIu64 " (%s)\n",
4289 op1, regname (op1));
4290 break;
4291 case DW_CFA_undefined:
4292 // XXX overflow check
4293 get_uleb128 (op1, readp);
4294 printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1));
4295 break;
4296 case DW_CFA_same_value:
4297 // XXX overflow check
4298 get_uleb128 (op1, readp);
4299 printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1));
4300 break;
4301 case DW_CFA_register:
4302 // XXX overflow check
4303 get_uleb128 (op1, readp);
4304 get_uleb128 (op2, readp);
4305 printf (" same_value r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n",
4306 op1, regname (op1), op2, regname (op2));
4307 break;
4308 case DW_CFA_remember_state:
4309 puts (" remember_state");
4310 break;
4311 case DW_CFA_restore_state:
4312 puts (" restore_state");
4313 break;
4314 case DW_CFA_def_cfa:
4315 // XXX overflow check
4316 get_uleb128 (op1, readp);
4317 get_uleb128 (op2, readp);
4318 printf (" def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n",
4319 op1, regname (op1), op2);
4320 break;
4321 case DW_CFA_def_cfa_register:
4322 // XXX overflow check
4323 get_uleb128 (op1, readp);
4324 printf (" def_cfa_register r%" PRIu64 " (%s)\n",
4325 op1, regname (op1));
4326 break;
4327 case DW_CFA_def_cfa_offset:
4328 // XXX overflow check
4329 get_uleb128 (op1, readp);
4330 printf (" def_cfa_offset %" PRIu64 "\n", op1);
4331 break;
4332 case DW_CFA_def_cfa_expression:
4333 // XXX overflow check
4334 get_uleb128 (op1, readp); /* Length of DW_FORM_block. */
4335 printf (" val_expression %" PRIu64 "\n", op1);
4336 print_ops (dwflmod, dbg, 10, 10, ptr_size, op1, readp);
4337 readp += op1;
4338 error (1,0,"need to implement BLOCK reading");
4339 break;
4340 case DW_CFA_expression:
4341 // XXX overflow check
4342 get_uleb128 (op1, readp);
4343 get_uleb128 (op2, readp); /* Length of DW_FORM_block. */
4344 printf (" val_expression %" PRIu64 "\n", op1);
4345 print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp);
4346 readp += op2;
4347 break;
4348 case DW_CFA_offset_extended_sf:
4349 // XXX overflow check
4350 get_uleb128 (op1, readp);
4351 get_sleb128 (sop2, readp);
4352 printf (" offset_extended_sf r%" PRIu64 " (%s) at cfa%+"
4353 PRId64 "\n",
4354 op1, regname (op1), sop2 * data_align);
4355 break;
4356 case DW_CFA_def_cfa_sf:
4357 // XXX overflow check
4358 get_uleb128 (op1, readp);
4359 get_sleb128 (sop2, readp);
4360 printf (" def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n",
4361 op1, regname (op1), sop2 * data_align);
4362 break;
4363 case DW_CFA_def_cfa_offset_sf:
4364 // XXX overflow check
4365 get_sleb128 (sop1, readp);
4366 printf (" def_cfa_offset_sf %" PRId64 "\n", sop1 * data_align);
4367 break;
4368 case DW_CFA_val_offset:
4369 // XXX overflow check
4370 get_uleb128 (op1, readp);
4371 get_uleb128 (op2, readp);
4372 printf (" val_offset %" PRIu64 " at offset %" PRIu64 "\n",
4373 op1, op2 * data_align);
4374 break;
4375 case DW_CFA_val_offset_sf:
4376 // XXX overflow check
4377 get_uleb128 (op1, readp);
4378 get_sleb128 (sop2, readp);
4379 printf (" val_offset %" PRIu64 " at offset %" PRId64 "\n",
4380 op1, sop2 * data_align);
4381 break;
4382 case DW_CFA_val_expression:
4383 // XXX overflow check
4384 get_uleb128 (op1, readp);
4385 get_uleb128 (op2, readp); /* Length of DW_FORM_block. */
4386 printf (" val_expression %" PRIu64 "\n", op1);
4387 print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp);
4388 readp += op2;
4389 break;
4390 case DW_CFA_MIPS_advance_loc8:
4391 op1 = read_8ubyte_unaligned_inc (dbg, readp);
4392 printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n",
4393 op1, pc += op1 * code_align);
4394 break;
4395 case DW_CFA_GNU_window_save:
4396 puts (" window_save");
4397 break;
4398 case DW_CFA_GNU_args_size:
4399 // XXX overflow check
4400 get_uleb128 (op1, readp);
4401 printf (" args_size %" PRIu64 "\n", op1);
4402 break;
4403 default:
4404 printf (" ??? (%u)\n", opcode);
4405 break;
4406 }
4407 else if (opcode < DW_CFA_offset)
4408 printf (" advance_loc %u to %#" PRIx64 "\n",
4409 opcode & 0x3f, pc += (opcode & 0x3f) * code_align);
4410 else if (opcode < DW_CFA_restore)
4411 {
4412 unsigned int offset;
4413 // XXX overflow check
4414 get_uleb128 (offset, readp);
4415 printf (" offset r%u (%s) at cfa%+d\n",
4416 opcode & 0x3f, regname (opcode & 0x3f), offset * data_align);
4417 }
4418 else
4419 printf (" restore r%u (%s)\n",
4420 opcode & 0x3f, regname (opcode & 0x3f));
4421 }
4422}
4423
4424
4425static unsigned int
4426encoded_ptr_size (int encoding, unsigned int ptr_size)
4427{
4428 switch (encoding & 7)
4429 {
4430 case 2:
4431 return 2;
4432 case 3:
4433 return 4;
4434 case 4:
4435 return 8;
4436 default:
4437 return ptr_size;
4438 }
4439}
4440
4441
Ulrich Drepper351bf202009-01-15 20:18:40 -08004442static unsigned int
4443print_encoding (unsigned int val)
4444{
4445 switch (val & 0xf)
4446 {
4447 case DW_EH_PE_absptr:
4448 fputs ("absptr", stdout);
4449 break;
4450 case DW_EH_PE_uleb128:
4451 fputs ("uleb128", stdout);
4452 break;
4453 case DW_EH_PE_udata2:
4454 fputs ("udata2", stdout);
4455 break;
4456 case DW_EH_PE_udata4:
4457 fputs ("udata4", stdout);
4458 break;
4459 case DW_EH_PE_udata8:
4460 fputs ("udata8", stdout);
4461 break;
4462 case DW_EH_PE_sleb128:
4463 fputs ("sleb128", stdout);
4464 break;
4465 case DW_EH_PE_sdata2:
4466 fputs ("sdata2", stdout);
4467 break;
4468 case DW_EH_PE_sdata4:
4469 fputs ("sdata4", stdout);
4470 break;
4471 case DW_EH_PE_sdata8:
4472 fputs ("sdata8", stdout);
4473 break;
4474 default:
4475 /* We did not use any of the bits after all. */
4476 return val;
4477 }
4478
4479 return val & ~0xf;
4480}
4481
4482
4483static unsigned int
4484print_relinfo (unsigned int val)
4485{
4486 switch (val & 0x70)
4487 {
4488 case DW_EH_PE_pcrel:
4489 fputs ("pcrel", stdout);
4490 break;
4491 case DW_EH_PE_textrel:
4492 fputs ("textrel", stdout);
4493 break;
4494 case DW_EH_PE_datarel:
4495 fputs ("datarel", stdout);
4496 break;
4497 case DW_EH_PE_funcrel:
4498 fputs ("funcrel", stdout);
4499 break;
4500 case DW_EH_PE_aligned:
4501 fputs ("aligned", stdout);
4502 break;
4503 default:
4504 return val;
4505 }
4506
4507 return val & ~0x70;
4508}
4509
4510
4511static void
Ulrich Drepperbc298972009-01-16 11:50:10 -08004512print_encoding_base (const char *pfx, unsigned int fde_encoding)
Ulrich Drepper351bf202009-01-15 20:18:40 -08004513{
Ulrich Drepperbc298972009-01-16 11:50:10 -08004514 printf ("(%s", pfx);
Ulrich Drepper351bf202009-01-15 20:18:40 -08004515
Ulrich Drepper05d2b202009-01-16 17:58:54 -08004516 if (fde_encoding == DW_EH_PE_omit)
4517 puts ("omit)");
4518 else
Ulrich Drepper351bf202009-01-15 20:18:40 -08004519 {
Ulrich Drepper05d2b202009-01-16 17:58:54 -08004520 unsigned int w = fde_encoding;
Ulrich Drepper351bf202009-01-15 20:18:40 -08004521
Ulrich Drepper05d2b202009-01-16 17:58:54 -08004522 if (w & 0xf)
4523 w = print_encoding (w);
4524
4525 if (w & 0x70)
4526 {
4527 if (w != fde_encoding)
4528 fputc_unlocked (' ', stdout);
4529
4530 w = print_relinfo (w);
4531 }
4532
4533 if (w != 0)
4534 printf ("%s%x", w != fde_encoding ? " " : "", w);
4535
4536 puts (")");
Ulrich Drepper351bf202009-01-15 20:18:40 -08004537 }
Ulrich Drepper351bf202009-01-15 20:18:40 -08004538}
4539
4540
Ulrich Drepperbc298972009-01-16 11:50:10 -08004541static const unsigned char *
4542read_encoded (unsigned int encoding, const unsigned char *readp,
4543 const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
4544{
4545 switch (encoding & 0xf)
4546 {
4547 case DW_EH_PE_uleb128:
4548 // XXX buffer overrun check
4549 get_uleb128 (*res, readp);
4550 break;
4551 case DW_EH_PE_sleb128:
4552 // XXX buffer overrun check
4553 get_sleb128 (*res, readp);
4554 break;
4555 case DW_EH_PE_udata2:
4556 if (readp + 2 > endp)
4557 goto invalid;
4558 *res = read_2ubyte_unaligned_inc (dbg, readp);
4559 break;
4560 case DW_EH_PE_udata4:
4561 if (readp + 4 > endp)
4562 goto invalid;
4563 *res = read_4ubyte_unaligned_inc (dbg, readp);
4564 break;
4565 case DW_EH_PE_udata8:
4566 if (readp + 8 > endp)
4567 goto invalid;
4568 *res = read_8ubyte_unaligned_inc (dbg, readp);
4569 break;
4570 case DW_EH_PE_sdata2:
4571 if (readp + 2 > endp)
4572 goto invalid;
4573 *res = read_2sbyte_unaligned_inc (dbg, readp);
4574 break;
4575 case DW_EH_PE_sdata4:
4576 if (readp + 4 > endp)
4577 goto invalid;
4578 *res = read_4sbyte_unaligned_inc (dbg, readp);
4579 break;
4580 case DW_EH_PE_sdata8:
4581 if (readp + 8 > endp)
4582 goto invalid;
4583 *res = read_8sbyte_unaligned_inc (dbg, readp);
4584 break;
4585 default:
4586 invalid:
4587 error (1, 0,
4588 gettext ("invalid encoding"));
4589 }
4590
4591 return readp;
4592}
4593
4594
Ulrich Drepperac194d02009-01-06 00:30:01 -08004595static void
4596print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
4597 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
4598{
4599 size_t shstrndx;
4600 /* We know this call will succeed since it did in the caller. */
4601 (void) elf_getshstrndx (ebl->elf, &shstrndx);
4602 const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
4603
4604 Elf_Data *data = elf_rawdata (scn, NULL);
4605
4606 if (unlikely (data == NULL))
4607 {
4608 error (0, 0, gettext ("cannot get %s content: %s"),
4609 scnname, elf_errmsg (-1));
4610 return;
4611 }
Ulrich Drepper351bf202009-01-15 20:18:40 -08004612 bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004613
Ulrich Drepper351bf202009-01-15 20:18:40 -08004614 if (is_eh_frame)
4615 printf (gettext ("\
4616\nCall frame information section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4617 elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
4618 else
4619 printf (gettext ("\
4620\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
4621 elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004622
4623 struct cieinfo
4624 {
4625 ptrdiff_t cie_offset;
4626 const char *augmentation;
4627 unsigned int code_alignment_factor;
4628 unsigned int data_alignment_factor;
4629 unsigned int fde_encoding;
Ulrich Drepperbc298972009-01-16 11:50:10 -08004630 unsigned int lsda_encoding;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004631 struct cieinfo *next;
4632 } *cies = NULL;
4633
4634 const unsigned char *readp = data->d_buf;
4635 const unsigned char *const dataend = ((unsigned char *) data->d_buf
4636 + data->d_size);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004637 while (readp < dataend)
4638 {
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004639 if (unlikely (readp + 4 > dataend))
Ulrich Drepperac194d02009-01-06 00:30:01 -08004640 {
4641 invalid_data:
4642 error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
4643 elf_ndxscn (scn), scnname);
4644 return;
4645 }
4646
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004647 /* At the beginning there must be a CIE. There can be multiple,
4648 hence we test tis in a loop. */
4649 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004650
4651 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp);
4652 unsigned int length = 4;
4653 if (unlikely (unit_length == 0xffffffff))
4654 {
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004655 if (unlikely (readp + 8 > dataend))
4656 goto invalid_data;
4657
Ulrich Drepperac194d02009-01-06 00:30:01 -08004658 unit_length = read_8ubyte_unaligned_inc (dbg, readp);
4659 length = 8;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004660 }
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004661
4662 if (unlikely (unit_length == 0))
4663 {
Roland McGrathe9de9b42009-01-22 13:05:40 -08004664 printf (gettext ("\n [%6tx] Zero terminator\n"), offset);
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004665 continue;
4666 }
4667
4668 unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4669
Ulrich Drepperac194d02009-01-06 00:30:01 -08004670 ptrdiff_t start = readp - (unsigned char *) data->d_buf;
4671 const unsigned char *const cieend = readp + unit_length;
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004672 if (unlikely (cieend > dataend || readp + 8 > dataend))
Ulrich Drepperac194d02009-01-06 00:30:01 -08004673 goto invalid_data;
4674
4675 Dwarf_Word cie_id;
4676 if (length == 4)
4677 cie_id = read_4ubyte_unaligned_inc (dbg, readp);
4678 else
4679 cie_id = read_8ubyte_unaligned_inc (dbg, readp);
4680
4681 unsigned int code_alignment_factor;
4682 int data_alignment_factor;
4683 unsigned int fde_encoding = 0;
Ulrich Drepperbc298972009-01-16 11:50:10 -08004684 unsigned int lsda_encoding = 0;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004685 Dwarf_Word initial_location = 0;
Ulrich Drepper62c46532009-01-24 17:01:08 -08004686 Dwarf_Word vma_base = 0;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004687
Ulrich Drepper351bf202009-01-15 20:18:40 -08004688 if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID))
Ulrich Drepperac194d02009-01-06 00:30:01 -08004689 {
4690 uint_fast8_t version = *readp++;
4691 const char *const augmentation = (const char *) readp;
4692 readp = memchr (readp, '\0', cieend - readp);
4693 if (unlikely (readp == NULL))
4694 goto invalid_data;
4695 ++readp;
4696 // XXX Check overflow
4697 get_uleb128 (code_alignment_factor, readp);
4698 // XXX Check overflow
4699 get_sleb128 (data_alignment_factor, readp);
4700
4701 /* In some variant for unwind data there is another field. */
4702 if (strcmp (augmentation, "eh") == 0)
4703 readp += ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
4704
4705 unsigned int return_address_register;
4706 if (unlikely (version == 1))
4707 return_address_register = *readp++;
4708 else
4709 // XXX Check overflow
4710 get_uleb128 (return_address_register, readp);
4711
Roland McGrathe9de9b42009-01-22 13:05:40 -08004712 printf ("\n [%6tx] CIE length=%" PRIu64 "\n"
Ulrich Drepperac194d02009-01-06 00:30:01 -08004713 " CIE_id: %" PRIu64 "\n"
4714 " version: %u\n"
4715 " augmentation: \"%s\"\n"
4716 " code_alignment_factor: %u\n"
4717 " data_alignment_factor: %d\n"
4718 " return_address_register: %u\n",
4719 offset, (uint64_t) unit_length, (uint64_t) cie_id,
4720 version, augmentation, code_alignment_factor,
4721 data_alignment_factor, return_address_register);
4722
4723 if (augmentation[0] == 'z')
4724 {
Ulrich Drepperac194d02009-01-06 00:30:01 -08004725 unsigned int augmentationlen;
4726 get_uleb128 (augmentationlen, readp);
4727
4728 const char *hdr = "Augmentation data:";
4729 const char *cp = augmentation + 1;
4730 while (*cp != '\0')
4731 {
4732 printf (" %-26s%#x ", hdr, *readp);
4733 hdr = "";
4734
4735 if (*cp == 'R')
4736 {
Ulrich Drepperbc298972009-01-16 11:50:10 -08004737 fde_encoding = *readp++;
4738 print_encoding_base (gettext ("FDE address encoding: "),
4739 fde_encoding);
4740 }
4741 else if (*cp == 'L')
4742 {
4743 lsda_encoding = *readp++;
4744 print_encoding_base (gettext ("LSDA pointer encoding: "),
4745 lsda_encoding);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004746 }
4747 else if (*cp == 'P')
4748 {
Ulrich Drepper351bf202009-01-15 20:18:40 -08004749 /* Personality. This field usually has a relocation
4750 attached pointing to __gcc_personality_v0. */
Ulrich Drepperac194d02009-01-06 00:30:01 -08004751 const unsigned char *startp = readp;
4752 unsigned int encoding = *readp++;
4753 uint64_t val = 0;
4754 int64_t sval = 0;
Roland McGrathcabeeee2009-01-22 13:17:45 -08004755 bool is_signed = false;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004756
4757 switch (encoding & 0xf)
4758 {
4759 case DW_EH_PE_uleb128:
4760 get_uleb128 (val, readp);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004761 break;
4762 case DW_EH_PE_sleb128:
4763 get_sleb128 (sval, readp);
4764 is_signed = true;
4765 break;
4766 case DW_EH_PE_udata2:
4767 val = read_2ubyte_unaligned_inc (dbg, readp);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004768 break;
4769 case DW_EH_PE_udata4:
4770 val = read_4ubyte_unaligned_inc (dbg, readp);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004771 break;
4772 case DW_EH_PE_udata8:
4773 val = read_8ubyte_unaligned_inc (dbg, readp);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004774 break;
4775 case DW_EH_PE_sdata2:
4776 val = read_2sbyte_unaligned_inc (dbg, readp);
4777 is_signed = true;
4778 break;
4779 case DW_EH_PE_sdata4:
4780 val = read_4sbyte_unaligned_inc (dbg, readp);
4781 is_signed = true;
4782 break;
4783 case DW_EH_PE_sdata8:
4784 val = read_8sbyte_unaligned_inc (dbg, readp);
4785 is_signed = true;
4786 break;
4787 default:
4788 error (1, 0,
4789 gettext ("invalid augmentation encoding"));
4790 }
4791
4792 while (++startp < readp)
4793 printf ("%#x ", *startp);
4794
4795 if (is_signed)
4796 printf ("(%" PRId64 ")\n", sval);
4797 else
4798 printf ("(%" PRIu64 ")\n", val);
4799 }
4800 else
4801 printf ("(%x)\n", *readp++);
4802
4803 ++cp;
4804 }
Ulrich Drepperac194d02009-01-06 00:30:01 -08004805 }
4806
4807 struct cieinfo *newp = alloca (sizeof (*newp));
4808 newp->cie_offset = offset;
4809 newp->augmentation = augmentation;
4810 newp->fde_encoding = fde_encoding;
Ulrich Drepperbc298972009-01-16 11:50:10 -08004811 newp->lsda_encoding = lsda_encoding;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004812 newp->code_alignment_factor = code_alignment_factor;
4813 newp->data_alignment_factor = data_alignment_factor;
4814 newp->next = cies;
4815 cies = newp;
4816 }
4817 else
4818 {
4819 struct cieinfo *cie = cies;
4820 while (cie != NULL)
Ulrich Drepper351bf202009-01-15 20:18:40 -08004821 if (is_eh_frame
4822 ? start - (ptrdiff_t) cie_id == cie->cie_offset
4823 : (ptrdiff_t) cie_id == cie->cie_offset)
Ulrich Drepperac194d02009-01-06 00:30:01 -08004824 break;
4825 else
4826 cie = cie->next;
4827 if (unlikely (cie == NULL))
4828 {
4829 puts ("invalid CIE reference in FDE");
4830 return;
4831 }
4832
4833 /* Initialize from CIE data. */
Ulrich Drepper351bf202009-01-15 20:18:40 -08004834 fde_encoding = cie->fde_encoding;
Ulrich Drepperbc298972009-01-16 11:50:10 -08004835 lsda_encoding = cie->lsda_encoding;
Ulrich Drepper351bf202009-01-15 20:18:40 -08004836 ptr_size = encoded_ptr_size (fde_encoding, ptr_size);
Ulrich Drepperac194d02009-01-06 00:30:01 -08004837 code_alignment_factor = cie->code_alignment_factor;
4838 data_alignment_factor = cie->data_alignment_factor;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004839
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004840 const unsigned char *base = readp;
Ulrich Drepper351bf202009-01-15 20:18:40 -08004841 // XXX There are sometimes relocations for this value
Ulrich Drepperac194d02009-01-06 00:30:01 -08004842 initial_location = read_ubyte_unaligned_inc (ptr_size, dbg, readp);
4843 Dwarf_Word address_range
4844 = read_ubyte_unaligned_inc (ptr_size, dbg, readp);
4845
Roland McGrathe9de9b42009-01-22 13:05:40 -08004846 printf ("\n [%6tx] FDE length=%" PRIu64 " cie=[%6tx]\n"
Ulrich Drepperac194d02009-01-06 00:30:01 -08004847 " CIE_pointer: %" PRIu64 "\n"
Ulrich Drepper351bf202009-01-15 20:18:40 -08004848 " initial_location: %#" PRIx64,
Ulrich Drepperac194d02009-01-06 00:30:01 -08004849 offset, (uint64_t) unit_length,
4850 cie->cie_offset, (uint64_t) cie_id,
Ulrich Drepper351bf202009-01-15 20:18:40 -08004851 (uint64_t) initial_location);
4852 if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
Ulrich Drepper62c46532009-01-24 17:01:08 -08004853 {
4854 vma_base = (((uint64_t) shdr->sh_offset
4855 + (base - (const unsigned char *) data->d_buf)
4856 + (uint64_t) initial_location)
4857 & (ptr_size == 4
4858 ? UINT64_C (0xffffffff)
4859 : UINT64_C (0xffffffffffffffff)));
4860 printf (gettext (" (offset: %#" PRIx64 ")"),
4861 (uint64_t) vma_base);
4862 }
4863
4864 printf ("\n address_range: %#" PRIx64,
4865 (uint64_t) address_range);
4866 if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
4867 printf (gettext (" (end offset: %#" PRIx64 ")"),
4868 ((uint64_t) vma_base + (uint64_t) address_range)
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08004869 & (ptr_size == 4
4870 ? UINT64_C (0xffffffff)
4871 : UINT64_C (0xffffffffffffffff)));
Ulrich Drepper62c46532009-01-24 17:01:08 -08004872 putchar ('\n');
Ulrich Drepperac194d02009-01-06 00:30:01 -08004873
4874 if (cie->augmentation[0] == 'z')
4875 {
4876 unsigned int augmentationlen;
4877 get_uleb128 (augmentationlen, readp);
4878
Ulrich Drepper351bf202009-01-15 20:18:40 -08004879 if (augmentationlen > 0)
Ulrich Drepperac194d02009-01-06 00:30:01 -08004880 {
Ulrich Drepper351bf202009-01-15 20:18:40 -08004881 const char *hdr = "Augmentation data:";
4882 const char *cp = cie->augmentation + 1;
Ulrich Drepperbc298972009-01-16 11:50:10 -08004883 unsigned int u = 0;
4884 while (*cp != '\0')
Ulrich Drepper351bf202009-01-15 20:18:40 -08004885 {
Ulrich Drepperbc298972009-01-16 11:50:10 -08004886 if (*cp == 'L')
4887 {
4888 uint64_t lsda_pointer;
4889 const unsigned char *p
4890 = read_encoded (lsda_encoding, &readp[u],
4891 &readp[augmentationlen],
4892 &lsda_pointer, dbg);
4893 u = p - readp;
4894 printf (gettext ("\
4895 %-26sLSDA pointer: %#" PRIx64 "\n"),
4896 hdr, lsda_pointer);
4897 hdr = "";
4898 }
4899 ++cp;
4900 }
4901
4902 while (u < augmentationlen)
4903 {
4904 printf (" %-26s%#x\n", hdr, readp[u++]);
Ulrich Drepper351bf202009-01-15 20:18:40 -08004905 hdr = "";
4906 }
Ulrich Drepperac194d02009-01-06 00:30:01 -08004907 }
Ulrich Drepperbc298972009-01-16 11:50:10 -08004908
4909 readp += augmentationlen;
Ulrich Drepperac194d02009-01-06 00:30:01 -08004910 }
4911 }
4912
Ulrich Drepperac194d02009-01-06 00:30:01 -08004913 /* Handle the initialization instructions. */
4914 print_cfa_program (readp, cieend, vma_base, code_alignment_factor,
4915 data_alignment_factor, ptr_size, dwflmod, ebl, dbg);
4916 readp = cieend;
4917 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004918}
4919
4920
4921struct attrcb_args
4922{
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004923 Dwfl_Module *dwflmod;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004924 Dwarf *dbg;
4925 int level;
4926 unsigned int addrsize;
4927 Dwarf_Off cu_offset;
4928};
4929
4930
4931static int
4932attr_callback (Dwarf_Attribute *attrp, void *arg)
4933{
4934 struct attrcb_args *cbargs = (struct attrcb_args *) arg;
4935 const int level = cbargs->level;
4936
4937 unsigned int attr = dwarf_whatattr (attrp);
4938 if (unlikely (attr == 0))
4939 {
4940 error (0, 0, gettext ("cannot get attribute code: %s"),
4941 dwarf_errmsg (-1));
4942 return DWARF_CB_ABORT;
4943 }
4944
4945 unsigned int form = dwarf_whatform (attrp);
4946 if (unlikely (form == 0))
4947 {
4948 error (0, 0, gettext ("cannot get attribute form: %s"),
4949 dwarf_errmsg (-1));
4950 return DWARF_CB_ABORT;
4951 }
4952
4953 switch (form)
4954 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004955 case DW_FORM_addr:
4956 {
4957 Dwarf_Addr addr;
4958 if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
4959 {
4960 attrval_out:
Ulrich Drepperc911d5c2008-01-22 05:59:26 +00004961 error (0, 0, gettext ("cannot get attribute value: %s"),
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00004962 dwarf_errmsg (-1));
4963 return DWARF_CB_ABORT;
4964 }
4965 char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr);
4966 printf (" %*s%-20s %s\n",
4967 (int) (level * 2), "", dwarf_attr_string (attr), a);
4968 free (a);
4969 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004970 break;
4971
4972 case DW_FORM_indirect:
4973 case DW_FORM_strp:
4974 case DW_FORM_string:;
4975 const char *str = dwarf_formstring (attrp);
4976 if (unlikely (str == NULL))
4977 goto attrval_out;
4978 printf (" %*s%-20s \"%s\"\n",
4979 (int) (level * 2), "", dwarf_attr_string (attr), str);
4980 break;
4981
4982 case DW_FORM_ref_addr:
4983 case DW_FORM_ref_udata:
4984 case DW_FORM_ref8:
4985 case DW_FORM_ref4:
4986 case DW_FORM_ref2:
4987 case DW_FORM_ref1:;
Roland McGrathe4c22ea2007-10-23 13:07:39 +00004988 Dwarf_Die ref;
4989 if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004990 goto attrval_out;
4991
4992 printf (" %*s%-20s [%6" PRIxMAX "]\n",
4993 (int) (level * 2), "", dwarf_attr_string (attr),
Roland McGrathe4c22ea2007-10-23 13:07:39 +00004994 (uintmax_t) dwarf_dieoffset (&ref));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004995 break;
4996
4997 case DW_FORM_udata:
4998 case DW_FORM_sdata:
4999 case DW_FORM_data8:
5000 case DW_FORM_data4:
5001 case DW_FORM_data2:
5002 case DW_FORM_data1:;
5003 Dwarf_Word num;
5004 if (unlikely (dwarf_formudata (attrp, &num) != 0))
5005 goto attrval_out;
5006
5007 const char *valuestr = NULL;
5008 switch (attr)
5009 {
5010 case DW_AT_location:
Roland McGrath07a696e2007-11-09 22:44:26 +00005011 case DW_AT_data_location:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005012 case DW_AT_data_member_location:
5013 case DW_AT_vtable_elem_location:
5014 case DW_AT_string_length:
5015 case DW_AT_use_location:
5016 case DW_AT_frame_base:
5017 case DW_AT_return_addr:
5018 case DW_AT_static_link:
5019 printf (" %*s%-20s location list [%6" PRIxMAX "]\n",
5020 (int) (level * 2), "", dwarf_attr_string (attr),
5021 (uintmax_t) num);
5022 return DWARF_CB_OK;
5023
5024 case DW_AT_ranges:
5025 printf (" %*s%-20s range list [%6" PRIxMAX "]\n",
5026 (int) (level * 2), "", dwarf_attr_string (attr),
5027 (uintmax_t) num);
5028 return DWARF_CB_OK;
5029
5030 case DW_AT_language:
5031 valuestr = dwarf_lang_string (num);
5032 break;
5033 case DW_AT_encoding:
5034 valuestr = dwarf_encoding_string (num);
5035 break;
5036 case DW_AT_accessibility:
5037 valuestr = dwarf_access_string (num);
5038 break;
5039 case DW_AT_visibility:
5040 valuestr = dwarf_visibility_string (num);
5041 break;
5042 case DW_AT_virtuality:
5043 valuestr = dwarf_virtuality_string (num);
5044 break;
5045 case DW_AT_identifier_case:
5046 valuestr = dwarf_identifier_case_string (num);
5047 break;
5048 case DW_AT_calling_convention:
5049 valuestr = dwarf_calling_convention_string (num);
5050 break;
5051 case DW_AT_inline:
5052 valuestr = dwarf_inline_string (num);
5053 break;
5054 case DW_AT_ordering:
5055 valuestr = dwarf_ordering_string (num);
5056 break;
5057 case DW_AT_discr_list:
5058 valuestr = dwarf_discr_list_string (num);
5059 break;
5060 default:
5061 /* Nothing. */
5062 break;
5063 }
5064
5065 if (valuestr == NULL)
5066 printf (" %*s%-20s %" PRIuMAX "\n",
5067 (int) (level * 2), "", dwarf_attr_string (attr),
5068 (uintmax_t) num);
5069 else
5070 printf (" %*s%-20s %s (%" PRIuMAX ")\n",
5071 (int) (level * 2), "", dwarf_attr_string (attr),
5072 valuestr, (uintmax_t) num);
5073 break;
5074
5075 case DW_FORM_flag:;
5076 bool flag;
5077 if (unlikely (dwarf_formflag (attrp, &flag) != 0))
5078 goto attrval_out;
5079
5080 printf (" %*s%-20s %s\n",
5081 (int) (level * 2), "", dwarf_attr_string (attr),
5082 nl_langinfo (flag ? YESSTR : NOSTR));
5083 break;
5084
5085 case DW_FORM_block4:
5086 case DW_FORM_block2:
5087 case DW_FORM_block1:
5088 case DW_FORM_block:;
5089 Dwarf_Block block;
5090 if (unlikely (dwarf_formblock (attrp, &block) != 0))
5091 goto attrval_out;
5092
5093 printf (" %*s%-20s %" PRIxMAX " byte block\n",
5094 (int) (level * 2), "", dwarf_attr_string (attr),
5095 (uintmax_t) block.length);
5096
5097 switch (attr)
5098 {
5099 case DW_AT_location:
Roland McGrath07a696e2007-11-09 22:44:26 +00005100 case DW_AT_data_location:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005101 case DW_AT_data_member_location:
5102 case DW_AT_vtable_elem_location:
5103 case DW_AT_string_length:
5104 case DW_AT_use_location:
5105 case DW_AT_frame_base:
5106 case DW_AT_return_addr:
5107 case DW_AT_static_link:
Roland McGrath1a2e8f42007-12-15 23:39:34 +00005108 case DW_AT_allocated:
5109 case DW_AT_associated:
5110 case DW_AT_bit_size:
5111 case DW_AT_bit_offset:
5112 case DW_AT_bit_stride:
5113 case DW_AT_byte_size:
5114 case DW_AT_byte_stride:
5115 case DW_AT_count:
5116 case DW_AT_lower_bound:
5117 case DW_AT_upper_bound:
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005118 print_ops (cbargs->dwflmod, cbargs->dbg,
5119 12 + level * 2, 12 + level * 2,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005120 cbargs->addrsize, block.length, block.data);
5121 break;
5122 }
5123 break;
5124
5125 default:
5126 printf (" %*s%-20s [form: %d] ???\n",
5127 (int) (level * 2), "", dwarf_attr_string (attr),
5128 (int) form);
5129 break;
5130 }
5131
5132 return DWARF_CB_OK;
5133}
5134
5135
5136static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005137print_debug_info_section (Dwfl_Module *dwflmod,
5138 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005139 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepper351bf202009-01-15 20:18:40 -08005140 Elf_Scn *scn,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005141 GElf_Shdr *shdr, Dwarf *dbg)
5142{
5143 printf (gettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08005144\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"),
5145 elf_ndxscn (scn), ".debug_info", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005146
5147 /* If the section is empty we don't have to do anything. */
5148 if (shdr->sh_size == 0)
5149 return;
5150
5151 int maxdies = 20;
5152 Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
5153
5154 Dwarf_Off offset = 0;
5155
5156 /* New compilation unit. */
5157 size_t cuhl;
5158 //Dwarf_Half version;
5159 Dwarf_Off abbroffset;
5160 uint8_t addrsize;
5161 uint8_t offsize;
5162 Dwarf_Off nextcu;
5163 next_cu:
5164 if (dwarf_nextcu (dbg, offset, &nextcu, &cuhl, &abbroffset, &addrsize,
5165 &offsize) != 0)
5166 goto do_return;
5167
5168 printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
5169 " Version: %" PRIu16 ", Abbreviation section offset: %"
5170 PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 "\n"),
5171 (uint64_t) offset, /*version*/2, abbroffset, addrsize, offsize);
5172
5173
5174 struct attrcb_args args;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005175 args.dwflmod = dwflmod;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005176 args.dbg = dbg;
5177 args.addrsize = addrsize;
5178 args.cu_offset = offset;
5179
5180 offset += cuhl;
5181
5182 int level = 0;
5183
5184 if (unlikely (dwarf_offdie (dbg, offset, &dies[level]) == NULL))
5185 {
5186 error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
5187 " in section '%s': %s"),
5188 (uint64_t) offset, ".debug_info", dwarf_errmsg (-1));
5189 goto do_return;
5190 }
5191
5192 do
5193 {
5194 offset = dwarf_dieoffset (&dies[level]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005195 if (unlikely (offset == ~0ul))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005196 {
5197 error (0, 0, gettext ("cannot get DIE offset: %s"),
5198 dwarf_errmsg (-1));
5199 goto do_return;
5200 }
5201
5202 int tag = dwarf_tag (&dies[level]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005203 if (unlikely (tag == DW_TAG_invalid))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005204 {
Ulrich Drepperc911d5c2008-01-22 05:59:26 +00005205 error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005206 " in section '%s': %s"),
5207 (uint64_t) offset, ".debug_info", dwarf_errmsg (-1));
5208 goto do_return;
5209 }
5210
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005211 printf (" [%6" PRIx64 "] %*s%s\n",
Ulrich Drepper8b383102007-02-16 00:31:57 +00005212 (uint64_t) offset, (int) (level * 2), "",
5213 dwarf_tag_string (tag));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005214
5215 /* Print the attribute values. */
5216 args.level = level;
5217 (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0);
5218
5219 /* Make room for the next level's DIE. */
5220 if (level + 1 == maxdies)
5221 dies = (Dwarf_Die *) xrealloc (dies,
5222 (maxdies += 10)
5223 * sizeof (Dwarf_Die));
5224
5225 int res = dwarf_child (&dies[level], &dies[level + 1]);
5226 if (res > 0)
5227 {
5228 while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1)
Ulrich Drepperc911d5c2008-01-22 05:59:26 +00005229 if (level-- == 0)
5230 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005231
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005232 if (unlikely (res == -1))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005233 {
5234 error (0, 0, gettext ("cannot get next DIE: %s\n"),
5235 dwarf_errmsg (-1));
5236 goto do_return;
5237 }
5238 }
5239 else if (unlikely (res < 0))
5240 {
5241 error (0, 0, gettext ("cannot get next DIE: %s"),
5242 dwarf_errmsg (-1));
5243 goto do_return;
5244 }
5245 else
5246 ++level;
5247 }
5248 while (level >= 0);
5249
5250 offset = nextcu;
5251 if (offset != 0)
5252 goto next_cu;
5253
5254 do_return:
5255 free (dies);
5256}
5257
5258
5259static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005260print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
5261 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005262 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5263{
5264 printf (gettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08005265\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5266 elf_ndxscn (scn), ".debug_line", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005267
5268 if (shdr->sh_size == 0)
5269 return;
5270
5271 /* There is no functionality in libdw to read the information in the
5272 way it is represented here. Hardcode the decoder. */
5273 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005274 if (unlikely (data == NULL || data->d_buf == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005275 {
5276 error (0, 0, gettext ("cannot get line data section data: %s"),
5277 elf_errmsg (-1));
5278 return;
5279 }
5280
5281 const unsigned char *linep = (const unsigned char *) data->d_buf;
5282 const unsigned char *lineendp;
5283
5284 while (linep
5285 < (lineendp = (const unsigned char *) data->d_buf + data->d_size))
5286 {
5287 size_t start_offset = linep - (const unsigned char *) data->d_buf;
5288
5289 printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
5290
5291 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
5292 unsigned int length = 4;
5293 if (unlikely (unit_length == 0xffffffff))
5294 {
5295 if (unlikely (linep + 8 > lineendp))
5296 {
5297 invalid_data:
5298 error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
5299 elf_ndxscn (scn), ".debug_line");
5300 return;
5301 }
5302 unit_length = read_8ubyte_unaligned_inc (dbg, linep);
5303 length = 8;
5304 }
5305
5306 /* Check whether we have enough room in the section. */
5307 if (unit_length < 2 + length + 5 * 1
5308 || unlikely (linep + unit_length > lineendp))
5309 goto invalid_data;
5310 lineendp = linep + unit_length;
5311
5312 /* The next element of the header is the version identifier. */
5313 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
5314
5315 /* Next comes the header length. */
5316 Dwarf_Word header_length;
5317 if (length == 4)
5318 header_length = read_4ubyte_unaligned_inc (dbg, linep);
5319 else
5320 header_length = read_8ubyte_unaligned_inc (dbg, linep);
5321 //const unsigned char *header_start = linep;
5322
5323 /* Next the minimum instruction length. */
5324 uint_fast8_t minimum_instr_len = *linep++;
5325
5326 /* Then the flag determining the default value of the is_stmt
5327 register. */
5328 uint_fast8_t default_is_stmt = *linep++;
5329
5330 /* Now the line base. */
5331 int_fast8_t line_base = *((const int_fast8_t *) linep);
5332 ++linep;
5333
5334 /* And the line range. */
5335 uint_fast8_t line_range = *linep++;
5336
5337 /* The opcode base. */
5338 uint_fast8_t opcode_base = *linep++;
5339
5340 /* Print what we got so far. */
5341 printf (gettext ("\n"
5342 " Length: %" PRIu64 "\n"
5343 " DWARF version: %" PRIuFAST16 "\n"
5344 " Prologue length: %" PRIu64 "\n"
5345 " Minimum instruction length: %" PRIuFAST8 "\n"
5346 " Initial value if '%s': %" PRIuFAST8 "\n"
5347 " Line base: %" PRIdFAST8 "\n"
5348 " Line range: %" PRIuFAST8 "\n"
5349 " Opcode base: %" PRIuFAST8 "\n"
5350 "\n"
5351 "Opcodes:\n"),
5352 (uint64_t) unit_length, version, (uint64_t) header_length,
5353 minimum_instr_len, "is_stmt", default_is_stmt, line_base,
5354 line_range, opcode_base);
5355
5356 if (unlikely (linep + opcode_base - 1 >= lineendp))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005357 {
5358 invalid_unit:
5359 error (0, 0,
5360 gettext ("invalid data at offset %tu in section [%zu] '%s'"),
5361 linep - (const unsigned char *) data->d_buf,
5362 elf_ndxscn (scn), ".debug_line");
5363 linep = lineendp;
5364 continue;
5365 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005366 int opcode_base_l10 = 1;
5367 unsigned int tmp = opcode_base;
5368 while (tmp > 10)
5369 {
5370 tmp /= 10;
5371 ++opcode_base_l10;
5372 }
5373 const uint8_t *standard_opcode_lengths = linep - 1;
5374 for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt)
5375 printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n",
5376 " [%*" PRIuFAST8 "] %hhu arguments\n",
5377 (int) linep[cnt - 1]),
5378 opcode_base_l10, cnt, linep[cnt - 1]);
5379 linep += opcode_base - 1;
5380 if (unlikely (linep >= lineendp))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005381 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005382
5383 puts (gettext ("\nDirectory table:"));
5384 while (*linep != 0)
5385 {
5386 unsigned char *endp = memchr (linep, '\0', lineendp - linep);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005387 if (unlikely (endp == NULL))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005388 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005389
5390 printf (" %s\n", (char *) linep);
5391
5392 linep = endp + 1;
5393 }
5394 /* Skip the final NUL byte. */
5395 ++linep;
5396
5397 if (unlikely (linep >= lineendp))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005398 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005399 puts (gettext ("\nFile name table:\n"
5400 " Entry Dir Time Size Name"));
5401 for (unsigned int cnt = 1; *linep != 0; ++cnt)
5402 {
5403 /* First comes the file name. */
5404 char *fname = (char *) linep;
5405 unsigned char *endp = memchr (fname, '\0', lineendp - linep);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005406 if (unlikely (endp == NULL))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005407 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005408 linep = endp + 1;
5409
5410 /* Then the index. */
5411 unsigned int diridx;
5412 get_uleb128 (diridx, linep);
5413
5414 /* Next comes the modification time. */
5415 unsigned int mtime;
5416 get_uleb128 (mtime, linep);
5417
5418 /* Finally the length of the file. */
5419 unsigned int fsize;
5420 get_uleb128 (fsize, linep);
5421
5422 printf (" %-5u %-5u %-9u %-9u %s\n",
5423 cnt, diridx, mtime, fsize, fname);
5424 }
5425 /* Skip the final NUL byte. */
5426 ++linep;
5427
5428 puts (gettext ("\nLine number statements:"));
5429 Dwarf_Word address = 0;
5430 size_t line = 1;
5431 uint_fast8_t is_stmt = default_is_stmt;
5432
5433 /* Default address value, in case we do not find the CU. */
5434 size_t address_size
5435 = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
5436
5437 /* Determine the CU this block is for. */
5438 Dwarf_Off cuoffset;
5439 Dwarf_Off ncuoffset = 0;
5440 size_t hsize;
5441 while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
5442 NULL, NULL, NULL) == 0)
5443 {
5444 Dwarf_Die cudie;
5445 if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
5446 continue;
5447 Dwarf_Attribute stmt_list;
5448 if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL)
5449 continue;
5450 Dwarf_Word lineoff;
5451 if (dwarf_formudata (&stmt_list, &lineoff) != 0)
5452 continue;
5453 if (lineoff == start_offset)
5454 {
5455 /* Found the CU. */
5456 address_size = cudie.cu->address_size;
5457 break;
5458 }
5459 }
5460
5461 while (linep < lineendp)
5462 {
5463 unsigned int u128;
5464 int s128;
5465
5466 /* Read the opcode. */
5467 unsigned int opcode = *linep++;
5468
5469 /* Is this a special opcode? */
5470 if (likely (opcode >= opcode_base))
5471 {
5472 /* Yes. Handling this is quite easy since the opcode value
5473 is computed with
5474
5475 opcode = (desired line increment - line_base)
5476 + (line_range * address advance) + opcode_base
5477 */
5478 int line_increment = (line_base
5479 + (opcode - opcode_base) % line_range);
5480 unsigned int address_increment = (minimum_instr_len
5481 * ((opcode - opcode_base)
5482 / line_range));
5483
5484 /* Perform the increments. */
5485 line += line_increment;
5486 address += address_increment;
5487
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005488 char *a = format_dwarf_addr (dwflmod, 0, address);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005489 printf (gettext ("\
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005490 special opcode %u: address+%u = %s, line%+d = %zu\n"),
5491 opcode, address_increment, a, line_increment, line);
5492 free (a);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005493 }
5494 else if (opcode == 0)
5495 {
5496 /* This an extended opcode. */
5497 if (unlikely (linep + 2 > lineendp))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005498 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005499
5500 /* The length. */
5501 unsigned int len = *linep++;
5502
5503 if (unlikely (linep + len > lineendp))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005504 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005505
5506 /* The sub-opcode. */
5507 opcode = *linep++;
5508
5509 printf (gettext (" extended opcode %u: "), opcode);
5510
5511 switch (opcode)
5512 {
5513 case DW_LNE_end_sequence:
5514 puts (gettext ("end of sequence"));
5515
5516 /* Reset the registers we care about. */
5517 address = 0;
5518 line = 1;
5519 is_stmt = default_is_stmt;
5520 break;
5521
5522 case DW_LNE_set_address:
5523 if (address_size == 4)
5524 address = read_4ubyte_unaligned_inc (dbg, linep);
5525 else
5526 address = read_8ubyte_unaligned_inc (dbg, linep);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005527 {
5528 char *a = format_dwarf_addr (dwflmod, 0, address);
5529 printf (gettext ("set address to %s\n"), a);
5530 free (a);
5531 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005532 break;
5533
5534 case DW_LNE_define_file:
5535 {
5536 char *fname = (char *) linep;
5537 unsigned char *endp = memchr (linep, '\0',
5538 lineendp - linep);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005539 if (unlikely (endp == NULL))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005540 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005541 linep = endp + 1;
5542
5543 unsigned int diridx;
5544 get_uleb128 (diridx, linep);
5545 Dwarf_Word mtime;
5546 get_uleb128 (mtime, linep);
5547 Dwarf_Word filelength;
5548 get_uleb128 (filelength, linep);
5549
5550 printf (gettext ("\
5551define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
5552 diridx, (uint64_t) mtime, (uint64_t) filelength,
5553 fname);
5554 }
5555 break;
5556
5557 default:
5558 /* Unknown, ignore it. */
5559 puts (gettext ("unknown opcode"));
5560 linep += len - 1;
5561 break;
5562 }
5563 }
Ulrich Drepper6d5c3bd2005-08-11 04:37:52 +00005564 else if (opcode <= DW_LNS_set_epilogue_begin)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005565 {
5566 /* This is a known standard opcode. */
5567 switch (opcode)
5568 {
5569 case DW_LNS_copy:
5570 /* Takes no argument. */
5571 puts (gettext (" copy"));
5572 break;
5573
5574 case DW_LNS_advance_pc:
5575 /* Takes one uleb128 parameter which is added to the
5576 address. */
5577 get_uleb128 (u128, linep);
5578 address += minimum_instr_len * u128;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005579 {
5580 char *a = format_dwarf_addr (dwflmod, 0, address);
5581 printf (gettext ("advance address by %u to %s\n"),
5582 u128, a);
5583 free (a);
5584 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005585 break;
5586
5587 case DW_LNS_advance_line:
5588 /* Takes one sleb128 parameter which is added to the
5589 line. */
5590 get_sleb128 (s128, linep);
5591 line += s128;
5592 printf (gettext ("\
5593 advance line by constant %d to %" PRId64 "\n"),
5594 s128, (int64_t) line);
5595 break;
5596
5597 case DW_LNS_set_file:
5598 /* Takes one uleb128 parameter which is stored in file. */
5599 get_uleb128 (u128, linep);
5600 printf (gettext (" set file to %" PRIu64 "\n"),
5601 (uint64_t) u128);
5602 break;
5603
5604 case DW_LNS_set_column:
5605 /* Takes one uleb128 parameter which is stored in column. */
5606 if (unlikely (standard_opcode_lengths[opcode] != 1))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005607 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005608
5609 get_uleb128 (u128, linep);
5610 printf (gettext (" set column to %" PRIu64 "\n"),
5611 (uint64_t) u128);
5612 break;
5613
5614 case DW_LNS_negate_stmt:
5615 /* Takes no argument. */
5616 is_stmt = 1 - is_stmt;
5617 printf (gettext (" set '%s' to %" PRIuFAST8 "\n"),
5618 "is_stmt", is_stmt);
5619 break;
5620
5621 case DW_LNS_set_basic_block:
5622 /* Takes no argument. */
5623 puts (gettext (" set basic block flag"));
5624 break;
5625
5626 case DW_LNS_const_add_pc:
5627 /* Takes no argument. */
5628 u128 = (minimum_instr_len
5629 * ((255 - opcode_base) / line_range));
5630 address += u128;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005631 {
5632 char *a = format_dwarf_addr (dwflmod, 0, address);
5633 printf (gettext ("advance address by constant %u to %s\n"),
5634 u128, a);
5635 free (a);
5636 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005637 break;
5638
5639 case DW_LNS_fixed_advance_pc:
5640 /* Takes one 16 bit parameter which is added to the
5641 address. */
5642 if (unlikely (standard_opcode_lengths[opcode] != 1))
Roland McGrathe4c22ea2007-10-23 13:07:39 +00005643 goto invalid_unit;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005644
5645 u128 = read_2ubyte_unaligned_inc (dbg, linep);
5646 address += u128;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005647 {
5648 char *a = format_dwarf_addr (dwflmod, 0, address);
5649 printf (gettext ("\
5650advance address by fixed value %u to %s\n"),
5651 u128, a);
5652 free (a);
5653 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005654 break;
5655
5656 case DW_LNS_set_prologue_end:
5657 /* Takes no argument. */
5658 puts (gettext (" set prologue end flag"));
5659 break;
5660
Ulrich Drepper6d5c3bd2005-08-11 04:37:52 +00005661 case DW_LNS_set_epilogue_begin:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005662 /* Takes no argument. */
5663 puts (gettext (" set epilogue begin flag"));
5664 break;
5665 }
5666 }
5667 else
5668 {
5669 /* This is a new opcode the generator but not we know about.
5670 Read the parameters associated with it but then discard
5671 everything. Read all the parameters for this opcode. */
5672 printf (ngettext (" unknown opcode with %" PRIu8 " parameter:",
5673 " unknown opcode with %" PRIu8 " parameters:",
5674 standard_opcode_lengths[opcode]),
5675 standard_opcode_lengths[opcode]);
5676 for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
5677 {
5678 get_uleb128 (u128, linep);
5679 if (n != standard_opcode_lengths[opcode])
5680 putc_unlocked (',', stdout);
5681 printf (" %u", u128);
5682 }
5683
5684 /* Next round, ignore this opcode. */
5685 continue;
5686 }
5687 }
5688 }
5689
5690 /* There must only be one data block. */
5691 assert (elf_getdata (scn, data) == NULL);
5692}
5693
5694
5695static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005696print_debug_loc_section (Dwfl_Module *dwflmod,
Ulrich Drepper351bf202009-01-15 20:18:40 -08005697 Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr,
5698 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005699{
5700 Elf_Data *data = elf_rawdata (scn, NULL);
5701
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005702 if (unlikely (data == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005703 {
5704 error (0, 0, gettext ("cannot get .debug_loc content: %s"),
5705 elf_errmsg (-1));
5706 return;
5707 }
5708
5709 printf (gettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08005710\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5711 elf_ndxscn (scn), ".debug_loc", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005712
5713 size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
5714
5715 bool first = true;
5716 unsigned char *readp = data->d_buf;
5717 while (readp < (unsigned char *) data->d_buf + data->d_size)
5718 {
5719 ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
5720
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005721 if (unlikely (data->d_size - offset < address_size * 2))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005722 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005723 printf (gettext (" [%6tx] <INVALID DATA>\n"), offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005724 break;
5725 }
5726
5727 Dwarf_Addr begin;
5728 Dwarf_Addr end;
5729 if (address_size == 8)
5730 {
5731 begin = read_8ubyte_unaligned_inc (dbg, readp);
5732 end = read_8ubyte_unaligned_inc (dbg, readp);
5733 }
5734 else
5735 {
5736 begin = read_4ubyte_unaligned_inc (dbg, readp);
5737 end = read_4ubyte_unaligned_inc (dbg, readp);
5738 if (begin == (Dwarf_Addr) (uint32_t) -1)
5739 begin = (Dwarf_Addr) -1l;
5740 }
5741
5742 if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005743 {
5744 char *b = format_dwarf_addr (dwflmod, address_size, end);
5745 printf (gettext (" [%6tx] base address %s\n"), offset, b);
5746 free (b);
5747 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005748 else if (begin == 0 && end == 0) /* End of list entry. */
5749 first = true;
5750 else
5751 {
5752 /* We have a location expression entry. */
5753 uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
5754
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005755 char *b = format_dwarf_addr (dwflmod, address_size, begin);
5756 char *e = format_dwarf_addr (dwflmod, address_size, end);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005757
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005758 if (first) /* First entry in a list. */
5759 printf (gettext (" [%6tx] %s..%s"), offset, b, e);
5760 else
5761 printf (gettext (" %s..%s"), b, e);
5762
5763 free (b);
5764 free (e);
5765
5766 print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005767 address_size, len, readp);
5768
5769 first = false;
5770 readp += len;
5771 }
5772 }
5773}
5774
5775struct mac_culist
5776{
5777 Dwarf_Die die;
5778 Dwarf_Off offset;
5779 Dwarf_Files *files;
5780 struct mac_culist *next;
5781};
5782
5783
5784static int
5785mac_compare (const void *p1, const void *p2)
5786{
5787 struct mac_culist *m1 = (struct mac_culist *) p1;
5788 struct mac_culist *m2 = (struct mac_culist *) p2;
5789
5790 if (m1->offset < m2->offset)
5791 return -1;
5792 if (m1->offset > m2->offset)
5793 return 1;
5794 return 0;
5795}
5796
5797
5798static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005799print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
5800 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005801 GElf_Ehdr *ehdr __attribute__ ((unused)),
5802 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
5803{
5804 printf (gettext ("\
Ulrich Drepper351bf202009-01-15 20:18:40 -08005805\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5806 elf_ndxscn (scn), ".debug_macinfo", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005807 putc_unlocked ('\n', stdout);
5808
5809 /* There is no function in libdw to iterate over the raw content of
5810 the section but it is easy enough to do. */
5811 Elf_Data *data = elf_getdata (scn, NULL);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005812 if (unlikely (data == NULL || data->d_buf == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005813 {
5814 error (0, 0, gettext ("cannot get macro information section data: %s"),
5815 elf_errmsg (-1));
5816 return;
5817 }
5818
5819 /* Get the source file information for all CUs. */
5820 Dwarf_Off offset;
5821 Dwarf_Off ncu = 0;
5822 size_t hsize;
5823 struct mac_culist *culist = NULL;
5824 size_t nculist = 0;
5825 while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
5826 {
5827 Dwarf_Die cudie;
5828 if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
5829 continue;
5830
5831 Dwarf_Attribute attr;
5832 if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL)
5833 continue;
5834
5835 Dwarf_Word macoff;
5836 if (dwarf_formudata (&attr, &macoff) != 0)
5837 continue;
5838
5839 struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
5840 newp->die = cudie;
5841 newp->offset = macoff;
5842 newp->files = NULL;
5843 newp->next = culist;
5844 culist = newp;
5845 ++nculist;
5846 }
5847
5848 /* Convert the list into an array for easier consumption. */
5849 struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1)
5850 * sizeof (*cus));
5851 /* Add sentinel. */
5852 cus[nculist].offset = data->d_size;
5853 if (nculist > 0)
5854 {
5855 for (size_t cnt = nculist - 1; culist != NULL; --cnt)
5856 {
5857 assert (cnt < nculist);
5858 cus[cnt] = *culist;
5859 culist = culist->next;
5860 }
5861
5862 /* Sort the array according to the offset in the .debug_macinfo
5863 section. Note we keep the sentinel at the end. */
5864 qsort (cus, nculist, sizeof (*cus), mac_compare);
5865 }
5866
5867 const unsigned char *readp = (const unsigned char *) data->d_buf;
5868 const unsigned char *readendp = readp + data->d_size;
5869 int level = 1;
5870
5871 while (readp < readendp)
5872 {
5873 unsigned int opcode = *readp++;
5874 unsigned int u128;
5875 unsigned int u128_2;
5876 const unsigned char *endp;
5877
5878 switch (opcode)
5879 {
5880 case DW_MACINFO_define:
5881 case DW_MACINFO_undef:
5882 case DW_MACINFO_vendor_ext:
5883 /* For the first two opcodes the parameters are
5884 line, string
5885 For the latter
5886 number, string.
5887 We can treat these cases together. */
5888 get_uleb128 (u128, readp);
5889
5890 endp = memchr (readp, '\0', readendp - readp);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005891 if (unlikely (endp == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005892 {
5893 printf (gettext ("\
5894%*s*** non-terminated string at end of section"),
5895 level, "");
5896 return;
5897 }
5898
5899 if (opcode == DW_MACINFO_define)
5900 printf ("%*s#define %s, line %u\n",
5901 level, "", (char *) readp, u128);
5902 else if (opcode == DW_MACINFO_undef)
5903 printf ("%*s#undef %s, line %u\n",
5904 level, "", (char *) readp, u128);
5905 else
5906 printf (" #vendor-ext %s, number %u\n", (char *) readp, u128);
5907
5908 readp = endp + 1;
5909 break;
5910
5911 case DW_MACINFO_start_file:
5912 /* The two parameters are line and file index, in this order. */
5913 get_uleb128 (u128, readp);
5914 get_uleb128 (u128_2, readp);
5915
5916 /* Find the CU DIE for this file. */
5917 size_t macoff = readp - (const unsigned char *) data->d_buf;
5918 const char *fname = "???";
5919 if (macoff >= cus[0].offset)
5920 {
5921 while (macoff >= cus[1].offset)
5922 ++cus;
5923
5924 if (cus[0].files == NULL
5925 && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0)
5926 cus[0].files = (Dwarf_Files *) -1l;
5927
5928 if (cus[0].files != (Dwarf_Files *) -1l)
5929 fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL)
5930 ?: "???");
5931 }
5932
5933 printf ("%*sstart_file %u, [%u] %s\n",
5934 level, "", u128, u128_2, fname);
5935 ++level;
5936 break;
5937
5938 case DW_MACINFO_end_file:
5939 --level;
5940 printf ("%*send_file\n", level, "");
5941 /* Nothing more to do. */
5942 break;
5943
5944 default:
5945 // XXX gcc seems to generate files with a trailing zero.
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00005946 if (unlikely (opcode != 0 || readp != readendp))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005947 printf ("%*s*** invalid opcode %u\n", level, "", opcode);
5948 break;
5949 }
5950 }
5951}
5952
5953
5954/* Callback for printing global names. */
5955static int
5956print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
5957 void *arg)
5958{
5959 int *np = (int *) arg;
5960
5961 printf (gettext (" [%5d] DIE offset: %6" PRId64
5962 ", CU DIE offset: %6" PRId64 ", name: %s\n"),
5963 (*np)++, global->die_offset, global->cu_offset, global->name);
5964
5965 return 0;
5966}
5967
5968
5969/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
5970static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005971print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
5972 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005973 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepper351bf202009-01-15 20:18:40 -08005974 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005975{
Ulrich Drepper351bf202009-01-15 20:18:40 -08005976 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
5977 elf_ndxscn (scn), ".debug_pubnames", (uint64_t) shdr->sh_offset);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005978
5979 int n = 0;
5980 (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
5981}
5982
5983/* Print the content of the DWARF string section '.debug_str'. */
5984static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00005985print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
5986 Ebl *ebl __attribute__ ((unused)),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005987 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepper351bf202009-01-15 20:18:40 -08005988 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00005989{
5990 /* Compute floor(log16(shdr->sh_size)). */
5991 GElf_Addr tmp = shdr->sh_size;
5992 int digits = 1;
5993 while (tmp >= 16)
5994 {
5995 ++digits;
5996 tmp >>= 4;
5997 }
5998 digits = MAX (4, digits);
5999
Ulrich Drepper351bf202009-01-15 20:18:40 -08006000 printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006001 " %*s String\n"),
Ulrich Drepper351bf202009-01-15 20:18:40 -08006002 elf_ndxscn (scn),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006003 ".debug_str", (uint64_t) shdr->sh_offset,
6004 /* TRANS: the debugstr| prefix makes the string unique. */
6005 digits + 2, sgettext ("debugstr|Offset"));
6006
6007 Dwarf_Off offset = 0;
6008 while (offset < shdr->sh_size)
6009 {
6010 size_t len;
6011 const char *str = dwarf_getstring (dbg, offset, &len);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00006012 if (unlikely (str == NULL))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006013 {
6014 printf (gettext (" *** error while reading strings: %s\n"),
6015 dwarf_errmsg (-1));
6016 break;
6017 }
6018
6019 printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str);
6020
6021 offset += len + 1;
6022 }
6023}
6024
Ulrich Drepper351bf202009-01-15 20:18:40 -08006025
Ulrich Drepper351bf202009-01-15 20:18:40 -08006026/* Print the content of the call frame search table section
6027 '.eh_frame_hdr'. */
6028static void
6029print_debug_frame_hdr_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
6030 Ebl *ebl __attribute__ ((unused)),
6031 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08006032 Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
Ulrich Drepper351bf202009-01-15 20:18:40 -08006033{
6034 printf (gettext ("\
6035\nCall frame search table section [%2zu] '.eh_frame_hdr':\n"),
6036 elf_ndxscn (scn));
6037
6038 Elf_Data *data = elf_rawdata (scn, NULL);
6039
6040 if (unlikely (data == NULL))
6041 {
6042 error (0, 0, gettext ("cannot get %s content: %s"),
6043 ".eh_frame_hdr", elf_errmsg (-1));
6044 return;
6045 }
6046
6047 const unsigned char *readp = data->d_buf;
6048 const unsigned char *const dataend = ((unsigned char *) data->d_buf
6049 + data->d_size);
6050
6051 if (unlikely (readp + 4 > dataend))
6052 {
6053 invalid_data:
6054 error (0, 0, gettext ("invalid data"));
6055 return;
6056 }
6057
6058 unsigned int version = *readp++;
6059 unsigned int eh_frame_ptr_enc = *readp++;
6060 unsigned int fde_count_enc = *readp++;
6061 unsigned int table_enc = *readp++;
6062
6063 printf (" version: %u\n"
6064 " eh_frame_ptr_enc: %#x ",
6065 version, eh_frame_ptr_enc);
Ulrich Drepperbc298972009-01-16 11:50:10 -08006066 print_encoding_base ("", eh_frame_ptr_enc);
Ulrich Drepper351bf202009-01-15 20:18:40 -08006067 printf (" fde_count_enc: %#x ", fde_count_enc);
Ulrich Drepperbc298972009-01-16 11:50:10 -08006068 print_encoding_base ("", fde_count_enc);
Ulrich Drepper351bf202009-01-15 20:18:40 -08006069 printf (" table_enc: %#x ", table_enc);
Ulrich Drepperbc298972009-01-16 11:50:10 -08006070 print_encoding_base ("", table_enc);
Ulrich Drepper351bf202009-01-15 20:18:40 -08006071
6072 uint64_t eh_frame_ptr = 0;
6073 if (eh_frame_ptr_enc != DW_EH_PE_omit)
6074 {
6075 readp = read_encoded (eh_frame_ptr_enc, readp, dataend, &eh_frame_ptr,
6076 dbg);
6077 if (unlikely (readp == NULL))
6078 goto invalid_data;
6079
6080 printf (" eh_frame_ptr: %#" PRIx64, eh_frame_ptr);
6081 if ((eh_frame_ptr_enc & 0x70) == DW_EH_PE_pcrel)
6082 printf (" (offset: %#" PRIx64 ")",
6083 /* +4 because of the 4 byte header of the section. */
6084 (uint64_t) shdr->sh_offset + 4 + eh_frame_ptr);
6085
6086 putchar_unlocked ('\n');
6087 }
6088
6089 uint64_t fde_count = 0;
6090 if (fde_count_enc != DW_EH_PE_omit)
6091 {
6092 readp = read_encoded (fde_count_enc, readp, dataend, &fde_count, dbg);
6093 if (unlikely (readp == NULL))
6094 goto invalid_data;
6095
6096 printf (" fde_count: %" PRIu64 "\n", fde_count);
6097 }
6098
6099 if (fde_count == 0 || table_enc == DW_EH_PE_omit)
6100 return;
6101
6102 puts (" Table:");
6103
6104 /* Optimize for the most common case. */
6105 if (table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
6106 while (fde_count > 0 && readp + 8 <= dataend)
6107 {
6108 int32_t initial_location = read_4sbyte_unaligned_inc (dbg, readp);
6109 uint64_t initial_offset = ((uint64_t) shdr->sh_offset
6110 + (int64_t) initial_location);
6111 int32_t address = read_4sbyte_unaligned_inc (dbg, readp);
6112 // XXX Possibly print symbol name or section offset for initial_offset
6113 printf (" %#" PRIx32 " (offset: %#6" PRIx64 ") -> %#" PRIx32
6114 " fde=[%6" PRIx64 "]\n",
6115 initial_location, initial_offset,
6116 address, address - (eh_frame_ptr + 4));
6117 }
6118 else
6119 while (0 && readp < dataend)
6120 {
6121
6122 }
6123}
6124
6125
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08006126/* Print the content of the exception handling table section
6127 '.eh_frame_hdr'. */
6128static void
6129print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
6130 Ebl *ebl __attribute__ ((unused)),
6131 GElf_Ehdr *ehdr __attribute__ ((unused)),
Ulrich Drepper05d2b202009-01-16 17:58:54 -08006132 Elf_Scn *scn,
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08006133 GElf_Shdr *shdr __attribute__ ((unused)),
6134 Dwarf *dbg __attribute__ ((unused)))
6135{
6136 printf (gettext ("\
6137\nException handling table section [%2zu] '.gcc_except_table':\n"),
6138 elf_ndxscn (scn));
6139
6140 Elf_Data *data = elf_rawdata (scn, NULL);
6141
6142 if (unlikely (data == NULL))
6143 {
6144 error (0, 0, gettext ("cannot get %s content: %s"),
6145 ".gcc_except_table", elf_errmsg (-1));
6146 return;
6147 }
Ulrich Drepper05d2b202009-01-16 17:58:54 -08006148
6149 const unsigned char *readp = data->d_buf;
6150 const unsigned char *const dataend = readp + data->d_size;
6151
6152 if (unlikely (readp + 1 > dataend))
6153 {
6154 invalid_data:
6155 error (0, 0, gettext ("invalid data"));
6156 return;
6157 }
6158 unsigned int lpstart_encoding = *readp++;
6159 printf (gettext (" LPStart encoding: %#x "), lpstart_encoding);
6160 print_encoding_base ("", lpstart_encoding);
6161 if (lpstart_encoding != DW_EH_PE_omit)
6162 {
6163 uint64_t lpstart;
6164 readp = read_encoded (lpstart_encoding, readp, dataend, &lpstart, dbg);
6165 printf (" LPStart: %#" PRIx64 "\n", lpstart);
6166 }
6167
6168 if (unlikely (readp + 1 > dataend))
6169 goto invalid_data;
6170 unsigned int ttype_encoding = *readp++;
6171 printf (gettext (" TType encoding: %#x "), ttype_encoding);
6172 print_encoding_base ("", ttype_encoding);
6173 const unsigned char *ttype_base = NULL;
6174 if (ttype_encoding != DW_EH_PE_omit)
6175 {
6176 unsigned int ttype_base_offset;
6177 get_uleb128 (ttype_base_offset, readp);
6178 printf (" TType base offset: %#x\n", ttype_base_offset);
6179 ttype_base = readp + ttype_base_offset;
6180 }
6181
6182 if (unlikely (readp + 1 > dataend))
6183 goto invalid_data;
6184 unsigned int call_site_encoding = *readp++;
6185 printf (gettext (" Call site encoding: %#x "), call_site_encoding);
6186 print_encoding_base ("", call_site_encoding);
6187 unsigned int call_site_table_len;
6188 get_uleb128 (call_site_table_len, readp);
6189
6190 const unsigned char *const action_table = readp + call_site_table_len;
6191 if (unlikely (action_table > dataend))
6192 goto invalid_data;
6193 unsigned int u = 0;
6194 unsigned int max_action = 0;
6195 while (readp < action_table)
6196 {
6197 if (u == 0)
6198 puts (gettext ("\n Call site table:"));
6199
6200 uint64_t call_site_start;
6201 readp = read_encoded (call_site_encoding, readp, dataend,
6202 &call_site_start, dbg);
6203 uint64_t call_site_length;
6204 readp = read_encoded (call_site_encoding, readp, dataend,
6205 &call_site_length, dbg);
6206 uint64_t landing_pad;
6207 readp = read_encoded (call_site_encoding, readp, dataend,
6208 &landing_pad, dbg);
6209 unsigned int action;
6210 get_uleb128 (action, readp);
6211 max_action = MAX (action, max_action);
6212 printf (gettext (" [%4u] Call site start: %#" PRIx64 "\n"
6213 " Call site length: %" PRIu64 "\n"
6214 " Landing pad: %#" PRIx64 "\n"
6215 " Action: %u\n"),
6216 u++, call_site_start, call_site_length, landing_pad, action);
6217 }
6218 assert (readp == action_table);
6219
6220 unsigned int max_ar_filter = 0;
6221 if (max_action > 0)
6222 {
6223 puts ("\n Action table:");
6224
6225 const unsigned char *const action_table_end
6226 = action_table + max_action + 1;
6227
6228 u = 0;
6229 do
6230 {
6231 int ar_filter;
6232 get_sleb128 (ar_filter, readp);
6233 if (ar_filter > 0 && (unsigned int) ar_filter > max_ar_filter)
6234 max_ar_filter = ar_filter;
6235 int ar_disp;
6236 get_sleb128 (ar_disp, readp);
6237
Ulrich Drepper935edde2009-01-17 16:06:42 -08006238 printf (" [%4u] ar_filter: % d\n"
6239 " ar_disp: % -5d",
6240 u, ar_filter, ar_disp);
6241 if (abs (ar_disp) & 1)
6242 printf (" -> [%4u]\n", u + (ar_disp + 1) / 2);
6243 else if (ar_disp != 0)
6244 puts (" -> ???");
6245 else
6246 putchar_unlocked ('\n');
6247 ++u;
Ulrich Drepper05d2b202009-01-16 17:58:54 -08006248 }
6249 while (readp < action_table_end);
6250 }
6251
6252 if (max_ar_filter > 0)
6253 {
6254 puts ("\n TType table:");
6255
6256 // XXX Not *4, size of encoding;
6257 switch (ttype_encoding & 7)
6258 {
6259 case DW_EH_PE_udata2:
6260 case DW_EH_PE_sdata2:
6261 readp = ttype_base - max_ar_filter * 2;
6262 break;
6263 case DW_EH_PE_udata4:
6264 case DW_EH_PE_sdata4:
6265 readp = ttype_base - max_ar_filter * 4;
6266 break;
6267 case DW_EH_PE_udata8:
6268 case DW_EH_PE_sdata8:
6269 readp = ttype_base - max_ar_filter * 8;
6270 break;
6271 default:
6272 error (1, 0, gettext ("invalid TType encoding"));
6273 }
6274
6275 do
6276 {
6277 uint64_t ttype;
6278 readp = read_encoded (ttype_encoding, readp, ttype_base, &ttype,
6279 dbg);
6280 printf (" [%4u] %#" PRIx64 "\n", max_ar_filter--, ttype);
6281 }
6282 while (readp < ttype_base);
6283 }
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08006284}
6285
6286
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006287static void
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006288print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006289{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006290 /* Before we start the real work get a debug context descriptor. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006291 Dwarf_Addr dwbias;
6292 Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006293 if (dbg == NULL)
6294 {
6295 error (0, 0, gettext ("cannot get debug context descriptor: %s"),
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006296 dwfl_errmsg (-1));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006297 return;
6298 }
6299
6300 /* Get the section header string table index. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006301 size_t shstrndx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00006302 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006303 error (EXIT_FAILURE, 0,
6304 gettext ("cannot get section header string table index"));
6305
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006306 /* Look through all the sections for the debugging sections to print. */
6307 Elf_Scn *scn = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006308 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
6309 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006310 GElf_Shdr shdr_mem;
6311 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
6312
Ulrich Drepper903c1162007-02-15 19:40:37 +00006313 if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006314 {
6315 static const struct
6316 {
6317 const char *name;
6318 enum section_e bitmask;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006319 void (*fp) (Dwfl_Module *, Ebl *,
6320 GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006321 } debug_sections[] =
6322 {
6323#define NEW_SECTION(name) \
6324 { ".debug_" #name, section_##name, print_debug_##name##_section }
6325 NEW_SECTION (abbrev),
6326 NEW_SECTION (aranges),
6327 NEW_SECTION (frame),
6328 NEW_SECTION (info),
6329 NEW_SECTION (line),
6330 NEW_SECTION (loc),
6331 NEW_SECTION (pubnames),
6332 NEW_SECTION (str),
6333 NEW_SECTION (macinfo),
6334 NEW_SECTION (ranges),
Ulrich Drepperb006fbf2009-01-16 03:08:25 -08006335 { ".eh_frame", section_frame | section_exception,
6336 print_debug_frame_section },
6337 { ".eh_frame_hdr", section_frame | section_exception,
6338 print_debug_frame_hdr_section },
6339 { ".gcc_except_table", section_frame | section_exception,
6340 print_debug_exception_table }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006341 };
6342 const int ndebug_sections = (sizeof (debug_sections)
6343 / sizeof (debug_sections[0]));
6344 const char *name = elf_strptr (ebl->elf, shstrndx,
6345 shdr->sh_name);
6346 int n;
6347
6348 for (n = 0; n < ndebug_sections; ++n)
6349 if (strcmp (name, debug_sections[n].name) == 0)
6350 {
6351 if (print_debug_sections & debug_sections[n].bitmask)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006352 debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006353 break;
6354 }
6355 }
6356 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00006357}
6358
6359
Roland McGrathcb6d8652007-08-23 08:10:54 +00006360#define ITEM_INDENT 4
6361#define ITEM_WRAP_COLUMN 150
6362#define REGISTER_WRAP_COLUMN 75
6363
6364/* Print "NAME: FORMAT", wrapping when FORMAT_MAX chars of FORMAT would
6365 make the line exceed ITEM_WRAP_COLUMN. Unpadded numbers look better
6366 for the core items. But we do not want the line breaks to depend on
6367 the particular values. */
6368static unsigned int
6369__attribute__ ((format (printf, 7, 8)))
6370print_core_item (unsigned int colno, char sep, unsigned int wrap,
6371 size_t name_width, const char *name,
6372 size_t format_max, const char *format, ...)
6373{
6374 size_t len = strlen (name);
6375 if (name_width < len)
6376 name_width = len;
6377
6378 size_t n = name_width + sizeof ": " - 1 + format_max;
6379
6380 if (colno == 0)
6381 {
6382 printf ("%*s", ITEM_INDENT, "");
6383 colno = ITEM_INDENT + n;
6384 }
6385 else if (colno + 2 + n < wrap)
6386 {
6387 printf ("%c ", sep);
6388 colno += 2 + n;
6389 }
6390 else
6391 {
6392 printf ("\n%*s", ITEM_INDENT, "");
6393 colno = ITEM_INDENT + n;
6394 }
6395
6396 printf ("%s: %*s", name, (int) (name_width - len), "");
6397
6398 va_list ap;
6399 va_start (ap, format);
6400 vprintf (format, ap);
6401 va_end (ap);
6402
6403 return colno;
6404}
6405
6406static const void *
6407convert (Elf *core, Elf_Type type, uint_fast16_t count,
Roland McGrath1d8bb252008-08-07 08:39:41 +00006408 void *value, const void *data, size_t size)
Roland McGrathcb6d8652007-08-23 08:10:54 +00006409{
6410 Elf_Data valuedata =
6411 {
6412 .d_type = type,
6413 .d_buf = value,
Roland McGrath1d8bb252008-08-07 08:39:41 +00006414 .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT),
Roland McGrathcb6d8652007-08-23 08:10:54 +00006415 .d_version = EV_CURRENT,
6416 };
6417 Elf_Data indata =
6418 {
6419 .d_type = type,
6420 .d_buf = (void *) data,
6421 .d_size = valuedata.d_size,
6422 .d_version = EV_CURRENT,
6423 };
6424
6425 Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
6426 ? elf32_xlatetom : elf64_xlatetom)
6427 (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
6428 if (d == NULL)
6429 error (EXIT_FAILURE, 0,
6430 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
6431
6432 return data + indata.d_size;
6433}
6434
6435typedef uint8_t GElf_Byte;
6436
6437static unsigned int
6438handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
Roland McGrath1d8bb252008-08-07 08:39:41 +00006439 unsigned int colno, size_t *repeated_size)
Roland McGrathcb6d8652007-08-23 08:10:54 +00006440{
6441 uint_fast16_t count = item->count ?: 1;
6442
6443#define TYPES \
6444 DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8, 4); \
6445 DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16, 6); \
6446 DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32, 11); \
6447 DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32, 11); \
6448 DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64, 20); \
6449 DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64, 20)
6450
6451#define DO_TYPE(NAME, Name, hex, dec, max) GElf_##Name Name[count]
6452 union { TYPES; } value;
6453#undef DO_TYPE
6454
Roland McGrath1d8bb252008-08-07 08:39:41 +00006455 void *data = &value;
6456 size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
6457 size_t convsize = size;
6458 if (repeated_size != NULL)
6459 {
6460 if (*repeated_size > size && (item->format == 'b' || item->format == 'B'))
6461 {
6462 data = alloca (*repeated_size);
6463 count *= *repeated_size / size;
6464 convsize = count * size;
6465 *repeated_size -= convsize;
6466 }
6467 else
6468 *repeated_size -= size;
6469 }
6470
6471 desc = convert (core, item->type, count, data, desc + item->offset, convsize);
6472
6473 Elf_Type type = item->type;
6474 if (type == ELF_T_ADDR)
6475 type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD;
Roland McGrathcb6d8652007-08-23 08:10:54 +00006476
6477 switch (item->format)
6478 {
6479 case 'd':
6480 assert (count == 1);
Roland McGrath1d8bb252008-08-07 08:39:41 +00006481 switch (type)
Roland McGrathcb6d8652007-08-23 08:10:54 +00006482 {
6483#define DO_TYPE(NAME, Name, hex, dec, max) \
6484 case ELF_T_##NAME: \
6485 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
6486 0, item->name, max, dec, value.Name[0]); \
6487 break
6488 TYPES;
6489#undef DO_TYPE
6490 default:
6491 abort ();
6492 }
6493 break;
6494
6495 case 'x':
6496 assert (count == 1);
Roland McGrath1d8bb252008-08-07 08:39:41 +00006497 switch (type)
Roland McGrathcb6d8652007-08-23 08:10:54 +00006498 {
6499#define DO_TYPE(NAME, Name, hex, dec, max) \
6500 case ELF_T_##NAME: \
6501 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
6502 0, item->name, max, hex, value.Name[0]); \
6503 break
6504 TYPES;
6505#undef DO_TYPE
6506 default:
6507 abort ();
6508 }
6509 break;
6510
6511 case 'b':
Roland McGrath1d8bb252008-08-07 08:39:41 +00006512 case 'B':
6513 assert (size % sizeof (unsigned int) == 0);
6514 unsigned int nbits = count * size * 8;
6515 unsigned int pop = 0;
6516 for (const unsigned int *i = data; (void *) i < data + count * size; ++i)
6517 pop += __builtin_popcount (*i);
6518 bool negate = pop > nbits / 2;
6519 const unsigned int bias = item->format == 'b';
6520
6521 {
6522 char printed[(negate ? nbits - pop : pop) * 16];
6523 char *p = printed;
6524 *p = '\0';
6525
6526 if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int))
6527 {
6528 assert (size == sizeof (unsigned int) * 2);
6529 for (unsigned int *i = data;
6530 (void *) i < data + count * size; i += 2)
6531 {
6532 unsigned int w = i[1];
6533 i[1] = i[0];
6534 i[0] = w;
6535 }
6536 }
6537
6538 unsigned int lastbit = 0;
6539 for (const unsigned int *i = data;
6540 (void *) i < data + count * size; ++i)
6541 {
6542 unsigned int bit = ((void *) i - data) * 8;
6543 unsigned int w = negate ? ~*i : *i;
6544 while (w != 0)
6545 {
6546 int n = ffs (w);
6547 w >>= n;
6548 bit += n;
6549
6550 if (lastbit + 1 != bit)
6551 p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias);
6552 else if (lastbit == 0)
6553 p += sprintf (p, "%u", bit - bias);
6554
6555 lastbit = bit;
6556 }
6557 }
6558 if (lastbit > 0 && lastbit + 1 != nbits)
6559 p += sprintf (p, "-%u", nbits - bias);
6560
6561 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
6562 4 + nbits * 4,
6563 negate ? "~<%s>" : "<%s>", printed);
6564 }
Roland McGrathcb6d8652007-08-23 08:10:54 +00006565 break;
6566
6567 case 'T':
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006568 case (char) ('T'|0x80):
Roland McGrathcb6d8652007-08-23 08:10:54 +00006569 assert (count == 2);
6570 Dwarf_Word sec;
6571 Dwarf_Word usec;
6572 size_t maxfmt = 7;
Roland McGrath1d8bb252008-08-07 08:39:41 +00006573 switch (type)
Roland McGrathcb6d8652007-08-23 08:10:54 +00006574 {
6575#define DO_TYPE(NAME, Name, hex, dec, max) \
6576 case ELF_T_##NAME: \
6577 sec = value.Name[0]; \
6578 usec = value.Name[1]; \
6579 maxfmt += max; \
6580 break
6581 TYPES;
6582#undef DO_TYPE
6583 default:
6584 abort ();
6585 }
Ulrich Drepperb597dfa2007-10-16 05:21:27 +00006586 if (unlikely (item->format == (char) ('T'|0x80)))
6587 {
6588 /* This is a hack for an ill-considered 64-bit ABI where
6589 tv_usec is actually a 32-bit field with 32 bits of padding
6590 rounding out struct timeval. We've already converted it as
6591 a 64-bit field. For little-endian, this just means the
6592 high half is the padding; it's presumably zero, but should
6593 be ignored anyway. For big-endian, it means the 32-bit
6594 field went into the high half of USEC. */
6595 GElf_Ehdr ehdr_mem;
6596 GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
6597 if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
6598 usec >>= 32;
6599 else
6600 usec &= UINT32_MAX;
6601 }
Roland McGrathcb6d8652007-08-23 08:10:54 +00006602 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
6603 maxfmt, "%" PRIu64 ".%.6" PRIu64, sec, usec);
6604 break;
6605
6606 case 'c':
6607 assert (count == 1);
6608 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
6609 1, "%c", value.Byte[0]);
6610 break;
6611
6612 case 's':
6613 colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
6614 count, "%.*s", (int) count, value.Byte);
6615 break;
6616
6617 default:
6618 error (0, 0, "XXX not handling format '%c' for %s",
6619 item->format, item->name);
6620 break;
6621 }
6622
6623#undef TYPES
6624
6625 return colno;
6626}
6627
6628
6629/* Sort items by group, and by layout offset within each group. */
6630static int
6631compare_core_items (const void *a, const void *b)
6632{
6633 const Ebl_Core_Item *const *p1 = a;
6634 const Ebl_Core_Item *const *p2 = b;
6635 const Ebl_Core_Item *item1 = *p1;
6636 const Ebl_Core_Item *item2 = *p2;
6637
6638 return ((item1->group == item2->group ? 0
6639 : strcmp (item1->group, item2->group))
6640 ?: (int) item1->offset - (int) item2->offset);
6641}
6642
6643/* Sort item groups by layout offset of the first item in the group. */
6644static int
6645compare_core_item_groups (const void *a, const void *b)
6646{
6647 const Ebl_Core_Item *const *const *p1 = a;
6648 const Ebl_Core_Item *const *const *p2 = b;
6649 const Ebl_Core_Item *const *group1 = *p1;
6650 const Ebl_Core_Item *const *group2 = *p2;
6651 const Ebl_Core_Item *item1 = *group1;
6652 const Ebl_Core_Item *item2 = *group2;
6653
6654 return (int) item1->offset - (int) item2->offset;
6655}
6656
6657static unsigned int
Roland McGrath059c83e2008-02-21 06:19:39 +00006658handle_core_items (Elf *core, const void *desc, size_t descsz,
Roland McGrathcb6d8652007-08-23 08:10:54 +00006659 const Ebl_Core_Item *items, size_t nitems)
6660{
6661 if (nitems == 0)
6662 return 0;
6663
6664 /* Sort to collect the groups together. */
6665 const Ebl_Core_Item *sorted_items[nitems];
6666 for (size_t i = 0; i < nitems; ++i)
6667 sorted_items[i] = &items[i];
6668 qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
6669
6670 /* Collect the unique groups and sort them. */
6671 const Ebl_Core_Item **groups[nitems];
6672 groups[0] = &sorted_items[0];
6673 size_t ngroups = 1;
6674 for (size_t i = 1; i < nitems; ++i)
6675 if (sorted_items[i]->group != sorted_items[i - 1]->group
6676 && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
6677 groups[ngroups++] = &sorted_items[i];
6678 qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
6679
6680 /* Write out all the groups. */
6681 unsigned int colno = 0;
Roland McGrathcb6d8652007-08-23 08:10:54 +00006682
Roland McGrath1d8bb252008-08-07 08:39:41 +00006683 const void *last = desc;
6684 if (nitems == 1)
6685 {
6686 size_t size = descsz;
6687 colno = handle_core_item (core, sorted_items[0], desc, colno, &size);
6688 if (size == 0)
6689 return colno;
6690 desc += descsz - size;
6691 descsz = size;
6692 }
6693
Roland McGrath059c83e2008-02-21 06:19:39 +00006694 do
6695 {
6696 for (size_t i = 0; i < ngroups; ++i)
6697 {
6698 for (const Ebl_Core_Item **item = groups[i];
6699 (item < &sorted_items[nitems]
6700 && ((*item)->group == groups[i][0]->group
6701 || !strcmp ((*item)->group, groups[i][0]->group)));
6702 ++item)
Roland McGrath1d8bb252008-08-07 08:39:41 +00006703 colno = handle_core_item (core, *item, desc, colno, NULL);
Roland McGrath059c83e2008-02-21 06:19:39 +00006704
6705 /* Force a line break at the end of the group. */
6706 colno = ITEM_WRAP_COLUMN;
6707 }
6708
6709 if (descsz == 0)
6710 break;
6711
6712 /* This set of items consumed a certain amount of the note's data.
6713 If there is more data there, we have another unit of the same size.
6714 Loop to print that out too. */
6715 const Ebl_Core_Item *item = &items[nitems - 1];
6716 size_t eltsz = item->offset + gelf_fsize (core, item->type,
6717 item->count ?: 1, EV_CURRENT);
Roland McGrath1d8bb252008-08-07 08:39:41 +00006718
6719 int reps = -1;
6720 do
6721 {
6722 ++reps;
6723 desc += eltsz;
6724 descsz -= eltsz;
6725 }
6726 while (descsz >= eltsz && !memcmp (desc, last, eltsz));
6727
6728 if (reps == 1)
6729 {
6730 /* For just one repeat, print it unabridged twice. */
6731 desc -= eltsz;
6732 descsz += eltsz;
6733 }
6734 else if (reps > 1)
6735 printf (gettext ("\n%*s... <repeats %u more times> ..."),
6736 ITEM_INDENT, "", reps);
6737
6738 last = desc;
Roland McGrathcb6d8652007-08-23 08:10:54 +00006739 }
Roland McGrath059c83e2008-02-21 06:19:39 +00006740 while (descsz > 0);
Roland McGrathcb6d8652007-08-23 08:10:54 +00006741
6742 return colno;
6743}
6744
6745static unsigned int
6746handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
6747 unsigned int colno)
6748{
6749 desc += regloc->offset;
6750
6751 abort (); /* XXX */
6752 return colno;
6753}
6754
6755
6756static unsigned int
6757handle_core_register (Ebl *ebl, Elf *core, int maxregname,
6758 const Ebl_Register_Location *regloc, const void *desc,
6759 unsigned int colno)
6760{
6761 if (regloc->bits % 8 != 0)
6762 return handle_bit_registers (regloc, desc, colno);
6763
6764 desc += regloc->offset;
6765
6766 for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
6767 {
6768 const char *pfx;
6769 const char *set;
6770 char name[16];
6771 int bits;
6772 int type;
6773 ssize_t n = ebl_register_info (ebl, reg, name, sizeof name,
6774 &pfx, &set, &bits, &type);
6775 if (n <= 0)
6776 error (EXIT_FAILURE, 0,
6777 gettext ("unable to handle register number %d"),
6778 regloc->regno);
6779
6780#define TYPES \
6781 BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8, 4); \
6782 BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16, 6); \
6783 BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32, 11); \
6784 BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64, 20)
6785
6786#define BITS(bits, xtype, sfmt, ufmt, max) \
6787 uint##bits##_t b##bits; int##bits##_t b##bits##s
6788 union { TYPES; uint64_t b128[2]; } value;
6789#undef BITS
6790
6791 switch (type)
6792 {
6793 case DW_ATE_unsigned:
6794 case DW_ATE_signed:
6795 case DW_ATE_address:
6796 switch (bits)
6797 {
6798#define BITS(bits, xtype, sfmt, ufmt, max) \
6799 case bits: \
Roland McGrath1d8bb252008-08-07 08:39:41 +00006800 desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0); \
Roland McGrathcb6d8652007-08-23 08:10:54 +00006801 if (type == DW_ATE_signed) \
6802 colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
6803 maxregname, name, \
6804 max, sfmt, value.b##bits##s); \
6805 else \
6806 colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
6807 maxregname, name, \
6808 max, ufmt, value.b##bits); \
6809 break
6810
6811 TYPES;
6812
6813 case 128:
6814 assert (type == DW_ATE_unsigned);
Roland McGrath1d8bb252008-08-07 08:39:41 +00006815 desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0);
Roland McGrathcb6d8652007-08-23 08:10:54 +00006816 int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
6817 colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
6818 maxregname, name,
6819 34, "0x%.16" PRIx64 "%.16" PRIx64,
6820 value.b128[!be], value.b128[be]);
6821 break;
6822
6823 default:
6824 abort ();
6825#undef BITS
6826 }
6827 break;
6828
6829 default:
6830 /* Print each byte in hex, the whole thing in native byte order. */
6831 assert (bits % 8 == 0);
6832 const uint8_t *bytes = desc;
6833 desc += bits / 8;
6834 char hex[bits / 4 + 1];
6835 hex[bits / 4] = '\0';
6836 int incr = 1;
6837 if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
6838 {
6839 bytes += bits / 8 - 1;
6840 incr = -1;
6841 }
6842 size_t idx = 0;
6843 for (char *h = hex; bits > 0; bits -= 8, idx += incr)
6844 {
6845 *h++ = "0123456789abcdef"[bytes[idx] >> 4];
6846 *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
6847 }
6848 colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
6849 maxregname, name,
6850 2 + sizeof hex - 1, "0x%s", hex);
6851 break;
6852 }
6853 desc += regloc->pad;
6854
6855#undef TYPES
6856 }
6857
6858 return colno;
6859}
6860
6861
6862struct register_info
6863{
6864 const Ebl_Register_Location *regloc;
6865 const char *set;
6866 char name[16];
6867 Dwarf_Half regno;
6868 uint8_t bits;
6869 uint8_t type;
6870};
6871
6872static int
6873register_bitpos (const struct register_info *r)
6874{
6875 return (r->regloc->offset * 8
6876 + ((r->regno - r->regloc->regno)
6877 * (r->regloc->bits + r->regloc->pad * 8)));
6878}
6879
6880static int
6881compare_sets_by_info (const struct register_info *r1,
6882 const struct register_info *r2)
6883{
6884 return ((int) r2->bits - (int) r1->bits
6885 ?: register_bitpos (r1) - register_bitpos (r2));
6886}
6887
6888/* Sort registers by set, and by size and layout offset within each set. */
6889static int
6890compare_registers (const void *a, const void *b)
6891{
6892 const struct register_info *r1 = a;
6893 const struct register_info *r2 = b;
6894
6895 /* Unused elements sort last. */
6896 if (r1->regloc == NULL)
6897 return r2->regloc == NULL ? 0 : 1;
6898 if (r2->regloc == NULL)
6899 return -1;
6900
6901 return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
6902 ?: compare_sets_by_info (r1, r2));
6903}
6904
6905/* Sort register sets by layout offset of the first register in the set. */
6906static int
6907compare_register_sets (const void *a, const void *b)
6908{
6909 const struct register_info *const *p1 = a;
6910 const struct register_info *const *p2 = b;
6911 return compare_sets_by_info (*p1, *p2);
6912}
6913
6914static unsigned int
6915handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
6916 const Ebl_Register_Location *reglocs, size_t nregloc)
6917{
6918 if (nregloc == 0)
6919 return 0;
6920
6921 ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
6922 if (maxnreg <= 0)
6923 error (EXIT_FAILURE, 0,
6924 gettext ("cannot register info: %s"), elf_errmsg (-1));
6925
6926 struct register_info regs[maxnreg];
6927 memset (regs, 0, sizeof regs);
6928
6929 /* Sort to collect the sets together. */
6930 int maxreg = 0;
6931 for (size_t i = 0; i < nregloc; ++i)
6932 for (int reg = reglocs[i].regno;
6933 reg < reglocs[i].regno + reglocs[i].count;
6934 ++reg)
6935 {
6936 assert (reg < maxnreg);
6937 if (reg > maxreg)
6938 maxreg = reg;
6939 struct register_info *info = &regs[reg];
6940
6941 const char *pfx;
6942 int bits;
6943 int type;
6944 ssize_t n = ebl_register_info (ebl, reg, info->name, sizeof info->name,
6945 &pfx, &info->set, &bits, &type);
6946 if (n <= 0)
6947 error (EXIT_FAILURE, 0,
6948 gettext ("cannot register info: %s"), elf_errmsg (-1));
6949
6950 info->regloc = &reglocs[i];
6951 info->regno = reg;
6952 info->bits = bits;
6953 info->type = type;
6954 }
6955 qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
6956
6957 /* Collect the unique sets and sort them. */
6958 inline bool same_set (const struct register_info *a,
6959 const struct register_info *b)
6960 {
6961 return (a < &regs[maxnreg] && a->regloc != NULL
6962 && b < &regs[maxnreg] && b->regloc != NULL
6963 && a->bits == b->bits
6964 && (a->set == b->set || !strcmp (a->set, b->set)));
6965 }
6966 struct register_info *sets[maxreg + 1];
6967 sets[0] = &regs[0];
6968 size_t nsets = 1;
6969 for (int i = 1; i <= maxreg; ++i)
6970 if (regs[i].regloc != NULL && !same_set (&regs[i], &regs[i - 1]))
6971 sets[nsets++] = &regs[i];
6972 qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
6973
6974 /* Write out all the sets. */
6975 unsigned int colno = 0;
6976 for (size_t i = 0; i < nsets; ++i)
6977 {
6978 /* Find the longest name of a register in this set. */
6979 size_t maxname = 0;
6980 const struct register_info *end;
6981 for (end = sets[i]; same_set (sets[i], end); ++end)
6982 {
6983 size_t len = strlen (end->name);
6984 if (len > maxname)
6985 maxname = len;
6986 }
6987
6988 for (const struct register_info *reg = sets[i];
6989 reg < end;
6990 reg += reg->regloc->count ?: 1)
6991 colno = handle_core_register (ebl, core, maxname,
6992 reg->regloc, desc, colno);
6993
6994 /* Force a line break at the end of the group. */
6995 colno = REGISTER_WRAP_COLUMN;
6996 }
6997
6998 return colno;
6999}
7000
7001static void
Roland McGrath59ea7f32007-10-04 08:50:09 +00007002handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
Roland McGrathcb6d8652007-08-23 08:10:54 +00007003{
Roland McGrath59ea7f32007-10-04 08:50:09 +00007004 Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV);
7005 if (data == NULL)
7006 elf_error:
7007 error (EXIT_FAILURE, 0,
7008 gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
7009
Roland McGrathcb6d8652007-08-23 08:10:54 +00007010 const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT);
7011 for (size_t i = 0; i < nauxv; ++i)
7012 {
Roland McGrath59ea7f32007-10-04 08:50:09 +00007013 GElf_auxv_t av_mem;
7014 GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem);
7015 if (av == NULL)
7016 goto elf_error;
Roland McGrathcb6d8652007-08-23 08:10:54 +00007017
7018 const char *name;
7019 const char *fmt;
7020 if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
7021 {
7022 /* Unknown type. */
7023 if (av->a_un.a_val == 0)
7024 printf (" %" PRIu64 "\n", av->a_type);
7025 else
7026 printf (" %" PRIu64 ": %#" PRIx64 "\n",
7027 av->a_type, av->a_un.a_val);
7028 }
7029 else
7030 switch (fmt[0])
7031 {
7032 case '\0': /* Normally zero. */
7033 if (av->a_un.a_val == 0)
7034 {
7035 printf (" %s\n", name);
7036 break;
7037 }
7038 /* Fall through */
7039 case 'x': /* hex */
7040 case 'p': /* address */
7041 case 's': /* address of string */
7042 printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val);
7043 break;
7044 case 'u':
7045 printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val);
7046 break;
7047 case 'd':
7048 printf (" %s: %" PRId64 "\n", name, av->a_un.a_val);
7049 break;
7050
7051 case 'b':
7052 printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val);
7053 GElf_Xword bit = 1;
7054 const char *pfx = "<";
7055 for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
7056 {
7057 if (av->a_un.a_val & bit)
7058 {
7059 printf ("%s%s", pfx, p);
7060 pfx = " ";
7061 }
7062 bit <<= 1;
7063 }
7064 printf (">\n");
7065 break;
7066
7067 default:
7068 abort ();
7069 }
7070 }
7071}
7072
7073static void
7074handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc)
7075{
7076 GElf_Word regs_offset;
7077 size_t nregloc;
7078 const Ebl_Register_Location *reglocs;
7079 size_t nitems;
7080 const Ebl_Core_Item *items;
7081
7082 if (! ebl_core_note (ebl, nhdr->n_type, nhdr->n_descsz,
7083 &regs_offset, &nregloc, &reglocs, &nitems, &items))
7084 return;
7085
Roland McGrath059c83e2008-02-21 06:19:39 +00007086 /* Pass 0 for DESCSZ when there are registers in the note,
7087 so that the ITEMS array does not describe the whole thing.
7088 For non-register notes, the actual descsz might be a multiple
7089 of the unit size, not just exactly the unit size. */
7090 unsigned int colno = handle_core_items (ebl->elf, desc,
7091 nregloc == 0 ? nhdr->n_descsz : 0,
7092 items, nitems);
Roland McGrathcb6d8652007-08-23 08:10:54 +00007093 if (colno != 0)
7094 putchar_unlocked ('\n');
7095
7096 colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
7097 reglocs, nregloc);
7098 if (colno != 0)
7099 putchar_unlocked ('\n');
7100}
7101
Roland McGrath59ea7f32007-10-04 08:50:09 +00007102static void
7103handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
7104 GElf_Off start, Elf_Data *data)
7105{
7106 fputs_unlocked (gettext (" Owner Data size Type\n"), stdout);
7107
7108 if (data == NULL)
7109 goto bad_note;
7110
7111 size_t offset = 0;
7112 GElf_Nhdr nhdr;
7113 size_t name_offset;
7114 size_t desc_offset;
7115 while (offset < data->d_size
7116 && (offset = gelf_getnote (data, offset,
7117 &nhdr, &name_offset, &desc_offset)) > 0)
7118 {
7119 const char *name = data->d_buf + name_offset;
7120 const char *desc = data->d_buf + desc_offset;
7121
7122 char buf[100];
7123 char buf2[100];
7124 printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
7125 (int) nhdr.n_namesz, name, nhdr.n_descsz,
7126 ehdr->e_type == ET_CORE
7127 ? ebl_core_note_type_name (ebl, nhdr.n_type,
7128 buf, sizeof (buf))
7129 : ebl_object_note_type_name (ebl, nhdr.n_type,
7130 buf2, sizeof (buf2)));
7131
7132 /* Filter out invalid entries. */
7133 if (memchr (name, '\0', nhdr.n_namesz) != NULL
7134 /* XXX For now help broken Linux kernels. */
7135 || 1)
7136 {
7137 if (ehdr->e_type == ET_CORE)
7138 {
7139 if (nhdr.n_type == NT_AUXV)
7140 handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz,
7141 start + desc_offset);
7142 else
7143 handle_core_note (ebl, &nhdr, desc);
7144 }
7145 else
7146 ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
7147 }
7148 }
7149
7150 if (offset == data->d_size)
7151 return;
7152
7153 bad_note:
7154 error (EXIT_FAILURE, 0,
7155 gettext ("cannot get content of note section: %s"),
7156 elf_errmsg (-1));
7157}
Roland McGrathcb6d8652007-08-23 08:10:54 +00007158
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007159static void
7160handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
7161{
Roland McGrath59ea7f32007-10-04 08:50:09 +00007162 /* If we have section headers, just look for SHT_NOTE sections.
7163 In a debuginfo file, the program headers are not reliable. */
7164 if (shnum != 0)
7165 {
7166 /* Get the section header string table index. */
7167 size_t shstrndx;
7168 if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
7169 error (EXIT_FAILURE, 0,
7170 gettext ("cannot get section header string table index"));
7171
7172 Elf_Scn *scn = NULL;
7173 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
7174 {
7175 GElf_Shdr shdr_mem;
7176 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
7177
7178 if (shdr == NULL || shdr->sh_type != SHT_NOTE)
7179 /* Not what we are looking for. */
7180 continue;
7181
7182 printf (gettext ("\
7183\nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
7184 elf_ndxscn (scn),
7185 elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
7186 shdr->sh_size, shdr->sh_offset);
7187
7188 handle_notes_data (ebl, ehdr, shdr->sh_offset,
7189 elf_getdata (scn, NULL));
7190 }
7191 return;
7192 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007193
7194 /* We have to look through the program header to find the note
7195 sections. There can be more than one. */
Roland McGrath59ea7f32007-10-04 08:50:09 +00007196 for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007197 {
7198 GElf_Phdr mem;
7199 GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
7200
7201 if (phdr == NULL || phdr->p_type != PT_NOTE)
7202 /* Not what we are looking for. */
7203 continue;
7204
7205 printf (gettext ("\
Roland McGrath59ea7f32007-10-04 08:50:09 +00007206\nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007207 phdr->p_filesz, phdr->p_offset);
7208
Roland McGrath59ea7f32007-10-04 08:50:09 +00007209 handle_notes_data (ebl, ehdr, phdr->p_offset,
7210 elf_getdata_rawchunk (ebl->elf,
7211 phdr->p_offset, phdr->p_filesz,
7212 ELF_T_NHDR));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007213 }
7214}
Roland McGrath60fc84c2007-08-03 21:59:15 +00007215
7216
7217static void
7218hex_dump (const uint8_t *data, size_t len)
7219{
7220 size_t pos = 0;
7221 while (pos < len)
7222 {
Roland McGrath241ac022007-10-01 18:21:46 +00007223 printf (" 0x%08Zx ", pos);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007224
7225 const size_t chunk = MIN (len - pos, 16);
7226
7227 for (size_t i = 0; i < chunk; ++i)
7228 if (i % 4 == 3)
7229 printf ("%02x ", data[pos + i]);
7230 else
7231 printf ("%02x", data[pos + i]);
7232
7233 if (chunk < 16)
Roland McGrathe4c22ea2007-10-23 13:07:39 +00007234 printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
Roland McGrath60fc84c2007-08-03 21:59:15 +00007235
7236 for (size_t i = 0; i < chunk; ++i)
7237 {
7238 unsigned char b = data[pos + i];
Ulrich Drepperc98bcc72007-08-04 17:06:14 +00007239 printf ("%c", isprint (b) ? b : '.');
Roland McGrath60fc84c2007-08-03 21:59:15 +00007240 }
7241
7242 putchar ('\n');
7243 pos += chunk;
7244 }
7245}
7246
7247static void
Roland McGrathc76f0b02007-09-27 07:31:33 +00007248dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
7249{
7250 if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
7251 printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
7252 elf_ndxscn (scn), name);
7253 else
7254 {
7255 Elf_Data *data = elf_rawdata (scn, NULL);
7256 if (data == NULL)
7257 error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
7258 elf_ndxscn (scn), name, elf_errmsg (-1));
7259 else
7260 {
7261 printf (gettext ("\nHex dump of section [%Zu] '%s', %" PRIu64
7262 " bytes at offset %#0" PRIx64 ":\n"),
7263 elf_ndxscn (scn), name,
7264 shdr->sh_size, shdr->sh_offset);
7265 hex_dump (data->d_buf, data->d_size);
7266 }
7267 }
7268}
7269
7270static void
7271print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
7272{
7273 if (shdr->sh_size == 0)
7274 printf (gettext ("\nSection [%Zu] '%s' is empty.\n"),
7275 elf_ndxscn (scn), name);
7276
7277 Elf_Data *data = elf_rawdata (scn, NULL);
7278 if (data == NULL)
7279 error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
7280 elf_ndxscn (scn), name, elf_errmsg (-1));
7281 else
7282 {
7283 printf (gettext ("\nString section [%Zu] '%s' contains %" PRIu64
7284 " bytes at offset %#0" PRIx64 ":\n"),
7285 elf_ndxscn (scn), name,
7286 shdr->sh_size, shdr->sh_offset);
7287
7288 const char *start = data->d_buf;
7289 const char *const limit = start + data->d_size;
7290 do
7291 {
7292 const char *end = memchr (start, '\0', limit - start);
7293 const size_t pos = start - (const char *) data->d_buf;
7294 if (unlikely (end == NULL))
7295 {
7296 printf (" [%6Zx]- %.*s\n",
7297 pos, (int) (limit - start), start);
7298 break;
7299 }
7300 printf (" [%6Zx] %s\n", pos, start);
7301 start = end + 1;
7302 } while (start < limit);
7303 }
7304}
7305
7306static void
7307for_each_section_argument (Elf *elf, const struct section_argument *list,
7308 void (*dump) (Elf_Scn *scn, const GElf_Shdr *shdr,
7309 const char *name))
Roland McGrath60fc84c2007-08-03 21:59:15 +00007310{
7311 /* Get the section header string table index. */
7312 size_t shstrndx;
Roland McGrathc76f0b02007-09-27 07:31:33 +00007313 if (elf_getshstrndx (elf, &shstrndx) < 0)
Roland McGrath60fc84c2007-08-03 21:59:15 +00007314 error (EXIT_FAILURE, 0,
7315 gettext ("cannot get section header string table index"));
7316
Roland McGrathc76f0b02007-09-27 07:31:33 +00007317 for (const struct section_argument *a = list; a != NULL; a = a->next)
Roland McGrath60fc84c2007-08-03 21:59:15 +00007318 {
7319 Elf_Scn *scn;
7320 GElf_Shdr shdr_mem;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00007321 const char *name = NULL;
Roland McGrath60fc84c2007-08-03 21:59:15 +00007322
7323 char *endp = NULL;
7324 unsigned long int shndx = strtoul (a->arg, &endp, 0);
Ulrich Drepperc98bcc72007-08-04 17:06:14 +00007325 if (endp != a->arg && *endp == '\0')
Roland McGrath60fc84c2007-08-03 21:59:15 +00007326 {
Roland McGrathc76f0b02007-09-27 07:31:33 +00007327 scn = elf_getscn (elf, shndx);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007328 if (scn == NULL)
7329 {
7330 error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
7331 continue;
7332 }
7333
7334 if (gelf_getshdr (scn, &shdr_mem) == NULL)
7335 error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
7336 elf_errmsg (-1));
Roland McGrathc76f0b02007-09-27 07:31:33 +00007337 name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007338 }
7339 else
7340 {
7341 /* Need to look up the section by name. */
7342 scn = NULL;
Roland McGrathc76f0b02007-09-27 07:31:33 +00007343 while ((scn = elf_nextscn (elf, scn)) != NULL)
Roland McGrath60fc84c2007-08-03 21:59:15 +00007344 {
7345 if (gelf_getshdr (scn, &shdr_mem) == NULL)
7346 continue;
Roland McGrathc76f0b02007-09-27 07:31:33 +00007347 name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007348 if (name == NULL)
7349 continue;
7350 if (!strcmp (name, a->arg))
7351 break;
7352 }
7353
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00007354 if (unlikely (scn == NULL))
Roland McGrath60fc84c2007-08-03 21:59:15 +00007355 {
7356 error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
7357 continue;
7358 }
7359 }
7360
Roland McGrathc76f0b02007-09-27 07:31:33 +00007361 (*dump) (scn, &shdr_mem, name);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007362 }
7363}
7364
7365static void
Roland McGrathc76f0b02007-09-27 07:31:33 +00007366dump_data (Ebl *ebl)
7367{
7368 for_each_section_argument (ebl->elf, dump_data_sections, &dump_data_section);
7369}
7370
7371static void
7372dump_strings (Ebl *ebl)
7373{
7374 for_each_section_argument (ebl->elf, string_sections, &print_string_section);
7375}
7376
7377static void
Roland McGrath60fc84c2007-08-03 21:59:15 +00007378print_strings (Ebl *ebl)
7379{
7380 /* Get the section header string table index. */
7381 size_t shstrndx;
Ulrich Drepper3fc3d7b2007-10-04 18:40:28 +00007382 if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0))
Roland McGrath60fc84c2007-08-03 21:59:15 +00007383 error (EXIT_FAILURE, 0,
7384 gettext ("cannot get section header string table index"));
7385
7386 Elf_Scn *scn;
7387 GElf_Shdr shdr_mem;
7388 const char *name;
7389 scn = NULL;
7390 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
7391 {
7392 if (gelf_getshdr (scn, &shdr_mem) == NULL)
7393 continue;
7394
7395 if (shdr_mem.sh_type != SHT_PROGBITS
7396 || !(shdr_mem.sh_flags & SHF_STRINGS))
7397 continue;
7398
7399 name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
7400 if (name == NULL)
7401 continue;
7402
Roland McGrathc76f0b02007-09-27 07:31:33 +00007403 print_string_section (scn, &shdr_mem, name);
Roland McGrath60fc84c2007-08-03 21:59:15 +00007404 }
7405}
Roland McGrath59ea7f32007-10-04 08:50:09 +00007406
7407static void
7408dump_archive_index (Elf *elf, const char *fname)
7409{
7410 size_t narsym;
7411 const Elf_Arsym *arsym = elf_getarsym (elf, &narsym);
7412 if (arsym == NULL)
7413 {
7414 int result = elf_errno ();
Ulrich Drepper3fc3d7b2007-10-04 18:40:28 +00007415 if (unlikely (result != ELF_E_NO_INDEX))
Roland McGrath59ea7f32007-10-04 08:50:09 +00007416 error (EXIT_FAILURE, 0,
7417 gettext ("cannot get symbol index of archive '%s': %s"),
7418 fname, elf_errmsg (result));
7419 else
7420 printf (gettext ("\nArchive '%s' has no symbol index\n"), fname);
7421 return;
7422 }
7423
7424 printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"),
7425 fname, narsym);
7426
7427 size_t as_off = 0;
7428 for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s)
7429 {
7430 if (s->as_off != as_off)
7431 {
7432 as_off = s->as_off;
7433
7434 Elf *subelf;
Ulrich Drepper3fc3d7b2007-10-04 18:40:28 +00007435 if (unlikely (elf_rand (elf, as_off) == 0)
7436 || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
7437 == NULL))
7438#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)
7439 while (1)
7440#endif
7441 error (EXIT_FAILURE, 0,
7442 gettext ("cannot extract member at offset %Zu in '%s': %s"),
7443 as_off, fname, elf_errmsg (-1));
Roland McGrath59ea7f32007-10-04 08:50:09 +00007444
7445 const Elf_Arhdr *h = elf_getarhdr (subelf);
7446
7447 printf (gettext ("Archive member '%s' contains:\n"), h->ar_name);
7448
7449 elf_end (subelf);
7450 }
7451
7452 printf ("\t%s\n", s->as_name);
7453 }
7454}
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00007455
7456#include "debugpred.h"