1/*-
2 * Copyright (c) 2007-2012 Kai Wang
3 * Copyright (c) 2003 David O'Brien.  All rights reserved.
4 * Copyright (c) 2001 Jake Burkholder
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/queue.h>
31#include <sys/stat.h>
32
33#include <ar.h>
34#include <assert.h>
35#include <err.h>
36#include <fcntl.h>
37#include <gelf.h>
38#include <getopt.h>
39#include <libelftc.h>
40#include <inttypes.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#ifdef USE_LIBARCHIVE_AR
47#include <archive.h>
48#include <archive_entry.h>
49#endif
50
51#include "_elftc.h"
52
53ELFTC_VCSID("$Id: elfdump.c 3762 2019-06-28 21:06:24Z emaste $");
54
55#if defined(ELFTC_NEED_ELF_NOTE_DEFINITION)
56#include "native-elf-format.h"
57#if ELFTC_CLASS == ELFCLASS32
58typedef Elf32_Nhdr	Elf_Note;
59#else
60typedef Elf64_Nhdr	Elf_Note;
61#endif
62#endif
63
64/* elfdump(1) options. */
65#define	ED_DYN		(1<<0)
66#define	ED_EHDR		(1<<1)
67#define	ED_GOT		(1<<2)
68#define	ED_HASH		(1<<3)
69#define	ED_INTERP	(1<<4)
70#define	ED_NOTE		(1<<5)
71#define	ED_PHDR		(1<<6)
72#define	ED_REL		(1<<7)
73#define	ED_SHDR		(1<<8)
74#define	ED_SYMTAB	(1<<9)
75#define	ED_SYMVER	(1<<10)
76#define	ED_CHECKSUM	(1<<11)
77#define	ED_ALL		((1<<12)-1)
78
79/* elfdump(1) run control flags. */
80#define	SOLARIS_FMT		(1<<0)
81#define	PRINT_FILENAME		(1<<1)
82#define	PRINT_ARSYM		(1<<2)
83#define	ONLY_ARSYM		(1<<3)
84
85/* Convenient print macro. */
86#define	PRT(...)	fprintf(ed->out, __VA_ARGS__)
87
88/* Internal data structure for sections. */
89struct section {
90	const char	*name;		/* section name */
91	Elf_Scn		*scn;		/* section scn */
92	uint64_t	 off;		/* section offset */
93	uint64_t	 sz;		/* section size */
94	uint64_t	 entsize;	/* section entsize */
95	uint64_t	 align;		/* section alignment */
96	uint64_t	 type;		/* section type */
97	uint64_t	 flags;		/* section flags */
98	uint64_t	 addr;		/* section virtual addr */
99	uint32_t	 link;		/* section link ndx */
100	uint32_t	 info;		/* section info ndx */
101};
102
103struct spec_name {
104	const char	*name;
105	STAILQ_ENTRY(spec_name)	sn_list;
106};
107
108/* Structure encapsulates the global data for readelf(1). */
109struct elfdump {
110	FILE		*out;		/* output redirection. */
111	const char	*filename;	/* current processing file. */
112	const char	*archive;	/* archive name */
113	int		 options;	/* command line options. */
114	int		 flags;		/* run control flags. */
115	Elf		*elf;		/* underlying ELF descriptor. */
116#ifndef USE_LIBARCHIVE_AR
117	Elf		*ar;		/* ar(1) archive descriptor. */
118#endif
119	GElf_Ehdr	 ehdr;		/* ELF header. */
120	int		 ec;		/* ELF class. */
121	size_t		 shnum;		/* #sections. */
122	struct section	*sl;		/* list of sections. */
123	STAILQ_HEAD(, spec_name) snl;	/* list of names specified by -N. */
124};
125
126/* Relocation entry. */
127struct rel_entry {
128	union {
129		GElf_Rel rel;
130		GElf_Rela rela;
131	} u_r;
132	const char *symn;
133	uint32_t type;
134};
135
136#if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS)
137static __inline uint32_t
138be32dec(const void *pp)
139{
140	unsigned char const *p = (unsigned char const *)pp;
141
142	return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
143}
144
145static __inline uint32_t
146le32dec(const void *pp)
147{
148	unsigned char const *p = (unsigned char const *)pp;
149
150	return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
151}
152#endif
153
154/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
155static const char *
156d_tags(uint64_t tag)
157{
158	static char unknown_buf[64];
159
160	switch (tag) {
161	case DT_NULL:		return "DT_NULL";
162	case DT_NEEDED:		return "DT_NEEDED";
163	case DT_PLTRELSZ:	return "DT_PLTRELSZ";
164	case DT_PLTGOT:		return "DT_PLTGOT";
165	case DT_HASH:		return "DT_HASH";
166	case DT_STRTAB:		return "DT_STRTAB";
167	case DT_SYMTAB:		return "DT_SYMTAB";
168	case DT_RELA:		return "DT_RELA";
169	case DT_RELASZ:		return "DT_RELASZ";
170	case DT_RELAENT:	return "DT_RELAENT";
171	case DT_STRSZ:		return "DT_STRSZ";
172	case DT_SYMENT:		return "DT_SYMENT";
173	case DT_INIT:		return "DT_INIT";
174	case DT_FINI:		return "DT_FINI";
175	case DT_SONAME:		return "DT_SONAME";
176	case DT_RPATH:		return "DT_RPATH";
177	case DT_SYMBOLIC:	return "DT_SYMBOLIC";
178	case DT_REL:		return "DT_REL";
179	case DT_RELSZ:		return "DT_RELSZ";
180	case DT_RELENT:		return "DT_RELENT";
181	case DT_PLTREL:		return "DT_PLTREL";
182	case DT_DEBUG:		return "DT_DEBUG";
183	case DT_TEXTREL:	return "DT_TEXTREL";
184	case DT_JMPREL:		return "DT_JMPREL";
185	case DT_BIND_NOW:	return "DT_BIND_NOW";
186	case DT_INIT_ARRAY:	return "DT_INIT_ARRAY";
187	case DT_FINI_ARRAY:	return "DT_FINI_ARRAY";
188	case DT_INIT_ARRAYSZ:	return "DT_INIT_ARRAYSZ";
189	case DT_FINI_ARRAYSZ:	return "DT_FINI_ARRAYSZ";
190	case DT_RUNPATH:	return "DT_RUNPATH";
191	case DT_FLAGS:		return "DT_FLAGS";
192	case DT_PREINIT_ARRAY:	return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */
193	case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ";
194	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
195	case 0x6ffffdf5:	return "DT_GNU_PRELINKED";
196	case 0x6ffffdf6:	return "DT_GNU_CONFLICTSZ";
197	case 0x6ffffdf7:	return "DT_GNU_LIBLISTSZ";
198	case 0x6ffffdf8:	return "DT_SUNW_CHECKSUM";
199	case DT_PLTPADSZ:	return "DT_PLTPADSZ";
200	case DT_MOVEENT:	return "DT_MOVEENT";
201	case DT_MOVESZ:		return "DT_MOVESZ";
202	case 0x6ffffdfc:	return "DT_FEATURE";
203	case DT_POSFLAG_1:	return "DT_POSFLAG_1";
204	case DT_SYMINSZ:	return "DT_SYMINSZ";
205	case DT_SYMINENT:	return "DT_SYMINENT (DT_VALRNGHI)";
206	case DT_ADDRRNGLO:	return "DT_ADDRRNGLO";
207	case DT_GNU_HASH:	return "DT_GNU_HASH";
208	case 0x6ffffef8:	return "DT_GNU_CONFLICT";
209	case 0x6ffffef9:	return "DT_GNU_LIBLIST";
210	case 0x6ffffefa:	return "DT_CONFIG";
211	case 0x6ffffefb:	return "DT_DEPAUDIT";
212	case 0x6ffffefc:	return "DT_AUDIT";
213	case 0x6ffffefd:	return "DT_PLTPAD";
214	case 0x6ffffefe:	return "DT_MOVETAB";
215	case DT_SYMINFO:	return "DT_SYMINFO (DT_ADDRRNGHI)";
216	case DT_RELACOUNT:	return "DT_RELACOUNT";
217	case DT_RELCOUNT:	return "DT_RELCOUNT";
218	case DT_FLAGS_1:	return "DT_FLAGS_1";
219	case DT_VERDEF:		return "DT_VERDEF";
220	case DT_VERDEFNUM:	return "DT_VERDEFNUM";
221	case DT_VERNEED:	return "DT_VERNEED";
222	case DT_VERNEEDNUM:	return "DT_VERNEEDNUM";
223	case 0x6ffffff0:	return "DT_GNU_VERSYM";
224	/* 0x70000000 - 0x7fffffff processor-specific semantics */
225	case 0x70000000:	return "DT_IA_64_PLT_RESERVE";
226	case DT_AUXILIARY:	return "DT_AUXILIARY";
227	case DT_USED:		return "DT_USED";
228	case DT_FILTER:		return "DT_FILTER";
229	}
230
231	snprintf(unknown_buf, sizeof(unknown_buf),
232		"<unknown: %#llx>", (unsigned long long)tag);
233	return (unknown_buf);
234}
235
236static const char *
237e_machines(unsigned int mach)
238{
239	static char machdesc[64];
240
241	switch (mach) {
242	case EM_NONE:	return "EM_NONE";
243	case EM_M32:	return "EM_M32";
244	case EM_SPARC:	return "EM_SPARC";
245	case EM_386:	return "EM_386";
246	case EM_68K:	return "EM_68K";
247	case EM_88K:	return "EM_88K";
248	case EM_IAMCU:	return "EM_IAMCU";
249	case EM_860:	return "EM_860";
250	case EM_MIPS:	return "EM_MIPS";
251	case EM_PPC:	return "EM_PPC";
252	case EM_PPC64:	return "EM_PPC64";
253	case EM_ARM:	return "EM_ARM";
254	case EM_ALPHA:	return "EM_ALPHA (legacy)";
255	case EM_SPARCV9:return "EM_SPARCV9";
256	case EM_IA_64:	return "EM_IA_64";
257	case EM_X86_64:	return "EM_X86_64";
258	case EM_AARCH64:return "EM_AARCH64";
259	case EM_RISCV:	return "EM_RISCV";
260	}
261	snprintf(machdesc, sizeof(machdesc),
262	    "(unknown machine) -- type 0x%x", mach);
263	return (machdesc);
264}
265
266static const char *
267elf_type_str(unsigned int type)
268{
269	static char s_type[32];
270
271	switch (type)
272	{
273	case ET_NONE:	return "ET_NONE";
274	case ET_REL:	return "ET_REL";
275	case ET_EXEC:	return "ET_EXEC";
276	case ET_DYN:	return "ET_DYN";
277	case ET_CORE:	return "ET_CORE";
278	}
279	if (type >= ET_LOPROC)
280		snprintf(s_type, sizeof(s_type), "<proc: %#x>", type);
281	else if (type >= ET_LOOS && type <= ET_HIOS)
282		snprintf(s_type, sizeof(s_type), "<os: %#x>", type);
283	else
284		snprintf(s_type, sizeof(s_type), "<unknown: %#x", type);
285	return (s_type);
286}
287
288static const char *
289elf_version_str(unsigned int ver)
290{
291	static char s_ver[32];
292
293	switch (ver) {
294	case EV_NONE:		return "EV_NONE";
295	case EV_CURRENT:	return "EV_CURRENT";
296	}
297	snprintf(s_ver, sizeof(s_ver), "<unknown: %#x>", ver);
298	return (s_ver);
299}
300
301static const char *
302elf_class_str(unsigned int class)
303{
304	static char s_class[32];
305
306	switch (class) {
307	case ELFCLASSNONE:	return "ELFCLASSNONE";
308	case ELFCLASS32:	return "ELFCLASS32";
309	case ELFCLASS64:	return "ELFCLASS64";
310	}
311	snprintf(s_class, sizeof(s_class), "<unknown: %#x>", class);
312	return (s_class);
313}
314
315static const char *
316elf_data_str(unsigned int data)
317{
318	static char s_data[32];
319
320	switch (data) {
321	case ELFDATANONE:	return "ELFDATANONE";
322	case ELFDATA2LSB:	return "ELFDATA2LSB";
323	case ELFDATA2MSB:	return "ELFDATA2MSB";
324	}
325	snprintf(s_data, sizeof(s_data), "<unknown: %#x>", data);
326	return (s_data);
327}
328
329static const char *ei_abis[256] = {
330	"ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
331	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX",
332	"ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64",
333	"ELFOSABI_MODESTO", "ELFOSABI_OPENBSD",
334	[17] = "ELFOSABI_CLOUDABI",
335	[64] = "ELFOSABI_ARM_AEABI",
336	[97] = "ELFOSABI_ARM",
337	[255] = "ELFOSABI_STANDALONE"
338};
339
340static const char *
341elf_phdr_type_str(unsigned int type)
342{
343	static char s_type[32];
344
345	switch (type) {
346	case PT_NULL:			return "PT_NULL";
347	case PT_LOAD:			return "PT_LOAD";
348	case PT_DYNAMIC:		return "PT_DYNAMIC";
349	case PT_INTERP:			return "PT_INTERP";
350	case PT_NOTE:			return "PT_NOTE";
351	case PT_SHLIB:			return "PT_SHLIB";
352	case PT_PHDR:			return "PT_PHDR";
353	case PT_TLS:			return "PT_TLS";
354	case PT_GNU_EH_FRAME:		return "PT_GNU_EH_FRAME";
355	case PT_GNU_STACK:		return "PT_GNU_STACK";
356	case PT_GNU_RELRO:		return "PT_GNU_RELRO";
357	case PT_OPENBSD_RANDOMIZE:	return "PT_OPENBSD_RANDOMIZE";
358	case PT_OPENBSD_WXNEEDED:	return "PT_OPENBSD_WXNEEDED";
359	case PT_OPENBSD_BOOTDATA:	return "PT_OPENBSD_BOOTDATA";
360	}
361	snprintf(s_type, sizeof(s_type), "<unknown: %#x>", type);
362	return (s_type);
363}
364
365static const char *p_flags[] = {
366	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
367	"PF_X|PF_W|PF_R"
368};
369
370static const char *
371sh_name(struct elfdump *ed, int ndx)
372{
373	static char num[10];
374
375	switch (ndx) {
376	case SHN_UNDEF: return "UNDEF";
377	case SHN_ABS: return "ABS";
378	case SHN_COMMON: return "COMMON";
379	default:
380		if ((uint64_t)ndx < ed->shnum)
381			return (ed->sl[ndx].name);
382		else {
383			snprintf(num, sizeof(num), "%d", ndx);
384			return (num);
385		}
386	}
387}
388
389/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
390static const char *
391sh_types(uint64_t mach, uint64_t sht) {
392	static char unknown_buf[64];
393
394	if (sht < 0x60000000) {
395		switch (sht) {
396		case SHT_NULL:		return "SHT_NULL";
397		case SHT_PROGBITS:	return "SHT_PROGBITS";
398		case SHT_SYMTAB:	return "SHT_SYMTAB";
399		case SHT_STRTAB:	return "SHT_STRTAB";
400		case SHT_RELA:		return "SHT_RELA";
401		case SHT_HASH:		return "SHT_HASH";
402		case SHT_DYNAMIC:	return "SHT_DYNAMIC";
403		case SHT_NOTE:		return "SHT_NOTE";
404		case SHT_NOBITS:	return "SHT_NOBITS";
405		case SHT_REL:		return "SHT_REL";
406		case SHT_SHLIB:		return "SHT_SHLIB";
407		case SHT_DYNSYM:	return "SHT_DYNSYM";
408		case SHT_INIT_ARRAY:	return "SHT_INIT_ARRAY";
409		case SHT_FINI_ARRAY:	return "SHT_FINI_ARRAY";
410		case SHT_PREINIT_ARRAY:	return "SHT_PREINIT_ARRAY";
411		case SHT_GROUP:		return "SHT_GROUP";
412		case SHT_SYMTAB_SHNDX:	return "SHT_SYMTAB_SHNDX";
413		}
414	} else if (sht < 0x70000000) {
415		/* 0x60000000-0x6fffffff operating system-specific semantics */
416		switch (sht) {
417		case 0x6ffffff0:	return "XXX:VERSYM";
418		case SHT_SUNW_dof:	return "SHT_SUNW_dof";
419		case SHT_GNU_HASH:	return "SHT_GNU_HASH";
420		case 0x6ffffff7:	return "SHT_GNU_LIBLIST";
421		case 0x6ffffffc:	return "XXX:VERDEF";
422		case SHT_SUNW_verdef:	return "SHT_SUNW(GNU)_verdef";
423		case SHT_SUNW_verneed:	return "SHT_SUNW(GNU)_verneed";
424		case SHT_SUNW_versym:	return "SHT_SUNW(GNU)_versym";
425		}
426	} else if (sht < 0x80000000) {
427		/* 0x70000000 - 0x7fffffff processor-specific semantics */
428		switch (mach) {
429		case EM_ARM:
430			switch (sht) {
431			case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX";
432			case SHT_ARM_PREEMPTMAP: return "SHT_ARM_PREEMPTMAP";
433			case SHT_ARM_ATTRIBUTES: return "SHT_ARM_ATTRIBUTES";
434			case SHT_ARM_DEBUGOVERLAY:
435			    return "SHT_ARM_DEBUGOVERLAY";
436			case SHT_ARM_OVERLAYSECTION:
437			    return "SHT_ARM_OVERLAYSECTION";
438			}
439			break;
440		case EM_IA_64:
441			switch (sht) {
442			case 0x70000000: return "SHT_IA_64_EXT";
443			case 0x70000001: return "SHT_IA_64_UNWIND";
444			}
445			break;
446		case EM_MIPS:
447			switch (sht) {
448			case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO";
449			case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS";
450			case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS";
451			}
452			break;
453		}
454		switch (sht) {
455		case 0x7ffffffd: return "XXX:AUXILIARY";
456		case 0x7fffffff: return "XXX:FILTER";
457		}
458	}
459	/* 0x80000000 - 0xffffffff application programs */
460
461	snprintf(unknown_buf, sizeof(unknown_buf),
462		"<unknown: %#llx>", (unsigned long long)sht);
463	return (unknown_buf);
464}
465
466/*
467 * Define known section flags. These flags are defined in the order
468 * they are to be printed out.
469 */
470#define	DEFINE_SHFLAGS()			\
471	DEFINE_SHF(WRITE)			\
472	DEFINE_SHF(ALLOC)			\
473	DEFINE_SHF(EXECINSTR)			\
474	DEFINE_SHF(MERGE)			\
475	DEFINE_SHF(STRINGS)			\
476	DEFINE_SHF(INFO_LINK)			\
477	DEFINE_SHF(LINK_ORDER)			\
478	DEFINE_SHF(OS_NONCONFORMING)		\
479	DEFINE_SHF(GROUP)			\
480	DEFINE_SHF(TLS)				\
481	DEFINE_SHF(COMPRESSED)
482
483#undef	DEFINE_SHF
484#define	DEFINE_SHF(F) "SHF_" #F "|"
485#define ALLSHFLAGS	DEFINE_SHFLAGS()
486
487static const char *
488sh_flags(uint64_t shf)
489{
490	static char	flg[sizeof(ALLSHFLAGS)+1];
491
492	flg[0] = '\0';
493
494#undef	DEFINE_SHF
495#define	DEFINE_SHF(N)				\
496	if (shf & SHF_##N)			\
497		strcat(flg, "SHF_" #N "|");	\
498
499	DEFINE_SHFLAGS()
500
501	flg[strlen(flg) - 1] = '\0'; /* Remove the trailing "|". */
502
503	return (flg);
504}
505
506static const char *
507st_type(unsigned int mach, unsigned int type)
508{
509	static char s_type[32];
510
511	switch (type) {
512	case STT_NOTYPE: return "STT_NOTYPE";
513	case STT_OBJECT: return "STT_OBJECT";
514	case STT_FUNC: return "STT_FUNC";
515	case STT_SECTION: return "STT_SECTION";
516	case STT_FILE: return "STT_FILE";
517	case STT_COMMON: return "STT_COMMON";
518	case STT_TLS: return "STT_TLS";
519	case 13:
520		if (mach == EM_SPARCV9)
521			return "STT_SPARC_REGISTER";
522		break;
523	}
524	snprintf(s_type, sizeof(s_type), "<unknown: %#x>", type);
525	return (s_type);
526}
527
528static const char *
529st_type_S(unsigned int type)
530{
531	static char s_type[32];
532
533	switch (type) {
534	case STT_NOTYPE: return "NOTY";
535	case STT_OBJECT: return "OBJT";
536	case STT_FUNC: return "FUNC";
537	case STT_SECTION: return "SECT";
538	case STT_FILE: return "FILE";
539	}
540	snprintf(s_type, sizeof(s_type), "<unknown: %#x>", type);
541	return (s_type);
542}
543
544static const char *
545st_bindings(unsigned int sbind)
546{
547	static char s_sbind[32];
548
549	switch (sbind) {
550	case STB_LOCAL: return "STB_LOCAL";
551	case STB_GLOBAL: return "STB_GLOBAL";
552	case STB_WEAK: return "STB_WEAK";
553	case STB_GNU_UNIQUE: return "STB_GNU_UNIQUE";
554	default:
555		if (sbind >= STB_LOOS && sbind <= STB_HIOS)
556			return "OS";
557		else if (sbind >= STB_LOPROC && sbind <= STB_HIPROC)
558			return "PROC";
559		else
560			snprintf(s_sbind, sizeof(s_sbind), "<unknown: %#x>",
561			    sbind);
562		return (s_sbind);
563	}
564}
565
566static const char *
567st_bindings_S(unsigned int sbind)
568{
569	static char s_sbind[32];
570
571	switch (sbind) {
572	case STB_LOCAL: return "LOCL";
573	case STB_GLOBAL: return "GLOB";
574	case STB_WEAK: return "WEAK";
575	case STB_GNU_UNIQUE: return "UNIQ";
576	default:
577		if (sbind >= STB_LOOS && sbind <= STB_HIOS)
578			return "OS";
579		else if (sbind >= STB_LOPROC && sbind <= STB_HIPROC)
580			return "PROC";
581		else
582			snprintf(s_sbind, sizeof(s_sbind), "<%#x>",
583			    sbind);
584		return (s_sbind);
585	}
586}
587
588static unsigned char st_others[] = {
589	'D', 'I', 'H', 'P'
590};
591
592static void	add_name(struct elfdump *ed, const char *name);
593static void	elf_print_object(struct elfdump *ed);
594static void	elf_print_elf(struct elfdump *ed);
595static void	elf_print_ehdr(struct elfdump *ed);
596static void	elf_print_phdr(struct elfdump *ed);
597static void	elf_print_shdr(struct elfdump *ed);
598static void	elf_print_symtab(struct elfdump *ed, int i);
599static void	elf_print_symtabs(struct elfdump *ed);
600static void	elf_print_symver(struct elfdump *ed);
601static void	elf_print_verdef(struct elfdump *ed, struct section *s);
602static void	elf_print_verneed(struct elfdump *ed, struct section *s);
603static void	elf_print_interp(struct elfdump *ed);
604static void	elf_print_dynamic(struct elfdump *ed);
605static void	elf_print_rel_entry(struct elfdump *ed, struct section *s,
606    int j, struct rel_entry *r);
607static void	elf_print_rela(struct elfdump *ed, struct section *s,
608    Elf_Data *data);
609static void	elf_print_rel(struct elfdump *ed, struct section *s,
610    Elf_Data *data);
611static void	elf_print_reloc(struct elfdump *ed);
612static void	elf_print_got(struct elfdump *ed);
613static void	elf_print_got_section(struct elfdump *ed, struct section *s);
614static void	elf_print_note(struct elfdump *ed);
615static void	elf_print_svr4_hash(struct elfdump *ed, struct section *s);
616static void	elf_print_svr4_hash64(struct elfdump *ed, struct section *s);
617static void	elf_print_gnu_hash(struct elfdump *ed, struct section *s);
618static void	elf_print_hash(struct elfdump *ed);
619static void	elf_print_checksum(struct elfdump *ed);
620static void	find_gotrel(struct elfdump *ed, struct section *gs,
621    struct rel_entry *got);
622static struct spec_name	*find_name(struct elfdump *ed, const char *name);
623static int	get_ent_count(const struct section *s, int *ent_count);
624static const char *get_symbol_name(struct elfdump *ed, uint32_t symtab, int i);
625static const char *get_string(struct elfdump *ed, int strtab, size_t off);
626static void	get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs);
627static void	load_sections(struct elfdump *ed);
628static void	unload_sections(struct elfdump *ed);
629static void	usage(void);
630#ifdef	USE_LIBARCHIVE_AR
631static int	ac_detect_ar(int fd);
632static void	ac_print_ar(struct elfdump *ed, int fd);
633#else
634static void	elf_print_ar(struct elfdump *ed, int fd);
635#endif	/* USE_LIBARCHIVE_AR */
636
637static struct option elfdump_longopts[] =
638{
639	{ "help",	no_argument,	NULL,	'H' },
640	{ "version",	no_argument,	NULL,	'V' },
641	{ NULL,		0,		NULL,	0   }
642};
643
644int
645main(int ac, char **av)
646{
647	struct elfdump		*ed, ed_storage;
648	struct spec_name	*sn;
649	int			 ch, i;
650
651	ed = &ed_storage;
652	memset(ed, 0, sizeof(*ed));
653	STAILQ_INIT(&ed->snl);
654	ed->out = stdout;
655	while ((ch = getopt_long(ac, av, "acdeiGHhknN:prsSvVw:",
656		elfdump_longopts, NULL)) != -1)
657		switch (ch) {
658		case 'a':
659			ed->options = ED_ALL;
660			break;
661		case 'c':
662			ed->options |= ED_SHDR;
663			break;
664		case 'd':
665			ed->options |= ED_DYN;
666			break;
667		case 'e':
668			ed->options |= ED_EHDR;
669			break;
670		case 'i':
671			ed->options |= ED_INTERP;
672			break;
673		case 'G':
674			ed->options |= ED_GOT;
675			break;
676		case 'h':
677			ed->options |= ED_HASH;
678			break;
679		case 'k':
680			ed->options |= ED_CHECKSUM;
681			break;
682		case 'n':
683			ed->options |= ED_NOTE;
684			break;
685		case 'N':
686			add_name(ed, optarg);
687			break;
688		case 'p':
689			ed->options |= ED_PHDR;
690			break;
691		case 'r':
692			ed->options |= ED_REL;
693			break;
694		case 's':
695			ed->options |= ED_SYMTAB;
696			break;
697		case 'S':
698			ed->flags |= SOLARIS_FMT;
699			break;
700		case 'v':
701			ed->options |= ED_SYMVER;
702			break;
703		case 'V':
704			(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(),
705			    elftc_version());
706			exit(EXIT_SUCCESS);
707			break;
708		case 'w':
709			if ((ed->out = fopen(optarg, "w")) == NULL)
710				err(EXIT_FAILURE, "%s", optarg);
711			break;
712		case '?':
713		case 'H':
714		default:
715			usage();
716		}
717
718	ac -= optind;
719	av += optind;
720
721	if (ed->options == 0)
722		ed->options = ED_ALL;
723	sn = NULL;
724	if (ed->options & ED_SYMTAB &&
725	    (STAILQ_EMPTY(&ed->snl) || (sn = find_name(ed, "ARSYM")) != NULL)) {
726		ed->flags |= PRINT_ARSYM;
727		if (sn != NULL) {
728			STAILQ_REMOVE(&ed->snl, sn, spec_name, sn_list);
729			if (STAILQ_EMPTY(&ed->snl))
730				ed->flags |= ONLY_ARSYM;
731		}
732	}
733	if (ac == 0)
734		usage();
735	if (ac > 1)
736		ed->flags |= PRINT_FILENAME;
737	if (elf_version(EV_CURRENT) == EV_NONE)
738		errx(EXIT_FAILURE, "ELF library initialization failed: %s",
739		    elf_errmsg(-1));
740
741	for (i = 0; i < ac; i++) {
742		ed->filename = av[i];
743		ed->archive = NULL;
744		elf_print_object(ed);
745	}
746
747	exit(EXIT_SUCCESS);
748}
749
750#ifdef USE_LIBARCHIVE_AR
751
752/* Archive symbol table entry. */
753struct arsym_entry {
754	char *sym_name;
755	size_t off;
756};
757
758/*
759 * Convenient wrapper for general libarchive error handling.
760 */
761#define	AC(CALL) do {							\
762	if ((CALL)) {							\
763		warnx("%s", archive_error_string(a));			\
764		return;							\
765	}								\
766} while (0)
767
768/*
769 * Detect an ar(1) archive using libarchive(3).
770 */
771static int
772ac_detect_ar(int fd)
773{
774	struct archive		*a;
775	struct archive_entry	*entry;
776	int			 r;
777
778	r = -1;
779	if ((a = archive_read_new()) == NULL)
780		return (0);
781	archive_read_support_format_ar(a);
782	if (archive_read_open_fd(a, fd, 10240) == ARCHIVE_OK)
783		r = archive_read_next_header(a, &entry);
784	archive_read_close(a);
785	archive_read_free(a);
786
787	return (r == ARCHIVE_OK);
788}
789
790/*
791 * Dump an ar(1) archive using libarchive(3).
792 */
793static void
794ac_print_ar(struct elfdump *ed, int fd)
795{
796	struct archive		*a;
797	struct archive_entry	*entry;
798	struct arsym_entry	*arsym;
799	const char		*name;
800	char			 idx[10], *b;
801	void			*buff;
802	size_t			 size;
803	uint32_t		 cnt, i;
804	int			 r;
805
806	if (lseek(fd, 0, SEEK_SET) == -1)
807		err(EXIT_FAILURE, "lseek failed");
808	if ((a = archive_read_new()) == NULL)
809		errx(EXIT_FAILURE, "%s", archive_error_string(a));
810	archive_read_support_format_ar(a);
811	AC(archive_read_open_fd(a, fd, 10240));
812	for(;;) {
813		r = archive_read_next_header(a, &entry);
814		if (r == ARCHIVE_FATAL)
815			errx(EXIT_FAILURE, "%s", archive_error_string(a));
816		if (r == ARCHIVE_EOF)
817			break;
818		if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
819			warnx("%s", archive_error_string(a));
820		if (r == ARCHIVE_RETRY)
821			continue;
822		name = archive_entry_pathname(entry);
823		size = archive_entry_size(entry);
824		if (size == 0)
825			continue;
826		if ((buff = malloc(size)) == NULL) {
827			warn("malloc failed");
828			continue;
829		}
830		if (archive_read_data(a, buff, size) != (ssize_t)size) {
831			warnx("%s", archive_error_string(a));
832			free(buff);
833			continue;
834		}
835
836		/*
837		 * Note that when processing arsym via libarchive, there is
838		 * no way to tell which member a certain symbol belongs to,
839		 * since we can not just "lseek" to a member offset and read
840		 * the member header.
841		 */
842		if (!strcmp(name, "/") && ed->flags & PRINT_ARSYM) {
843			b = buff;
844			cnt = be32dec(b);
845			if (cnt == 0) {
846				free(buff);
847				continue;
848			}
849			arsym = calloc(cnt, sizeof(*arsym));
850			if (arsym == NULL)
851				err(EXIT_FAILURE, "calloc failed");
852			b += sizeof(uint32_t);
853			for (i = 0; i < cnt; i++) {
854				arsym[i].off = be32dec(b);
855				b += sizeof(uint32_t);
856			}
857			for (i = 0; i < cnt; i++) {
858				arsym[i].sym_name = b;
859				b += strlen(b) + 1;
860			}
861			if (ed->flags & SOLARIS_FMT) {
862				PRT("\nSymbol Table: (archive)\n");
863				PRT("     index    offset    symbol\n");
864			} else
865				PRT("\nsymbol table (archive):\n");
866			for (i = 0; i < cnt; i++) {
867				if (ed->flags & SOLARIS_FMT) {
868					snprintf(idx, sizeof(idx), "[%d]", i);
869					PRT("%10s  ", idx);
870					PRT("0x%8.8jx  ",
871					    (uintmax_t)arsym[i].off);
872					PRT("%s\n", arsym[i].sym_name);
873				} else {
874					PRT("\nentry: %d\n", i);
875					PRT("\toffset: %#jx\n",
876					    (uintmax_t)arsym[i].off);
877					PRT("\tsymbol: %s\n",
878					    arsym[i].sym_name);
879				}
880			}
881			free(arsym);
882			free(buff);
883			/* No need to continue if we only dump ARSYM. */
884			if (ed->flags & ONLY_ARSYM) {
885				AC(archive_read_close(a));
886				AC(archive_read_free(a));
887				return;
888			}
889			continue;
890		}
891		if ((ed->elf = elf_memory(buff, size)) == NULL) {
892			warnx("elf_memroy() failed: %s",
893			      elf_errmsg(-1));
894			free(buff);
895			continue;
896		}
897		/* Skip non-ELF member. */
898		if (elf_kind(ed->elf) == ELF_K_ELF) {
899			printf("\n%s(%s):\n", ed->archive, name);
900			elf_print_elf(ed);
901		}
902		elf_end(ed->elf);
903		free(buff);
904	}
905	AC(archive_read_close(a));
906	AC(archive_read_free(a));
907}
908
909#else  /* USE_LIBARCHIVE_AR */
910
911/*
912 * Dump an ar(1) archive.
913 */
914static void
915elf_print_ar(struct elfdump *ed, int fd)
916{
917	Elf		*e;
918	Elf_Arhdr	*arh;
919	Elf_Arsym	*arsym;
920	Elf_Cmd		 cmd;
921	char		 idx[21];
922	size_t		 cnt, i;
923
924	ed->ar = ed->elf;
925
926	if (ed->flags & PRINT_ARSYM) {
927		cnt = 0;
928		if ((arsym = elf_getarsym(ed->ar, &cnt)) == NULL) {
929			warnx("elf_getarsym failed: %s", elf_errmsg(-1));
930			goto print_members;
931		}
932		if (cnt == 0)
933			goto print_members;
934		if (ed->flags & SOLARIS_FMT) {
935			PRT("\nSymbol Table: (archive)\n");
936			PRT("     index    offset    member name and symbol\n");
937		} else
938			PRT("\nsymbol table (archive):\n");
939		for (i = 0; i < cnt - 1; i++) {
940			if (elf_rand(ed->ar, arsym[i].as_off) !=
941			    arsym[i].as_off) {
942				warnx("elf_rand failed: %s", elf_errmsg(-1));
943				break;
944			}
945			if ((e = elf_begin(fd, ELF_C_READ, ed->ar)) == NULL) {
946				warnx("elf_begin failed: %s", elf_errmsg(-1));
947				break;
948			}
949			if ((arh = elf_getarhdr(e)) == NULL) {
950				warnx("elf_getarhdr failed: %s",
951				    elf_errmsg(-1));
952				break;
953			}
954			if (ed->flags & SOLARIS_FMT) {
955				snprintf(idx, sizeof(idx), "[%zu]", i);
956				PRT("%10s  ", idx);
957				PRT("0x%8.8jx  ",
958				    (uintmax_t)arsym[i].as_off);
959				PRT("(%s):%s\n", arh->ar_name,
960				    arsym[i].as_name);
961			} else {
962				PRT("\nentry: %zu\n", i);
963				PRT("\toffset: %#jx\n",
964				    (uintmax_t)arsym[i].as_off);
965				PRT("\tmember: %s\n", arh->ar_name);
966				PRT("\tsymbol: %s\n", arsym[i].as_name);
967			}
968			elf_end(e);
969		}
970
971		/* No need to continue if we only dump ARSYM. */
972		if (ed->flags & ONLY_ARSYM)
973			return;
974	}
975
976print_members:
977
978	/* Rewind the archive. */
979	if (elf_rand(ed->ar, SARMAG) != SARMAG) {
980		warnx("elf_rand failed: %s", elf_errmsg(-1));
981		return;
982	}
983
984	/* Dump each member of the archive. */
985	cmd = ELF_C_READ;
986	while ((ed->elf = elf_begin(fd, cmd, ed->ar)) != NULL) {
987		/* Skip non-ELF member. */
988		if (elf_kind(ed->elf) == ELF_K_ELF) {
989			if ((arh = elf_getarhdr(ed->elf)) == NULL) {
990				warnx("elf_getarhdr failed: %s",
991				    elf_errmsg(-1));
992				break;
993			}
994			printf("\n%s(%s):\n", ed->archive, arh->ar_name);
995			elf_print_elf(ed);
996		}
997		cmd = elf_next(ed->elf);
998		elf_end(ed->elf);
999	}
1000}
1001
1002#endif	/* USE_LIBARCHIVE_AR */
1003
1004/*
1005 * Dump an object. (ELF object or ar(1) archive)
1006 */
1007static void
1008elf_print_object(struct elfdump *ed)
1009{
1010	int fd;
1011
1012	if ((fd = open(ed->filename, O_RDONLY)) == -1) {
1013		warn("open %s failed", ed->filename);
1014		return;
1015	}
1016
1017#ifdef	USE_LIBARCHIVE_AR
1018	if (ac_detect_ar(fd)) {
1019		ed->archive = ed->filename;
1020		ac_print_ar(ed, fd);
1021		return;
1022	}
1023#endif	/* USE_LIBARCHIVE_AR */
1024
1025	if ((ed->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
1026		warnx("elf_begin() failed: %s", elf_errmsg(-1));
1027		return;
1028	}
1029
1030	switch (elf_kind(ed->elf)) {
1031	case ELF_K_NONE:
1032		warnx("Not an ELF file.");
1033		return;
1034	case ELF_K_ELF:
1035		if (ed->flags & PRINT_FILENAME)
1036			printf("\n%s:\n", ed->filename);
1037		elf_print_elf(ed);
1038		break;
1039	case ELF_K_AR:
1040#ifndef	USE_LIBARCHIVE_AR
1041		ed->archive = ed->filename;
1042		elf_print_ar(ed, fd);
1043#endif
1044		break;
1045	default:
1046		warnx("Internal: libelf returned unknown elf kind.");
1047		return;
1048	}
1049
1050	elf_end(ed->elf);
1051}
1052
1053/*
1054 * Dump an ELF object.
1055 */
1056static void
1057elf_print_elf(struct elfdump *ed)
1058{
1059
1060	if (gelf_getehdr(ed->elf, &ed->ehdr) == NULL) {
1061		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
1062		return;
1063	}
1064	if ((ed->ec = gelf_getclass(ed->elf)) == ELFCLASSNONE) {
1065		warnx("gelf_getclass failed: %s", elf_errmsg(-1));
1066		return;
1067	}
1068
1069	if (ed->options & (ED_SHDR | ED_DYN | ED_REL | ED_GOT | ED_SYMTAB |
1070	    ED_SYMVER | ED_NOTE | ED_HASH))
1071		load_sections(ed);
1072
1073	if (ed->options & ED_EHDR)
1074		elf_print_ehdr(ed);
1075	if (ed->options & ED_PHDR)
1076		elf_print_phdr(ed);
1077	if (ed->options & ED_INTERP)
1078		elf_print_interp(ed);
1079	if (ed->options & ED_SHDR)
1080		elf_print_shdr(ed);
1081	if (ed->options & ED_DYN)
1082		elf_print_dynamic(ed);
1083	if (ed->options & ED_REL)
1084		elf_print_reloc(ed);
1085	if (ed->options & ED_GOT)
1086		elf_print_got(ed);
1087	if (ed->options & ED_SYMTAB)
1088		elf_print_symtabs(ed);
1089	if (ed->options & ED_SYMVER)
1090		elf_print_symver(ed);
1091	if (ed->options & ED_NOTE)
1092		elf_print_note(ed);
1093	if (ed->options & ED_HASH)
1094		elf_print_hash(ed);
1095	if (ed->options & ED_CHECKSUM)
1096		elf_print_checksum(ed);
1097
1098	unload_sections(ed);
1099}
1100
1101/*
1102 * Read the section headers from ELF object and store them in the
1103 * internal cache.
1104 */
1105static void
1106load_sections(struct elfdump *ed)
1107{
1108	struct section	*s;
1109	const char	*name;
1110	Elf_Scn		*scn;
1111	GElf_Shdr	 sh;
1112	size_t		 shstrndx, ndx;
1113	int		 elferr;
1114
1115	assert(ed->sl == NULL);
1116
1117	if (!elf_getshnum(ed->elf, &ed->shnum)) {
1118		warnx("elf_getshnum failed: %s", elf_errmsg(-1));
1119		return;
1120	}
1121	if (ed->shnum == 0)
1122		return;
1123	if ((ed->sl = calloc(ed->shnum, sizeof(*ed->sl))) == NULL)
1124		err(EXIT_FAILURE, "calloc failed");
1125	if (!elf_getshstrndx(ed->elf, &shstrndx)) {
1126		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
1127		return;
1128	}
1129	if ((scn = elf_getscn(ed->elf, 0)) == NULL) {
1130		warnx("elf_getscn failed: %s", elf_errmsg(-1));
1131		return;
1132	}
1133	(void) elf_errno();
1134	do {
1135		if (gelf_getshdr(scn, &sh) == NULL) {
1136			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
1137			(void) elf_errno();
1138			continue;
1139		}
1140		if ((name = elf_strptr(ed->elf, shstrndx, sh.sh_name)) == NULL) {
1141			(void) elf_errno();
1142			name = "ERROR";
1143		}
1144		if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF)
1145			if ((elferr = elf_errno()) != 0) {
1146				warnx("elf_ndxscn failed: %s",
1147				    elf_errmsg(elferr));
1148				continue;
1149			}
1150		if (ndx >= ed->shnum) {
1151			warnx("section index of '%s' out of range", name);
1152			continue;
1153		}
1154		s = &ed->sl[ndx];
1155		s->name = name;
1156		s->scn = scn;
1157		s->off = sh.sh_offset;
1158		s->sz = sh.sh_size;
1159		s->entsize = sh.sh_entsize;
1160		s->align = sh.sh_addralign;
1161		s->type = sh.sh_type;
1162		s->flags = sh.sh_flags;
1163		s->addr = sh.sh_addr;
1164		s->link = sh.sh_link;
1165		s->info = sh.sh_info;
1166	} while ((scn = elf_nextscn(ed->elf, scn)) != NULL);
1167	elferr = elf_errno();
1168	if (elferr != 0)
1169		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
1170}
1171
1172/*
1173 * Release section related resources.
1174 */
1175static void
1176unload_sections(struct elfdump *ed)
1177{
1178	if (ed->sl != NULL) {
1179		free(ed->sl);
1180		ed->sl = NULL;
1181	}
1182}
1183
1184/*
1185 * Add a name to the '-N' name list.
1186 */
1187static void
1188add_name(struct elfdump *ed, const char *name)
1189{
1190	struct spec_name *sn;
1191
1192	if (find_name(ed, name))
1193		return;
1194	if ((sn = malloc(sizeof(*sn))) == NULL) {
1195		warn("malloc failed");
1196		return;
1197	}
1198	sn->name = name;
1199	STAILQ_INSERT_TAIL(&ed->snl, sn, sn_list);
1200}
1201
1202/*
1203 * Lookup a name in the '-N' name list.
1204 */
1205static struct spec_name *
1206find_name(struct elfdump *ed, const char *name)
1207{
1208	struct spec_name *sn;
1209
1210	STAILQ_FOREACH(sn, &ed->snl, sn_list) {
1211		if (!strcmp(sn->name, name))
1212			return (sn);
1213	}
1214
1215	return (NULL);
1216}
1217
1218/*
1219 * Retrieve the name of a symbol using the section index of the symbol
1220 * table and the index of the symbol within that table.
1221 */
1222static const char *
1223get_symbol_name(struct elfdump *ed, uint32_t symtab, int i)
1224{
1225	static char	 sname[64];
1226	struct section	*s;
1227	const char	*name;
1228	GElf_Sym	 sym;
1229	Elf_Data	*data;
1230	int		 elferr;
1231
1232	if (symtab >= ed->shnum)
1233		return ("");
1234	s = &ed->sl[symtab];
1235	if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM)
1236		return ("");
1237	(void) elf_errno();
1238	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1239		elferr = elf_errno();
1240		if (elferr != 0)
1241			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
1242		return ("");
1243	}
1244	if (gelf_getsym(data, i, &sym) != &sym)
1245		return ("");
1246	if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
1247		if (sym.st_shndx < ed->shnum) {
1248			snprintf(sname, sizeof(sname), "%s (section)",
1249			    ed->sl[sym.st_shndx].name);
1250			return (sname);
1251		} else
1252			return ("");
1253	}
1254	if ((name = elf_strptr(ed->elf, s->link, sym.st_name)) == NULL)
1255		return ("");
1256
1257	return (name);
1258}
1259
1260/*
1261 * Retrieve a string using string table section index and the string offset.
1262 */
1263static const char*
1264get_string(struct elfdump *ed, int strtab, size_t off)
1265{
1266	const char *name;
1267
1268	if ((name = elf_strptr(ed->elf, strtab, off)) == NULL)
1269		return ("");
1270
1271	return (name);
1272}
1273
1274/*
1275 * Dump the ELF Executable Header.
1276 */
1277static void
1278elf_print_ehdr(struct elfdump *ed)
1279{
1280
1281	if (!STAILQ_EMPTY(&ed->snl))
1282		return;
1283
1284	if (ed->flags & SOLARIS_FMT) {
1285		PRT("\nELF Header\n");
1286		PRT("  ei_magic:   { %#x, %c, %c, %c }\n",
1287		    ed->ehdr.e_ident[0], ed->ehdr.e_ident[1],
1288		    ed->ehdr.e_ident[2], ed->ehdr.e_ident[3]);
1289		PRT("  ei_class:   %-18s",
1290		    elf_class_str(ed->ehdr.e_ident[EI_CLASS]));
1291		PRT("  ei_data:      %s\n",
1292		    elf_data_str(ed->ehdr.e_ident[EI_DATA]));
1293		PRT("  e_machine:  %-18s", e_machines(ed->ehdr.e_machine));
1294		PRT("  e_version:    %s\n",
1295		    elf_version_str(ed->ehdr.e_version));
1296		PRT("  e_type:     %s\n", elf_type_str(ed->ehdr.e_type));
1297		PRT("  e_flags:    %18d\n", ed->ehdr.e_flags);
1298		PRT("  e_entry:    %#18jx", (uintmax_t)ed->ehdr.e_entry);
1299		PRT("  e_ehsize: %6d", ed->ehdr.e_ehsize);
1300		PRT("  e_shstrndx:%5d\n", ed->ehdr.e_shstrndx);
1301		PRT("  e_shoff:    %#18jx", (uintmax_t)ed->ehdr.e_shoff);
1302		PRT("  e_shentsize: %3d", ed->ehdr.e_shentsize);
1303		PRT("  e_shnum:   %5d\n", ed->ehdr.e_shnum);
1304		PRT("  e_phoff:    %#18jx", (uintmax_t)ed->ehdr.e_phoff);
1305		PRT("  e_phentsize: %3d", ed->ehdr.e_phentsize);
1306		PRT("  e_phnum:   %5d\n", ed->ehdr.e_phnum);
1307	} else {
1308		PRT("\nelf header:\n");
1309		PRT("\n");
1310		PRT("\te_ident: %s %s %s\n",
1311		    elf_class_str(ed->ehdr.e_ident[EI_CLASS]),
1312		    elf_data_str(ed->ehdr.e_ident[EI_DATA]),
1313		    ei_abis[ed->ehdr.e_ident[EI_OSABI]]);
1314		PRT("\te_type: %s\n", elf_type_str(ed->ehdr.e_type));
1315		PRT("\te_machine: %s\n", e_machines(ed->ehdr.e_machine));
1316		PRT("\te_version: %s\n", elf_version_str(ed->ehdr.e_version));
1317		PRT("\te_entry: %#jx\n", (uintmax_t)ed->ehdr.e_entry);
1318		PRT("\te_phoff: %ju\n", (uintmax_t)ed->ehdr.e_phoff);
1319		PRT("\te_shoff: %ju\n", (uintmax_t) ed->ehdr.e_shoff);
1320		PRT("\te_flags: %u\n", ed->ehdr.e_flags);
1321		PRT("\te_ehsize: %u\n", ed->ehdr.e_ehsize);
1322		PRT("\te_phentsize: %u\n", ed->ehdr.e_phentsize);
1323		PRT("\te_phnum: %u\n", ed->ehdr.e_phnum);
1324		PRT("\te_shentsize: %u\n", ed->ehdr.e_shentsize);
1325		PRT("\te_shnum: %u\n", ed->ehdr.e_shnum);
1326		PRT("\te_shstrndx: %u\n", ed->ehdr.e_shstrndx);
1327	}
1328}
1329
1330/*
1331 * Dump the ELF Program Header Table.
1332 */
1333static void
1334elf_print_phdr(struct elfdump *ed)
1335{
1336	GElf_Phdr	 ph;
1337	size_t		 phnum, i;
1338	int		 header;
1339
1340	if (elf_getphnum(ed->elf, &phnum) == 0) {
1341		warnx("elf_getphnum failed: %s", elf_errmsg(-1));
1342		return;
1343	}
1344	header = 0;
1345	for (i = 0; i < phnum; i++) {
1346		if (gelf_getphdr(ed->elf, i, &ph) != &ph) {
1347			warnx("elf_getphdr failed: %s", elf_errmsg(-1));
1348			continue;
1349		}
1350		if (!STAILQ_EMPTY(&ed->snl) &&
1351		    find_name(ed, elf_phdr_type_str(ph.p_type)) == NULL)
1352			continue;
1353		if (ed->flags & SOLARIS_FMT) {
1354			PRT("\nProgram Header[%zu]:\n", i);
1355			PRT("    p_vaddr:      %#-14jx", (uintmax_t)ph.p_vaddr);
1356			PRT("  p_flags:    [ %s ]\n",
1357			    p_flags[ph.p_flags & 0x7]);
1358			PRT("    p_paddr:      %#-14jx", (uintmax_t)ph.p_paddr);
1359			PRT("  p_type:     [ %s ]\n",
1360			    elf_phdr_type_str(ph.p_type));
1361			PRT("    p_filesz:     %#-14jx",
1362			    (uintmax_t)ph.p_filesz);
1363			PRT("  p_memsz:    %#jx\n", (uintmax_t)ph.p_memsz);
1364			PRT("    p_offset:     %#-14jx",
1365			    (uintmax_t)ph.p_offset);
1366			PRT("  p_align:    %#jx\n", (uintmax_t)ph.p_align);
1367		} else {
1368			if (!header) {
1369				PRT("\nprogram header:\n");
1370				header = 1;
1371			}
1372			PRT("\n");
1373			PRT("entry: %zu\n", i);
1374			PRT("\tp_type: %s\n", elf_phdr_type_str(ph.p_type));
1375			PRT("\tp_offset: %ju\n", (uintmax_t)ph.p_offset);
1376			PRT("\tp_vaddr: %#jx\n", (uintmax_t)ph.p_vaddr);
1377			PRT("\tp_paddr: %#jx\n", (uintmax_t)ph.p_paddr);
1378			PRT("\tp_filesz: %ju\n", (uintmax_t)ph.p_filesz);
1379			PRT("\tp_memsz: %ju\n", (uintmax_t)ph.p_memsz);
1380			PRT("\tp_flags: %s\n", p_flags[ph.p_flags & 0x7]);
1381			PRT("\tp_align: %ju\n", (uintmax_t)ph.p_align);
1382		}
1383	}
1384}
1385
1386/*
1387 * Dump the ELF Section Header Table.
1388 */
1389static void
1390elf_print_shdr(struct elfdump *ed)
1391{
1392	struct section *s;
1393	size_t i;
1394
1395	if (!STAILQ_EMPTY(&ed->snl))
1396		return;
1397
1398	if ((ed->flags & SOLARIS_FMT) == 0)
1399		PRT("\nsection header:\n");
1400	for (i = 0; i < ed->shnum; i++) {
1401		s = &ed->sl[i];
1402		if (ed->flags & SOLARIS_FMT) {
1403			if (i == 0)
1404				continue;
1405			PRT("\nSection Header[%zu]:", i);
1406			PRT("  sh_name: %s\n", s->name);
1407			PRT("    sh_addr:      %#-14jx", (uintmax_t)s->addr);
1408			if (s->flags != 0)
1409				PRT("  sh_flags:   [ %s ]\n", sh_flags(s->flags));
1410			else
1411				PRT("  sh_flags:   0\n");
1412			PRT("    sh_size:      %#-14jx", (uintmax_t)s->sz);
1413			PRT("  sh_type:    [ %s ]\n",
1414			    sh_types(ed->ehdr.e_machine, s->type));
1415			PRT("    sh_offset:    %#-14jx", (uintmax_t)s->off);
1416			PRT("  sh_entsize: %#jx\n", (uintmax_t)s->entsize);
1417			PRT("    sh_link:      %-14u", s->link);
1418			PRT("  sh_info:    %u\n", s->info);
1419			PRT("    sh_addralign: %#jx\n", (uintmax_t)s->align);
1420		} else {
1421			PRT("\n");
1422			PRT("entry: %ju\n", (uintmax_t)i);
1423			PRT("\tsh_name: %s\n", s->name);
1424			PRT("\tsh_type: %s\n",
1425			    sh_types(ed->ehdr.e_machine, s->type));
1426			PRT("\tsh_flags: %s\n", sh_flags(s->flags));
1427			PRT("\tsh_addr: %#jx\n", (uintmax_t)s->addr);
1428			PRT("\tsh_offset: %ju\n", (uintmax_t)s->off);
1429			PRT("\tsh_size: %ju\n", (uintmax_t)s->sz);
1430			PRT("\tsh_link: %u\n", s->link);
1431			PRT("\tsh_info: %u\n", s->info);
1432			PRT("\tsh_addralign: %ju\n", (uintmax_t)s->align);
1433			PRT("\tsh_entsize: %ju\n", (uintmax_t)s->entsize);
1434		}
1435	}
1436}
1437
1438/*
1439 * Return number of entries in the given section. We'd prefer ent_count be a
1440 * size_t, but libelf APIs already use int for section indices.
1441 */
1442static int
1443get_ent_count(const struct section *s, int *ent_count)
1444{
1445	if (s->entsize == 0) {
1446		warnx("section %s has entry size 0", s->name);
1447		return (0);
1448	} else if (s->sz / s->entsize > INT_MAX) {
1449		warnx("section %s has invalid section count", s->name);
1450		return (0);
1451	}
1452	*ent_count = (int)(s->sz / s->entsize);
1453	return (1);
1454}
1455
1456/*
1457 * Retrieve the content of the corresponding SHT_SUNW_versym section for
1458 * a symbol table section.
1459 */
1460static void
1461get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs)
1462{
1463	struct section	*s;
1464	Elf_Data	*data;
1465	size_t		 j;
1466	int		 elferr;
1467
1468	s = NULL;
1469	for (j = 0; j < ed->shnum; j++) {
1470		s = &ed->sl[j];
1471		if (s->type == SHT_SUNW_versym && s->link == (uint32_t)i)
1472			break;
1473	}
1474	if (j >= ed->shnum) {
1475		*vs = NULL;
1476		return;
1477	}
1478	(void) elf_errno();
1479	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1480		elferr = elf_errno();
1481		if (elferr != 0)
1482			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
1483		*vs = NULL;
1484		return;
1485	}
1486
1487	*vs = data->d_buf;
1488	assert(data->d_size == s->sz);
1489	if (!get_ent_count(s, nvs))
1490		*nvs = 0;
1491}
1492
1493/*
1494 * Dump the symbol table section.
1495 */
1496static void
1497elf_print_symtab(struct elfdump *ed, int i)
1498{
1499	struct section	*s;
1500	const char	*name;
1501	uint16_t	*vs;
1502	char		 idx[13];
1503	Elf_Data	*data;
1504	GElf_Sym	 sym;
1505	int		 len, j, elferr, nvs;
1506
1507	s = &ed->sl[i];
1508	if (ed->flags & SOLARIS_FMT)
1509		PRT("\nSymbol Table Section:  %s\n", s->name);
1510	else
1511		PRT("\nsymbol table (%s):\n", s->name);
1512	(void) elf_errno();
1513	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1514		elferr = elf_errno();
1515		if (elferr != 0)
1516			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
1517		return;
1518	}
1519	vs = NULL;
1520	nvs = 0;
1521	assert(data->d_size == s->sz);
1522	if (!get_ent_count(s, &len))
1523		return;
1524	if (ed->flags & SOLARIS_FMT) {
1525		if (ed->ec == ELFCLASS32)
1526			PRT("     index    value       ");
1527		else
1528			PRT("     index        value           ");
1529		PRT("size     type bind oth ver shndx       name\n");
1530		get_versym(ed, i, &vs, &nvs);
1531		if (vs != NULL && nvs != len) {
1532			warnx("#symbol not equal to #versym");
1533			vs = NULL;
1534		}
1535	}
1536	for (j = 0; j < len; j++) {
1537		if (gelf_getsym(data, j, &sym) != &sym) {
1538			warnx("gelf_getsym failed: %s", elf_errmsg(-1));
1539			continue;
1540		}
1541		name = get_string(ed, s->link, sym.st_name);
1542		if (ed->flags & SOLARIS_FMT) {
1543			snprintf(idx, sizeof(idx), "[%d]", j);
1544			if (ed->ec == ELFCLASS32)
1545				PRT("%10s  ", idx);
1546			else
1547				PRT("%10s      ", idx);
1548			PRT("0x%8.8jx ", (uintmax_t)sym.st_value);
1549			if (ed->ec == ELFCLASS32)
1550				PRT("0x%8.8jx  ", (uintmax_t)sym.st_size);
1551			else
1552				PRT("0x%12.12jx  ", (uintmax_t)sym.st_size);
1553			PRT("%s ", st_type_S(GELF_ST_TYPE(sym.st_info)));
1554			PRT("%s  ", st_bindings_S(GELF_ST_BIND(sym.st_info)));
1555			PRT("%c  ", st_others[sym.st_other]);
1556			PRT("%3u ", (vs == NULL ? 0 : vs[j]));
1557			PRT("%-11.11s ", sh_name(ed, sym.st_shndx));
1558			PRT("%s\n", name);
1559		} else {
1560			PRT("\nentry: %d\n", j);
1561			PRT("\tst_name: %s\n", name);
1562			PRT("\tst_value: %#jx\n", (uintmax_t)sym.st_value);
1563			PRT("\tst_size: %ju\n", (uintmax_t)sym.st_size);
1564			PRT("\tst_info: %s %s\n",
1565			    st_type(ed->ehdr.e_machine,
1566			    GELF_ST_TYPE(sym.st_info)),
1567			    st_bindings(GELF_ST_BIND(sym.st_info)));
1568			PRT("\tst_shndx: %ju\n", (uintmax_t)sym.st_shndx);
1569		}
1570	}
1571}
1572
1573/*
1574 * Dump the symbol tables. (.dynsym and .symtab)
1575 */
1576static void
1577elf_print_symtabs(struct elfdump *ed)
1578{
1579	size_t i;
1580
1581	for (i = 0; i < ed->shnum; i++)
1582		if ((ed->sl[i].type == SHT_SYMTAB ||
1583		    ed->sl[i].type == SHT_DYNSYM) &&
1584		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, ed->sl[i].name)))
1585			elf_print_symtab(ed, i);
1586}
1587
1588/*
1589 * Dump the content of .dynamic section.
1590 */
1591static void
1592elf_print_dynamic(struct elfdump *ed)
1593{
1594	struct section	*s;
1595	const char	*name;
1596	char		 idx[13];
1597	Elf_Data	*data;
1598	GElf_Dyn	 dyn;
1599	int		 elferr, i, len;
1600
1601	s = NULL;
1602	for (i = 0; (size_t)i < ed->shnum; i++) {
1603		s = &ed->sl[i];
1604		if (s->type == SHT_DYNAMIC &&
1605		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name)))
1606			break;
1607	}
1608	if ((size_t)i >= ed->shnum)
1609		return;
1610
1611	if (ed->flags & SOLARIS_FMT) {
1612		PRT("Dynamic Section:  %s\n", s->name);
1613		PRT("     index  tag               value\n");
1614	} else
1615		PRT("\ndynamic:\n");
1616	(void) elf_errno();
1617	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1618		elferr = elf_errno();
1619		if (elferr != 0)
1620			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
1621		return;
1622	}
1623	assert(data->d_size == s->sz);
1624	if (!get_ent_count(s, &len))
1625		return;
1626	for (i = 0; i < len; i++) {
1627		if (gelf_getdyn(data, i, &dyn) != &dyn) {
1628			warnx("gelf_getdyn failed: %s", elf_errmsg(-1));
1629			continue;
1630		}
1631
1632		if (ed->flags & SOLARIS_FMT) {
1633			snprintf(idx, sizeof(idx), "[%d]", i);
1634			PRT("%10s  %-16s ", idx, d_tags(dyn.d_tag));
1635		} else {
1636			PRT("\n");
1637			PRT("entry: %d\n", i);
1638			PRT("\td_tag: %s\n", d_tags(dyn.d_tag));
1639		}
1640		switch(dyn.d_tag) {
1641		case DT_NEEDED:
1642		case DT_SONAME:
1643		case DT_RPATH:
1644		case DT_RUNPATH:
1645			if ((name = elf_strptr(ed->elf, s->link,
1646				    dyn.d_un.d_val)) == NULL)
1647				name = "";
1648			if (ed->flags & SOLARIS_FMT)
1649				PRT("%#-16jx %s\n", (uintmax_t)dyn.d_un.d_val,
1650				    name);
1651			else
1652				PRT("\td_val: %s\n", name);
1653			break;
1654		case DT_PLTRELSZ:
1655		case DT_RELA:
1656		case DT_RELASZ:
1657		case DT_RELAENT:
1658		case DT_RELACOUNT:
1659		case DT_STRSZ:
1660		case DT_SYMENT:
1661		case DT_RELSZ:
1662		case DT_RELENT:
1663		case DT_PLTREL:
1664		case DT_VERDEF:
1665		case DT_VERDEFNUM:
1666		case DT_VERNEED:
1667		case DT_VERNEEDNUM:
1668		case DT_VERSYM:
1669			if (ed->flags & SOLARIS_FMT)
1670				PRT("%#jx\n", (uintmax_t)dyn.d_un.d_val);
1671			else
1672				PRT("\td_val: %ju\n",
1673				    (uintmax_t)dyn.d_un.d_val);
1674			break;
1675		case DT_PLTGOT:
1676		case DT_HASH:
1677		case DT_GNU_HASH:
1678		case DT_STRTAB:
1679		case DT_SYMTAB:
1680		case DT_INIT:
1681		case DT_FINI:
1682		case DT_REL:
1683		case DT_JMPREL:
1684		case DT_DEBUG:
1685			if (ed->flags & SOLARIS_FMT)
1686				PRT("%#jx\n", (uintmax_t)dyn.d_un.d_ptr);
1687			else
1688				PRT("\td_ptr: %#jx\n",
1689				    (uintmax_t)dyn.d_un.d_ptr);
1690			break;
1691		case DT_NULL:
1692		case DT_SYMBOLIC:
1693		case DT_TEXTREL:
1694		default:
1695			if (ed->flags & SOLARIS_FMT)
1696				PRT("\n");
1697			break;
1698		}
1699	}
1700}
1701
1702/*
1703 * Dump a .rel/.rela section entry.
1704 */
1705static void
1706elf_print_rel_entry(struct elfdump *ed, struct section *s, int j,
1707    struct rel_entry *r)
1708{
1709
1710	if (ed->flags & SOLARIS_FMT) {
1711		PRT("        %-23s ", elftc_reloc_type_str(ed->ehdr.e_machine,
1712			GELF_R_TYPE(r->u_r.rel.r_info)));
1713		PRT("%#12jx ", (uintmax_t)r->u_r.rel.r_offset);
1714		if (r->type == SHT_RELA)
1715			PRT("%10jd  ", (intmax_t)r->u_r.rela.r_addend);
1716		else
1717			PRT("    ");
1718		PRT("%-14s ", s->name);
1719		PRT("%s\n", r->symn);
1720	} else {
1721		PRT("\n");
1722		PRT("entry: %d\n", j);
1723		PRT("\tr_offset: %#jx\n", (uintmax_t)r->u_r.rel.r_offset);
1724		if (ed->ec == ELFCLASS32)
1725			PRT("\tr_info: %#jx\n", (uintmax_t)
1726			    ELF32_R_INFO(ELF64_R_SYM(r->u_r.rel.r_info),
1727			    ELF64_R_TYPE(r->u_r.rel.r_info)));
1728		else
1729			PRT("\tr_info: %#jx\n", (uintmax_t)r->u_r.rel.r_info);
1730		if (r->type == SHT_RELA)
1731			PRT("\tr_addend: %jd\n",
1732			    (intmax_t)r->u_r.rela.r_addend);
1733	}
1734}
1735
1736/*
1737 * Dump a relocation section of type SHT_RELA.
1738 */
1739static void
1740elf_print_rela(struct elfdump *ed, struct section *s, Elf_Data *data)
1741{
1742	struct rel_entry	r;
1743	int			j, len;
1744
1745	if (ed->flags & SOLARIS_FMT) {
1746		PRT("\nRelocation Section:  %s\n", s->name);
1747		PRT("        type                          offset     "
1748		    "addend  section        with respect to\n");
1749	} else
1750		PRT("\nrelocation with addend (%s):\n", s->name);
1751	r.type = SHT_RELA;
1752	assert(data->d_size == s->sz);
1753	if (!get_ent_count(s, &len))
1754		return;
1755	for (j = 0; j < len; j++) {
1756		if (gelf_getrela(data, j, &r.u_r.rela) != &r.u_r.rela) {
1757			warnx("gelf_getrela failed: %s",
1758			    elf_errmsg(-1));
1759			continue;
1760		}
1761		r.symn = get_symbol_name(ed, s->link,
1762		    GELF_R_SYM(r.u_r.rela.r_info));
1763		elf_print_rel_entry(ed, s, j, &r);
1764	}
1765}
1766
1767/*
1768 * Dump a relocation section of type SHT_REL.
1769 */
1770static void
1771elf_print_rel(struct elfdump *ed, struct section *s, Elf_Data *data)
1772{
1773	struct rel_entry	r;
1774	int			j, len;
1775
1776	if (ed->flags & SOLARIS_FMT) {
1777		PRT("\nRelocation Section:  %s\n", s->name);
1778		PRT("        type                          offset     "
1779		    "section        with respect to\n");
1780	} else
1781		PRT("\nrelocation (%s):\n", s->name);
1782	r.type = SHT_REL;
1783	assert(data->d_size == s->sz);
1784	if (!get_ent_count(s, &len))
1785		return;
1786	for (j = 0; j < len; j++) {
1787		if (gelf_getrel(data, j, &r.u_r.rel) != &r.u_r.rel) {
1788			warnx("gelf_getrel failed: %s", elf_errmsg(-1));
1789			continue;
1790		}
1791		r.symn = get_symbol_name(ed, s->link,
1792		    GELF_R_SYM(r.u_r.rel.r_info));
1793		elf_print_rel_entry(ed, s, j, &r);
1794	}
1795}
1796
1797/*
1798 * Dump relocation sections.
1799 */
1800static void
1801elf_print_reloc(struct elfdump *ed)
1802{
1803	struct section	*s;
1804	Elf_Data	*data;
1805	size_t		 i;
1806	int		 elferr;
1807
1808	for (i = 0; i < ed->shnum; i++) {
1809		s = &ed->sl[i];
1810		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1811		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) {
1812			(void) elf_errno();
1813			if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1814				elferr = elf_errno();
1815				if (elferr != 0)
1816					warnx("elf_getdata failed: %s",
1817					    elf_errmsg(elferr));
1818				continue;
1819			}
1820			if (s->type == SHT_REL)
1821				elf_print_rel(ed, s, data);
1822			else
1823				elf_print_rela(ed, s, data);
1824		}
1825	}
1826}
1827
1828/*
1829 * Dump the content of PT_INTERP segment.
1830 */
1831static void
1832elf_print_interp(struct elfdump *ed)
1833{
1834	const char *s;
1835	GElf_Phdr phdr;
1836	size_t filesize, i, phnum;
1837
1838	if (!STAILQ_EMPTY(&ed->snl) && find_name(ed, "PT_INTERP") == NULL)
1839		return;
1840
1841	if ((s = elf_rawfile(ed->elf, &filesize)) == NULL) {
1842		warnx("elf_rawfile failed: %s", elf_errmsg(-1));
1843		return;
1844	}
1845	if (!elf_getphnum(ed->elf, &phnum)) {
1846		warnx("elf_getphnum failed: %s", elf_errmsg(-1));
1847		return;
1848	}
1849	for (i = 0; i < phnum; i++) {
1850		if (gelf_getphdr(ed->elf, i, &phdr) != &phdr) {
1851			warnx("elf_getphdr failed: %s", elf_errmsg(-1));
1852			continue;
1853		}
1854		if (phdr.p_type == PT_INTERP) {
1855			if (phdr.p_offset >= filesize) {
1856				warnx("invalid phdr offset");
1857				continue;
1858			}
1859			PRT("\ninterp:\n");
1860			PRT("\t%s\n", s + phdr.p_offset);
1861		}
1862	}
1863}
1864
1865/*
1866 * Search the relocation sections for entries referring to the .got section.
1867 */
1868static void
1869find_gotrel(struct elfdump *ed, struct section *gs, struct rel_entry *got)
1870{
1871	struct section		*s;
1872	struct rel_entry	 r;
1873	Elf_Data		*data;
1874	size_t			 i;
1875	int			 elferr, j, k, len;
1876
1877	for(i = 0; i < ed->shnum; i++) {
1878		s = &ed->sl[i];
1879		if (s->type != SHT_REL && s->type != SHT_RELA)
1880			continue;
1881		(void) elf_errno();
1882		if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1883			elferr = elf_errno();
1884			if (elferr != 0)
1885				warnx("elf_getdata failed: %s",
1886				    elf_errmsg(elferr));
1887			return;
1888		}
1889		memset(&r, 0, sizeof(struct rel_entry));
1890		r.type = s->type;
1891		assert(data->d_size == s->sz);
1892		if (!get_ent_count(s, &len))
1893			return;
1894		for (j = 0; j < len; j++) {
1895			if (s->type == SHT_REL) {
1896				if (gelf_getrel(data, j, &r.u_r.rel) !=
1897				    &r.u_r.rel) {
1898					warnx("gelf_getrel failed: %s",
1899					    elf_errmsg(-1));
1900					continue;
1901				}
1902			} else {
1903				if (gelf_getrela(data, j, &r.u_r.rela) !=
1904				    &r.u_r.rela) {
1905					warnx("gelf_getrel failed: %s",
1906					    elf_errmsg(-1));
1907					continue;
1908				}
1909			}
1910			if (r.u_r.rel.r_offset >= gs->addr &&
1911			    r.u_r.rel.r_offset < gs->addr + gs->sz) {
1912				r.symn = get_symbol_name(ed, s->link,
1913				    GELF_R_SYM(r.u_r.rel.r_info));
1914				k = (r.u_r.rel.r_offset - gs->addr) /
1915				    gs->entsize;
1916				memcpy(&got[k], &r, sizeof(struct rel_entry));
1917			}
1918		}
1919	}
1920}
1921
1922static void
1923elf_print_got_section(struct elfdump *ed, struct section *s)
1924{
1925	struct rel_entry	*got;
1926	Elf_Data		*data, dst;
1927	int			 elferr, i, len;
1928
1929	if (s->entsize == 0) {
1930		/* XXX IA64 GOT section generated by gcc has entry size 0. */
1931		if (s->align != 0)
1932			s->entsize = s->align;
1933		else
1934			return;
1935	}
1936
1937	if (!get_ent_count(s, &len))
1938		return;
1939	if (ed->flags & SOLARIS_FMT)
1940		PRT("\nGlobal Offset Table Section:  %s  (%d entries)\n",
1941		    s->name, len);
1942	else
1943		PRT("\nglobal offset table: %s\n", s->name);
1944	(void) elf_errno();
1945	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
1946		elferr = elf_errno();
1947		if (elferr != 0)
1948			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
1949		return;
1950	}
1951
1952	/*
1953	 * GOT section has section type SHT_PROGBITS, thus libelf treats it as
1954	 * byte stream and will not perform any translation on it. As a result,
1955	 * an exlicit call to gelf_xlatetom is needed here. Depends on arch,
1956	 * GOT section should be translated to either WORD or XWORD.
1957	 */
1958	if (ed->ec == ELFCLASS32)
1959		data->d_type = ELF_T_WORD;
1960	else
1961		data->d_type = ELF_T_XWORD;
1962	memcpy(&dst, data, sizeof(Elf_Data));
1963	if (gelf_xlatetom(ed->elf, &dst, data, ed->ehdr.e_ident[EI_DATA]) !=
1964	    &dst) {
1965		warnx("gelf_xlatetom failed: %s", elf_errmsg(-1));
1966		return;
1967	}
1968	assert(dst.d_size == s->sz);
1969	if (ed->flags & SOLARIS_FMT) {
1970		/*
1971		 * In verbose/Solaris mode, we search the relocation sections
1972		 * and try to find the corresponding reloc entry for each GOT
1973		 * section entry.
1974		 */
1975		if ((got = calloc(len, sizeof(struct rel_entry))) == NULL)
1976			err(EXIT_FAILURE, "calloc failed");
1977		find_gotrel(ed, s, got);
1978		if (ed->ec == ELFCLASS32) {
1979			PRT(" ndx     addr      value    reloc              ");
1980			PRT("addend   symbol\n");
1981		} else {
1982			PRT(" ndx     addr              value             ");
1983			PRT("reloc              addend       symbol\n");
1984		}
1985		for(i = 0; i < len; i++) {
1986			PRT("[%5.5d]  ", i);
1987			if (ed->ec == ELFCLASS32) {
1988				PRT("%-8.8jx  ",
1989				    (uintmax_t) (s->addr + i * s->entsize));
1990				PRT("%-8.8x ", *((uint32_t *)dst.d_buf + i));
1991			} else {
1992				PRT("%-16.16jx  ",
1993				    (uintmax_t) (s->addr + i * s->entsize));
1994				PRT("%-16.16jx  ",
1995				    (uintmax_t) *((uint64_t *)dst.d_buf + i));
1996			}
1997			PRT("%-18s ", elftc_reloc_type_str(ed->ehdr.e_machine,
1998				GELF_R_TYPE(got[i].u_r.rel.r_info)));
1999			if (ed->ec == ELFCLASS32)
2000				PRT("%-8.8jd ",
2001				    (intmax_t)got[i].u_r.rela.r_addend);
2002			else
2003				PRT("%-12.12jd ",
2004				    (intmax_t)got[i].u_r.rela.r_addend);
2005			if (got[i].symn == NULL)
2006				got[i].symn = "";
2007			PRT("%s\n", got[i].symn);
2008		}
2009		free(got);
2010	} else {
2011		for(i = 0; i < len; i++) {
2012			PRT("\nentry: %d\n", i);
2013			if (ed->ec == ELFCLASS32)
2014				PRT("\t%#x\n", *((uint32_t *)dst.d_buf + i));
2015			else
2016				PRT("\t%#jx\n",
2017				    (uintmax_t) *((uint64_t *)dst.d_buf + i));
2018		}
2019	}
2020}
2021
2022/*
2023 * Dump the content of Global Offset Table section.
2024 */
2025static void
2026elf_print_got(struct elfdump *ed)
2027{
2028	struct section	*s;
2029	size_t		 i;
2030
2031	if (!STAILQ_EMPTY(&ed->snl))
2032		return;
2033
2034	s = NULL;
2035	for (i = 0; i < ed->shnum; i++) {
2036		s = &ed->sl[i];
2037		if (s->name && !strncmp(s->name, ".got", 4) &&
2038		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name)))
2039			elf_print_got_section(ed, s);
2040	}
2041}
2042
2043/*
2044 * Dump the content of .note.ABI-tag section.
2045 */
2046static void
2047elf_print_note(struct elfdump *ed)
2048{
2049	struct section	*s;
2050	Elf_Data        *data;
2051	Elf_Note	*en;
2052	uint32_t	 namesz;
2053	uint32_t	 descsz;
2054	uint32_t	 desc;
2055	size_t		 count;
2056	int		 elferr, i;
2057	uint8_t		*src;
2058	char		 idx[17];
2059
2060	s = NULL;
2061	for (i = 0; (size_t)i < ed->shnum; i++) {
2062		s = &ed->sl[i];
2063		if (s->type == SHT_NOTE && s->name &&
2064		    !strcmp(s->name, ".note.ABI-tag") &&
2065		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name)))
2066			break;
2067	}
2068	if ((size_t)i >= ed->shnum)
2069		return;
2070	if (ed->flags & SOLARIS_FMT)
2071		PRT("\nNote Section:  %s\n", s->name);
2072	else
2073		PRT("\nnote (%s):\n", s->name);
2074	(void) elf_errno();
2075	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
2076		elferr = elf_errno();
2077		if (elferr != 0)
2078			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
2079		return;
2080	}
2081	src = data->d_buf;
2082	count = data->d_size;
2083	while (count > sizeof(Elf_Note)) {
2084		en = (Elf_Note *) (uintptr_t) src;
2085		namesz = en->n_namesz;
2086		descsz = en->n_descsz;
2087		src += sizeof(Elf_Note);
2088		count -= sizeof(Elf_Note);
2089		if (roundup2(namesz, 4) + roundup2(descsz, 4) > count) {
2090			warnx("truncated note section");
2091			return;
2092		}
2093		if (ed->flags & SOLARIS_FMT) {
2094			PRT("\n    type   %#x\n", en->n_type);
2095			PRT("    namesz %#x:\n", en->n_namesz);
2096			PRT("%s\n", src);
2097		} else
2098			PRT("\t%s ", src);
2099		src += roundup2(namesz, 4);
2100		count -= roundup2(namesz, 4);
2101
2102		/*
2103		 * Note that we dump the whole desc part if we're in
2104		 * "Solaris mode", while in the normal mode, we only look
2105		 * at the first 4 bytes (a 32bit word) of the desc, i.e,
2106		 * we assume that it's always a FreeBSD version number.
2107		 */
2108		if (ed->flags & SOLARIS_FMT) {
2109			PRT("    descsz %#x:", en->n_descsz);
2110			for (i = 0; (uint32_t)i < descsz; i++) {
2111				if ((i & 0xF) == 0) {
2112					snprintf(idx, sizeof(idx), "desc[%d]",
2113					    i);
2114					PRT("\n      %-9s", idx);
2115				} else if ((i & 0x3) == 0)
2116					PRT("  ");
2117				PRT(" %2.2x", src[i]);
2118			}
2119			PRT("\n");
2120		} else {
2121			if (ed->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
2122				desc = be32dec(src);
2123			else
2124				desc = le32dec(src);
2125			PRT("%d\n", desc);
2126		}
2127		src += roundup2(descsz, 4);
2128		count -= roundup2(descsz, 4);
2129	}
2130}
2131
2132/*
2133 * Dump a hash table.
2134 */
2135static void
2136elf_print_svr4_hash(struct elfdump *ed, struct section *s)
2137{
2138	Elf_Data	*data;
2139	uint32_t	*buf;
2140	uint32_t	*bucket, *chain;
2141	uint32_t	 nbucket, nchain;
2142	uint32_t	*bl, *c, maxl, total;
2143	uint32_t	 i, j;
2144	int		 first, elferr;
2145	char		 idx[10];
2146
2147	if (ed->flags & SOLARIS_FMT)
2148		PRT("\nHash Section:  %s\n", s->name);
2149	else
2150		PRT("\nhash table (%s):\n", s->name);
2151	(void) elf_errno();
2152	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
2153		elferr = elf_errno();
2154		if (elferr != 0)
2155			warnx("elf_getdata failed: %s",
2156			    elf_errmsg(elferr));
2157		return;
2158	}
2159	if (data->d_size < 2 * sizeof(uint32_t)) {
2160		warnx(".hash section too small");
2161		return;
2162	}
2163	buf = data->d_buf;
2164	nbucket = buf[0];
2165	nchain = buf[1];
2166	if (nbucket <= 0 || nchain <= 0) {
2167		warnx("Malformed .hash section");
2168		return;
2169	}
2170	if (data->d_size !=
2171	    ((uint64_t)nbucket + (uint64_t)nchain + 2) * sizeof(uint32_t)) {
2172		warnx("Malformed .hash section");
2173		return;
2174	}
2175	bucket = &buf[2];
2176	chain = &buf[2 + nbucket];
2177
2178	if (ed->flags & SOLARIS_FMT) {
2179		maxl = 0;
2180		if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
2181			err(EXIT_FAILURE, "calloc failed");
2182		for (i = 0; i < nbucket; i++)
2183			for (j = bucket[i]; j > 0 && j < nchain; j = chain[j])
2184				if (++bl[i] > maxl)
2185					maxl = bl[i];
2186		if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
2187			err(EXIT_FAILURE, "calloc failed");
2188		for (i = 0; i < nbucket; i++)
2189			c[bl[i]]++;
2190		PRT("    bucket    symndx    name\n");
2191		for (i = 0; i < nbucket; i++) {
2192			first = 1;
2193			for (j = bucket[i]; j > 0 && j < nchain; j = chain[j]) {
2194				if (first) {
2195					PRT("%10d  ", i);
2196					first = 0;
2197				} else
2198					PRT("            ");
2199				snprintf(idx, sizeof(idx), "[%d]", j);
2200				PRT("%-10s  ", idx);
2201				PRT("%s\n", get_symbol_name(ed, s->link, j));
2202			}
2203		}
2204		PRT("\n");
2205		total = 0;
2206		for (i = 0; i <= maxl; i++) {
2207			total += c[i] * i;
2208			PRT("%10u  buckets contain %8d symbols\n", c[i], i);
2209		}
2210		PRT("%10u  buckets         %8u symbols (globals)\n", nbucket,
2211		    total);
2212	} else {
2213		PRT("\nnbucket: %u\n", nbucket);
2214		PRT("nchain: %u\n\n", nchain);
2215		for (i = 0; i < nbucket; i++)
2216			PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]);
2217		for (i = 0; i < nchain; i++)
2218			PRT("chain[%d]:\n\t%u\n\n", i, chain[i]);
2219	}
2220}
2221
2222/*
2223 * Dump a 64bit hash table.
2224 */
2225static void
2226elf_print_svr4_hash64(struct elfdump *ed, struct section *s)
2227{
2228	Elf_Data	*data, dst;
2229	uint64_t	*buf;
2230	uint64_t	*bucket, *chain;
2231	uint64_t	 nbucket, nchain;
2232	uint64_t	*bl, *c, j, maxl, total;
2233	size_t		 i;
2234	int		 elferr, first;
2235	char		 idx[10];
2236
2237	if (ed->flags & SOLARIS_FMT)
2238		PRT("\nHash Section:  %s\n", s->name);
2239	else
2240		PRT("\nhash table (%s):\n", s->name);
2241
2242	/*
2243	 * ALPHA uses 64-bit hash entries. Since libelf assumes that
2244	 * .hash section contains only 32-bit entry, an explicit
2245	 * gelf_xlatetom is needed here.
2246	 */
2247	(void) elf_errno();
2248	if ((data = elf_rawdata(s->scn, NULL)) == NULL) {
2249		elferr = elf_errno();
2250		if (elferr != 0)
2251			warnx("elf_rawdata failed: %s",
2252			    elf_errmsg(elferr));
2253		return;
2254	}
2255	data->d_type = ELF_T_XWORD;
2256	memcpy(&dst, data, sizeof(Elf_Data));
2257	if (gelf_xlatetom(ed->elf, &dst, data,
2258		ed->ehdr.e_ident[EI_DATA]) != &dst) {
2259		warnx("gelf_xlatetom failed: %s", elf_errmsg(-1));
2260		return;
2261	}
2262	if (dst.d_size < 2 * sizeof(uint64_t)) {
2263		warnx(".hash section too small");
2264		return;
2265	}
2266	buf = dst.d_buf;
2267	nbucket = buf[0];
2268	nchain = buf[1];
2269	if (nbucket <= 0 || nchain <= 0) {
2270		warnx("Malformed .hash section");
2271		return;
2272	}
2273	if (dst.d_size != (nbucket + nchain + 2) * sizeof(uint64_t)) {
2274		warnx("Malformed .hash section");
2275		return;
2276	}
2277	bucket = &buf[2];
2278	chain = &buf[2 + nbucket];
2279
2280	if (ed->flags & SOLARIS_FMT) {
2281		maxl = 0;
2282		if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
2283			err(EXIT_FAILURE, "calloc failed");
2284		for (i = 0; i < nbucket; i++)
2285			for (j = bucket[i]; j > 0 && j < nchain; j = chain[j])
2286				if (++bl[i] > maxl)
2287					maxl = bl[i];
2288		if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
2289			err(EXIT_FAILURE, "calloc failed");
2290		for (i = 0; i < nbucket; i++)
2291			c[bl[i]]++;
2292		PRT("    bucket    symndx    name\n");
2293		for (i = 0; i < nbucket; i++) {
2294			first = 1;
2295			for (j = bucket[i]; j > 0 && j < nchain; j = chain[j]) {
2296				if (first) {
2297					PRT("%10zu  ", i);
2298					first = 0;
2299				} else
2300					PRT("            ");
2301				snprintf(idx, sizeof(idx), "[%zu]", (size_t)j);
2302				PRT("%-10s  ", idx);
2303				PRT("%s\n", get_symbol_name(ed, s->link, j));
2304			}
2305		}
2306		PRT("\n");
2307		total = 0;
2308		for (i = 0; i <= maxl; i++) {
2309			total += c[i] * i;
2310			PRT("%10ju  buckets contain %8zu symbols\n",
2311			    (uintmax_t)c[i], i);
2312		}
2313		PRT("%10ju  buckets         %8ju symbols (globals)\n",
2314		    (uintmax_t)nbucket, (uintmax_t)total);
2315	} else {
2316		PRT("\nnbucket: %ju\n", (uintmax_t)nbucket);
2317		PRT("nchain: %ju\n\n", (uintmax_t)nchain);
2318		for (i = 0; i < nbucket; i++)
2319			PRT("bucket[%zu]:\n\t%ju\n\n", i, (uintmax_t)bucket[i]);
2320		for (i = 0; i < nchain; i++)
2321			PRT("chain[%zu]:\n\t%ju\n\n", i, (uintmax_t)chain[i]);
2322	}
2323
2324}
2325
2326/*
2327 * Dump a GNU hash table.
2328 */
2329static void
2330elf_print_gnu_hash(struct elfdump *ed, struct section *s)
2331{
2332	struct section	*ds;
2333	Elf_Data	*data;
2334	uint32_t	*buf;
2335	uint32_t	*bucket, *chain;
2336	uint32_t	 nbucket, nchain, symndx, maskwords, shift2;
2337	uint32_t	*bl, *c, maxl, total;
2338	uint32_t	 i, j;
2339	int		 first, elferr, dynsymcount;
2340	char		 idx[10];
2341
2342	if (ed->flags & SOLARIS_FMT)
2343		PRT("\nGNU Hash Section:  %s\n", s->name);
2344	else
2345		PRT("\ngnu hash table (%s):\n", s->name);
2346	(void) elf_errno();
2347	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
2348		elferr = elf_errno();
2349		if (elferr != 0)
2350			warnx("elf_getdata failed: %s",
2351			    elf_errmsg(elferr));
2352		return;
2353	}
2354	if (data->d_size < 4 * sizeof(uint32_t)) {
2355		warnx(".gnu.hash section too small");
2356		return;
2357	}
2358	buf = data->d_buf;
2359	nbucket = buf[0];
2360	symndx = buf[1];
2361	maskwords = buf[2];
2362	shift2 = buf[3];
2363	buf += 4;
2364	if (s->link >= ed->shnum) {
2365		warnx("Malformed .gnu.hash section");
2366		return;
2367	}
2368	ds = &ed->sl[s->link];
2369	if (!get_ent_count(ds, &dynsymcount))
2370		return;
2371	if (symndx >= (uint32_t)dynsymcount) {
2372		warnx("Malformed .gnu.hash section");
2373		return;
2374	}
2375	nchain = dynsymcount - symndx;
2376	if (data->d_size != 4 * sizeof(uint32_t) + maskwords *
2377	    (ed->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) +
2378	    ((uint64_t)nbucket + (uint64_t)nchain) * sizeof(uint32_t)) {
2379		warnx("Malformed .gnu.hash section");
2380		return;
2381	}
2382	bucket = buf + (ed->ec == ELFCLASS32 ? maskwords : maskwords * 2);
2383	chain = bucket + nbucket;
2384
2385	if (ed->flags & SOLARIS_FMT) {
2386		maxl = 0;
2387		if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
2388			err(EXIT_FAILURE, "calloc failed");
2389		for (i = 0; i < nbucket; i++)
2390			for (j = bucket[i]; j > 0 && j - symndx < nchain; j++) {
2391				if (++bl[i] > maxl)
2392					maxl = bl[i];
2393				if (chain[j - symndx] & 1)
2394					break;
2395			}
2396		if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
2397			err(EXIT_FAILURE, "calloc failed");
2398		for (i = 0; i < nbucket; i++)
2399			c[bl[i]]++;
2400		PRT("    bucket    symndx    name\n");
2401		for (i = 0; i < nbucket; i++) {
2402			first = 1;
2403			for (j = bucket[i]; j > 0 && j - symndx < nchain; j++) {
2404				if (first) {
2405					PRT("%10d  ", i);
2406					first = 0;
2407				} else
2408					PRT("            ");
2409				snprintf(idx, sizeof(idx), "[%d]", j );
2410				PRT("%-10s  ", idx);
2411				PRT("%s\n", get_symbol_name(ed, s->link, j));
2412				if (chain[j - symndx] & 1)
2413					break;
2414			}
2415		}
2416		PRT("\n");
2417		total = 0;
2418		for (i = 0; i <= maxl; i++) {
2419			total += c[i] * i;
2420			PRT("%10u  buckets contain %8d symbols\n", c[i], i);
2421		}
2422		PRT("%10u  buckets         %8u symbols (globals)\n", nbucket,
2423		    total);
2424	} else {
2425		PRT("\nnbucket: %u\n", nbucket);
2426		PRT("symndx: %u\n", symndx);
2427		PRT("maskwords: %u\n", maskwords);
2428		PRT("shift2: %u\n", shift2);
2429		PRT("nchain: %u\n\n", nchain);
2430		for (i = 0; i < nbucket; i++)
2431			PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]);
2432		for (i = 0; i < nchain; i++)
2433			PRT("chain[%d]:\n\t%u\n\n", i, chain[i]);
2434	}
2435}
2436
2437/*
2438 * Dump hash tables.
2439 */
2440static void
2441elf_print_hash(struct elfdump *ed)
2442{
2443	struct section	*s;
2444	size_t		 i;
2445
2446	for (i = 0; i < ed->shnum; i++) {
2447		s = &ed->sl[i];
2448		if ((s->type == SHT_HASH || s->type == SHT_GNU_HASH) &&
2449		    (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) {
2450			if (s->type == SHT_GNU_HASH)
2451				elf_print_gnu_hash(ed, s);
2452			else if (ed->ehdr.e_machine == EM_ALPHA &&
2453			    s->entsize == 8)
2454				elf_print_svr4_hash64(ed, s);
2455			else
2456				elf_print_svr4_hash(ed, s);
2457		}
2458	}
2459}
2460
2461/*
2462 * Dump the content of a Version Definition(SHT_SUNW_Verdef) Section.
2463 */
2464static void
2465elf_print_verdef(struct elfdump *ed, struct section *s)
2466{
2467	Elf_Data	*data;
2468	Elf32_Verdef	*vd;
2469	Elf32_Verdaux	*vda;
2470	const char 	*str;
2471	char		 idx[10];
2472	uint8_t		*buf, *end, *buf2;
2473	int		 i, j, elferr, count;
2474
2475	if (ed->flags & SOLARIS_FMT)
2476		PRT("Version Definition Section:  %s\n", s->name);
2477	else
2478		PRT("\nversion definition section (%s):\n", s->name);
2479	(void) elf_errno();
2480	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
2481		elferr = elf_errno();
2482		if (elferr != 0)
2483			warnx("elf_getdata failed: %s",
2484			    elf_errmsg(elferr));
2485		return;
2486	}
2487	buf = data->d_buf;
2488	end = buf + data->d_size;
2489	i = 0;
2490	if (ed->flags & SOLARIS_FMT)
2491		PRT("     index  version                     dependency\n");
2492	while (buf + sizeof(Elf32_Verdef) <= end) {
2493		vd = (Elf32_Verdef *) (uintptr_t) buf;
2494		if (ed->flags & SOLARIS_FMT) {
2495			snprintf(idx, sizeof(idx), "[%d]", vd->vd_ndx);
2496			PRT("%10s  ", idx);
2497		} else {
2498			PRT("\nentry: %d\n", i++);
2499			PRT("\tvd_version: %u\n", vd->vd_version);
2500			PRT("\tvd_flags: %u\n", vd->vd_flags);
2501			PRT("\tvd_ndx: %u\n", vd->vd_ndx);
2502			PRT("\tvd_cnt: %u\n", vd->vd_cnt);
2503			PRT("\tvd_hash: %u\n", vd->vd_hash);
2504			PRT("\tvd_aux: %u\n", vd->vd_aux);
2505			PRT("\tvd_next: %u\n\n", vd->vd_next);
2506		}
2507		buf2 = buf + vd->vd_aux;
2508		j = 0;
2509		count = 0;
2510		while (buf2 + sizeof(Elf32_Verdaux) <= end && j < vd->vd_cnt) {
2511			vda = (Elf32_Verdaux *) (uintptr_t) buf2;
2512			str = get_string(ed, s->link, vda->vda_name);
2513			if (ed->flags & SOLARIS_FMT) {
2514				if (count == 0)
2515					PRT("%-26.26s", str);
2516				else if (count == 1)
2517					PRT("  %-20.20s", str);
2518				else {
2519					PRT("\n%40.40s", "");
2520					PRT("%s", str);
2521				}
2522			} else {
2523				PRT("\t\tvda: %d\n", j++);
2524				PRT("\t\t\tvda_name: %s\n", str);
2525				PRT("\t\t\tvda_next: %u\n", vda->vda_next);
2526			}
2527			if (vda->vda_next == 0) {
2528				if (ed->flags & SOLARIS_FMT) {
2529					if (vd->vd_flags & VER_FLG_BASE) {
2530						if (count == 0)
2531							PRT("%-20.20s", "");
2532						PRT("%s", "[ BASE ]");
2533					}
2534					PRT("\n");
2535				}
2536				break;
2537			}
2538			if (ed->flags & SOLARIS_FMT)
2539				count++;
2540			buf2 += vda->vda_next;
2541		}
2542		if (vd->vd_next == 0)
2543			break;
2544		buf += vd->vd_next;
2545	}
2546}
2547
2548/*
2549 * Dump the content of a Version Needed(SHT_SUNW_Verneed) Section.
2550 */
2551static void
2552elf_print_verneed(struct elfdump *ed, struct section *s)
2553{
2554	Elf_Data	*data;
2555	Elf32_Verneed	*vn;
2556	Elf32_Vernaux	*vna;
2557	uint8_t		*buf, *end, *buf2;
2558	int		 i, j, elferr, first;
2559
2560	if (ed->flags & SOLARIS_FMT)
2561		PRT("\nVersion Needed Section:  %s\n", s->name);
2562	else
2563		PRT("\nversion need section (%s):\n", s->name);
2564	(void) elf_errno();
2565	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
2566		elferr = elf_errno();
2567		if (elferr != 0)
2568			warnx("elf_getdata failed: %s",
2569			    elf_errmsg(elferr));
2570		return;
2571	}
2572	buf = data->d_buf;
2573	end = buf + data->d_size;
2574	if (ed->flags & SOLARIS_FMT)
2575		PRT("            file                        version\n");
2576	i = 0;
2577	while (buf + sizeof(Elf32_Verneed) <= end) {
2578		vn = (Elf32_Verneed *) (uintptr_t) buf;
2579		if (ed->flags & SOLARIS_FMT)
2580			PRT("            %-26.26s  ",
2581			    get_string(ed, s->link, vn->vn_file));
2582		else {
2583			PRT("\nentry: %d\n", i++);
2584			PRT("\tvn_version: %u\n", vn->vn_version);
2585			PRT("\tvn_cnt: %u\n", vn->vn_cnt);
2586			PRT("\tvn_file: %s\n",
2587			    get_string(ed, s->link, vn->vn_file));
2588			PRT("\tvn_aux: %u\n", vn->vn_aux);
2589			PRT("\tvn_next: %u\n\n", vn->vn_next);
2590		}
2591		buf2 = buf + vn->vn_aux;
2592		j = 0;
2593		first = 1;
2594		while (buf2 + sizeof(Elf32_Vernaux) <= end && j < vn->vn_cnt) {
2595			vna = (Elf32_Vernaux *) (uintptr_t) buf2;
2596			if (ed->flags & SOLARIS_FMT) {
2597				if (!first)
2598					PRT("%40.40s", "");
2599				else
2600					first = 0;
2601				PRT("%s\n", get_string(ed, s->link,
2602				    vna->vna_name));
2603			} else {
2604				PRT("\t\tvna: %d\n", j++);
2605				PRT("\t\t\tvna_hash: %u\n", vna->vna_hash);
2606				PRT("\t\t\tvna_flags: %u\n", vna->vna_flags);
2607				PRT("\t\t\tvna_other: %u\n", vna->vna_other);
2608				PRT("\t\t\tvna_name: %s\n",
2609				    get_string(ed, s->link, vna->vna_name));
2610				PRT("\t\t\tvna_next: %u\n", vna->vna_next);
2611			}
2612			if (vna->vna_next == 0)
2613				break;
2614			buf2 += vna->vna_next;
2615		}
2616		if (vn->vn_next == 0)
2617			break;
2618		buf += vn->vn_next;
2619	}
2620}
2621
2622/*
2623 * Dump the symbol-versioning sections.
2624 */
2625static void
2626elf_print_symver(struct elfdump *ed)
2627{
2628	struct section	*s;
2629	size_t		 i;
2630
2631	for (i = 0; i < ed->shnum; i++) {
2632		s = &ed->sl[i];
2633		if (!STAILQ_EMPTY(&ed->snl) && !find_name(ed, s->name))
2634			continue;
2635		if (s->type == SHT_SUNW_verdef)
2636			elf_print_verdef(ed, s);
2637		if (s->type == SHT_SUNW_verneed)
2638			elf_print_verneed(ed, s);
2639	}
2640}
2641
2642/*
2643 * Dump the ELF checksum. See gelf_checksum(3) for details.
2644 */
2645static void
2646elf_print_checksum(struct elfdump *ed)
2647{
2648
2649	if (!STAILQ_EMPTY(&ed->snl))
2650		return;
2651
2652	PRT("\nelf checksum: %#lx\n", gelf_checksum(ed->elf));
2653}
2654
2655#define	USAGE_MESSAGE	"\
2656Usage: %s [options] file...\n\
2657  Display information about ELF objects and ar(1) archives.\n\n\
2658  Options:\n\
2659  -a                        Show all information.\n\
2660  -c                        Show shared headers.\n\
2661  -d                        Show dynamic symbols.\n\
2662  -e                        Show the ELF header.\n\
2663  -G                        Show the GOT.\n\
2664  -H | --help               Show a usage message and exit.\n\
2665  -h                        Show hash values.\n\
2666  -i                        Show the dynamic interpreter.\n\
2667  -k                        Show the ELF checksum.\n\
2668  -n                        Show the contents of note sections.\n\
2669  -N NAME                   Show the section named \"NAME\".\n\
2670  -p                        Show the program header.\n\
2671  -r                        Show relocations.\n\
2672  -s                        Show the symbol table.\n\
2673  -S                        Use the Solaris elfdump format.\n\
2674  -v                        Show symbol-versioning information.\n\
2675  -V | --version            Print a version identifier and exit.\n\
2676  -w FILE                   Write output to \"FILE\".\n"
2677
2678static void
2679usage(void)
2680{
2681	fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
2682	exit(EXIT_FAILURE);
2683}
2684