xref: /freebsd/contrib/elftoolchain/readelf/readelf.c (revision 2c23cb7c270bad30cda301d64efdb024ca5510ac)
1*2c23cb7cSEd Maste /*-
2*2c23cb7cSEd Maste  * Copyright (c) 2009,2010 Kai Wang
3*2c23cb7cSEd Maste  * All rights reserved.
4*2c23cb7cSEd Maste  *
5*2c23cb7cSEd Maste  * Redistribution and use in source and binary forms, with or without
6*2c23cb7cSEd Maste  * modification, are permitted provided that the following conditions
7*2c23cb7cSEd Maste  * are met:
8*2c23cb7cSEd Maste  * 1. Redistributions of source code must retain the above copyright
9*2c23cb7cSEd Maste  *    notice, this list of conditions and the following disclaimer.
10*2c23cb7cSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11*2c23cb7cSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12*2c23cb7cSEd Maste  *    documentation and/or other materials provided with the distribution.
13*2c23cb7cSEd Maste  *
14*2c23cb7cSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*2c23cb7cSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*2c23cb7cSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*2c23cb7cSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*2c23cb7cSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*2c23cb7cSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*2c23cb7cSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*2c23cb7cSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*2c23cb7cSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*2c23cb7cSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*2c23cb7cSEd Maste  * SUCH DAMAGE.
25*2c23cb7cSEd Maste  */
26*2c23cb7cSEd Maste 
27*2c23cb7cSEd Maste #include <sys/cdefs.h>
28*2c23cb7cSEd Maste #include <sys/param.h>
29*2c23cb7cSEd Maste #include <sys/queue.h>
30*2c23cb7cSEd Maste #include <ar.h>
31*2c23cb7cSEd Maste #include <ctype.h>
32*2c23cb7cSEd Maste #include <dwarf.h>
33*2c23cb7cSEd Maste #include <err.h>
34*2c23cb7cSEd Maste #include <fcntl.h>
35*2c23cb7cSEd Maste #include <gelf.h>
36*2c23cb7cSEd Maste #include <getopt.h>
37*2c23cb7cSEd Maste #include <libdwarf.h>
38*2c23cb7cSEd Maste #include <libelftc.h>
39*2c23cb7cSEd Maste #include <libgen.h>
40*2c23cb7cSEd Maste #include <stdarg.h>
41*2c23cb7cSEd Maste #include <stdio.h>
42*2c23cb7cSEd Maste #include <stdlib.h>
43*2c23cb7cSEd Maste #include <string.h>
44*2c23cb7cSEd Maste #include <time.h>
45*2c23cb7cSEd Maste #include <unistd.h>
46*2c23cb7cSEd Maste 
47*2c23cb7cSEd Maste #include "_elftc.h"
48*2c23cb7cSEd Maste 
49*2c23cb7cSEd Maste ELFTC_VCSID("$Id: readelf.c 2946 2013-05-26 08:00:11Z kaiwang27 $");
50*2c23cb7cSEd Maste 
51*2c23cb7cSEd Maste /*
52*2c23cb7cSEd Maste  * readelf(1) options.
53*2c23cb7cSEd Maste  */
54*2c23cb7cSEd Maste #define	RE_AA	0x00000001
55*2c23cb7cSEd Maste #define	RE_C	0x00000002
56*2c23cb7cSEd Maste #define	RE_DD	0x00000004
57*2c23cb7cSEd Maste #define	RE_D	0x00000008
58*2c23cb7cSEd Maste #define	RE_G	0x00000010
59*2c23cb7cSEd Maste #define	RE_H	0x00000020
60*2c23cb7cSEd Maste #define	RE_II	0x00000040
61*2c23cb7cSEd Maste #define	RE_I	0x00000080
62*2c23cb7cSEd Maste #define	RE_L	0x00000100
63*2c23cb7cSEd Maste #define	RE_NN	0x00000200
64*2c23cb7cSEd Maste #define	RE_N	0x00000400
65*2c23cb7cSEd Maste #define	RE_P	0x00000800
66*2c23cb7cSEd Maste #define	RE_R	0x00001000
67*2c23cb7cSEd Maste #define	RE_SS	0x00002000
68*2c23cb7cSEd Maste #define	RE_S	0x00004000
69*2c23cb7cSEd Maste #define	RE_T	0x00008000
70*2c23cb7cSEd Maste #define	RE_U	0x00010000
71*2c23cb7cSEd Maste #define	RE_VV	0x00020000
72*2c23cb7cSEd Maste #define	RE_WW	0x00040000
73*2c23cb7cSEd Maste #define	RE_W	0x00080000
74*2c23cb7cSEd Maste #define	RE_X	0x00100000
75*2c23cb7cSEd Maste 
76*2c23cb7cSEd Maste /*
77*2c23cb7cSEd Maste  * dwarf dump options.
78*2c23cb7cSEd Maste  */
79*2c23cb7cSEd Maste #define	DW_A	0x00000001
80*2c23cb7cSEd Maste #define	DW_FF	0x00000002
81*2c23cb7cSEd Maste #define	DW_F	0x00000004
82*2c23cb7cSEd Maste #define	DW_I	0x00000008
83*2c23cb7cSEd Maste #define	DW_LL	0x00000010
84*2c23cb7cSEd Maste #define	DW_L	0x00000020
85*2c23cb7cSEd Maste #define	DW_M	0x00000040
86*2c23cb7cSEd Maste #define	DW_O	0x00000080
87*2c23cb7cSEd Maste #define	DW_P	0x00000100
88*2c23cb7cSEd Maste #define	DW_RR	0x00000200
89*2c23cb7cSEd Maste #define	DW_R	0x00000400
90*2c23cb7cSEd Maste #define	DW_S	0x00000800
91*2c23cb7cSEd Maste 
92*2c23cb7cSEd Maste #define	DW_DEFAULT_OPTIONS (DW_A | DW_F | DW_I | DW_L | DW_O | DW_P | \
93*2c23cb7cSEd Maste 	    DW_R | DW_RR | DW_S)
94*2c23cb7cSEd Maste 
95*2c23cb7cSEd Maste /*
96*2c23cb7cSEd Maste  * readelf(1) run control flags.
97*2c23cb7cSEd Maste  */
98*2c23cb7cSEd Maste #define	DISPLAY_FILENAME	0x0001
99*2c23cb7cSEd Maste 
100*2c23cb7cSEd Maste /*
101*2c23cb7cSEd Maste  * Internal data structure for sections.
102*2c23cb7cSEd Maste  */
103*2c23cb7cSEd Maste struct section {
104*2c23cb7cSEd Maste 	const char	*name;		/* section name */
105*2c23cb7cSEd Maste 	Elf_Scn		*scn;		/* section scn */
106*2c23cb7cSEd Maste 	uint64_t	 off;		/* section offset */
107*2c23cb7cSEd Maste 	uint64_t	 sz;		/* section size */
108*2c23cb7cSEd Maste 	uint64_t	 entsize;	/* section entsize */
109*2c23cb7cSEd Maste 	uint64_t	 align;		/* section alignment */
110*2c23cb7cSEd Maste 	uint64_t	 type;		/* section type */
111*2c23cb7cSEd Maste 	uint64_t	 flags;		/* section flags */
112*2c23cb7cSEd Maste 	uint64_t	 addr;		/* section virtual addr */
113*2c23cb7cSEd Maste 	uint32_t	 link;		/* section link ndx */
114*2c23cb7cSEd Maste 	uint32_t	 info;		/* section info ndx */
115*2c23cb7cSEd Maste };
116*2c23cb7cSEd Maste 
117*2c23cb7cSEd Maste struct dumpop {
118*2c23cb7cSEd Maste 	union {
119*2c23cb7cSEd Maste 		size_t si;		/* section index */
120*2c23cb7cSEd Maste 		const char *sn;		/* section name */
121*2c23cb7cSEd Maste 	} u;
122*2c23cb7cSEd Maste 	enum {
123*2c23cb7cSEd Maste 		DUMP_BY_INDEX = 0,
124*2c23cb7cSEd Maste 		DUMP_BY_NAME
125*2c23cb7cSEd Maste 	} type;				/* dump type */
126*2c23cb7cSEd Maste #define HEX_DUMP	0x0001
127*2c23cb7cSEd Maste #define STR_DUMP	0x0002
128*2c23cb7cSEd Maste 	int op;				/* dump operation */
129*2c23cb7cSEd Maste 	STAILQ_ENTRY(dumpop) dumpop_list;
130*2c23cb7cSEd Maste };
131*2c23cb7cSEd Maste 
132*2c23cb7cSEd Maste struct symver {
133*2c23cb7cSEd Maste 	const char *name;
134*2c23cb7cSEd Maste 	int type;
135*2c23cb7cSEd Maste };
136*2c23cb7cSEd Maste 
137*2c23cb7cSEd Maste /*
138*2c23cb7cSEd Maste  * Structure encapsulates the global data for readelf(1).
139*2c23cb7cSEd Maste  */
140*2c23cb7cSEd Maste struct readelf {
141*2c23cb7cSEd Maste 	const char	 *filename;	/* current processing file. */
142*2c23cb7cSEd Maste 	int		  options;	/* command line options. */
143*2c23cb7cSEd Maste 	int		  flags;	/* run control flags. */
144*2c23cb7cSEd Maste 	int		  dop;		/* dwarf dump options. */
145*2c23cb7cSEd Maste 	Elf		 *elf;		/* underlying ELF descriptor. */
146*2c23cb7cSEd Maste 	Elf		 *ar;		/* archive ELF descriptor. */
147*2c23cb7cSEd Maste 	Dwarf_Debug	  dbg;		/* DWARF handle. */
148*2c23cb7cSEd Maste 	GElf_Ehdr	  ehdr;		/* ELF header. */
149*2c23cb7cSEd Maste 	int		  ec;		/* ELF class. */
150*2c23cb7cSEd Maste 	size_t		  shnum;	/* #sections. */
151*2c23cb7cSEd Maste 	struct section	 *vd_s;		/* Verdef section. */
152*2c23cb7cSEd Maste 	struct section	 *vn_s;		/* Verneed section. */
153*2c23cb7cSEd Maste 	struct section	 *vs_s;		/* Versym section. */
154*2c23cb7cSEd Maste 	uint16_t	 *vs;		/* Versym array. */
155*2c23cb7cSEd Maste 	int		  vs_sz;	/* Versym array size. */
156*2c23cb7cSEd Maste 	struct symver	 *ver;		/* Version array. */
157*2c23cb7cSEd Maste 	int		  ver_sz;	/* Size of version array. */
158*2c23cb7cSEd Maste 	struct section	 *sl;		/* list of sections. */
159*2c23cb7cSEd Maste 	STAILQ_HEAD(, dumpop) v_dumpop; /* list of dump ops. */
160*2c23cb7cSEd Maste 	uint64_t	(*dw_read)(Elf_Data *, uint64_t *, int);
161*2c23cb7cSEd Maste 	uint64_t	(*dw_decode)(uint8_t **, int);
162*2c23cb7cSEd Maste };
163*2c23cb7cSEd Maste 
164*2c23cb7cSEd Maste enum options
165*2c23cb7cSEd Maste {
166*2c23cb7cSEd Maste 	OPTION_DEBUG_DUMP
167*2c23cb7cSEd Maste };
168*2c23cb7cSEd Maste 
169*2c23cb7cSEd Maste static struct option longopts[] = {
170*2c23cb7cSEd Maste 	{"all", no_argument, NULL, 'a'},
171*2c23cb7cSEd Maste 	{"arch-specific", no_argument, NULL, 'A'},
172*2c23cb7cSEd Maste 	{"archive-index", no_argument, NULL, 'c'},
173*2c23cb7cSEd Maste 	{"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP},
174*2c23cb7cSEd Maste 	{"dynamic", no_argument, NULL, 'd'},
175*2c23cb7cSEd Maste 	{"file-header", no_argument, NULL, 'h'},
176*2c23cb7cSEd Maste 	{"full-section-name", no_argument, NULL, 'N'},
177*2c23cb7cSEd Maste 	{"headers", no_argument, NULL, 'e'},
178*2c23cb7cSEd Maste 	{"help", no_argument, 0, 'H'},
179*2c23cb7cSEd Maste 	{"hex-dump", required_argument, NULL, 'x'},
180*2c23cb7cSEd Maste 	{"histogram", no_argument, NULL, 'I'},
181*2c23cb7cSEd Maste 	{"notes", no_argument, NULL, 'n'},
182*2c23cb7cSEd Maste 	{"program-headers", no_argument, NULL, 'l'},
183*2c23cb7cSEd Maste 	{"relocs", no_argument, NULL, 'r'},
184*2c23cb7cSEd Maste 	{"sections", no_argument, NULL, 'S'},
185*2c23cb7cSEd Maste 	{"section-headers", no_argument, NULL, 'S'},
186*2c23cb7cSEd Maste 	{"section-groups", no_argument, NULL, 'g'},
187*2c23cb7cSEd Maste 	{"section-details", no_argument, NULL, 't'},
188*2c23cb7cSEd Maste 	{"segments", no_argument, NULL, 'l'},
189*2c23cb7cSEd Maste 	{"string-dump", required_argument, NULL, 'p'},
190*2c23cb7cSEd Maste 	{"symbols", no_argument, NULL, 's'},
191*2c23cb7cSEd Maste 	{"syms", no_argument, NULL, 's'},
192*2c23cb7cSEd Maste 	{"unwind", no_argument, NULL, 'u'},
193*2c23cb7cSEd Maste 	{"use-dynamic", no_argument, NULL, 'D'},
194*2c23cb7cSEd Maste 	{"version-info", no_argument, 0, 'V'},
195*2c23cb7cSEd Maste 	{"version", no_argument, 0, 'v'},
196*2c23cb7cSEd Maste 	{"wide", no_argument, 0, 'W'},
197*2c23cb7cSEd Maste 	{NULL, 0, NULL, 0}
198*2c23cb7cSEd Maste };
199*2c23cb7cSEd Maste 
200*2c23cb7cSEd Maste struct eflags_desc {
201*2c23cb7cSEd Maste 	uint64_t flag;
202*2c23cb7cSEd Maste 	const char *desc;
203*2c23cb7cSEd Maste };
204*2c23cb7cSEd Maste 
205*2c23cb7cSEd Maste struct mips_option {
206*2c23cb7cSEd Maste 	uint64_t flag;
207*2c23cb7cSEd Maste 	const char *desc;
208*2c23cb7cSEd Maste };
209*2c23cb7cSEd Maste 
210*2c23cb7cSEd Maste static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op,
211*2c23cb7cSEd Maste     int t);
212*2c23cb7cSEd Maste static const char *aeabi_adv_simd_arch(uint64_t simd);
213*2c23cb7cSEd Maste static const char *aeabi_align_needed(uint64_t an);
214*2c23cb7cSEd Maste static const char *aeabi_align_preserved(uint64_t ap);
215*2c23cb7cSEd Maste static const char *aeabi_arm_isa(uint64_t ai);
216*2c23cb7cSEd Maste static const char *aeabi_cpu_arch(uint64_t arch);
217*2c23cb7cSEd Maste static const char *aeabi_cpu_arch_profile(uint64_t pf);
218*2c23cb7cSEd Maste static const char *aeabi_div(uint64_t du);
219*2c23cb7cSEd Maste static const char *aeabi_enum_size(uint64_t es);
220*2c23cb7cSEd Maste static const char *aeabi_fp_16bit_format(uint64_t fp16);
221*2c23cb7cSEd Maste static const char *aeabi_fp_arch(uint64_t fp);
222*2c23cb7cSEd Maste static const char *aeabi_fp_denormal(uint64_t fd);
223*2c23cb7cSEd Maste static const char *aeabi_fp_exceptions(uint64_t fe);
224*2c23cb7cSEd Maste static const char *aeabi_fp_hpext(uint64_t fh);
225*2c23cb7cSEd Maste static const char *aeabi_fp_number_model(uint64_t fn);
226*2c23cb7cSEd Maste static const char *aeabi_fp_optm_goal(uint64_t fog);
227*2c23cb7cSEd Maste static const char *aeabi_fp_rounding(uint64_t fr);
228*2c23cb7cSEd Maste static const char *aeabi_hardfp(uint64_t hfp);
229*2c23cb7cSEd Maste static const char *aeabi_mpext(uint64_t mp);
230*2c23cb7cSEd Maste static const char *aeabi_optm_goal(uint64_t og);
231*2c23cb7cSEd Maste static const char *aeabi_pcs_config(uint64_t pcs);
232*2c23cb7cSEd Maste static const char *aeabi_pcs_got(uint64_t got);
233*2c23cb7cSEd Maste static const char *aeabi_pcs_r9(uint64_t r9);
234*2c23cb7cSEd Maste static const char *aeabi_pcs_ro(uint64_t ro);
235*2c23cb7cSEd Maste static const char *aeabi_pcs_rw(uint64_t rw);
236*2c23cb7cSEd Maste static const char *aeabi_pcs_wchar_t(uint64_t wt);
237*2c23cb7cSEd Maste static const char *aeabi_t2ee(uint64_t t2ee);
238*2c23cb7cSEd Maste static const char *aeabi_thumb_isa(uint64_t ti);
239*2c23cb7cSEd Maste static const char *aeabi_fp_user_exceptions(uint64_t fu);
240*2c23cb7cSEd Maste static const char *aeabi_unaligned_access(uint64_t ua);
241*2c23cb7cSEd Maste static const char *aeabi_vfp_args(uint64_t va);
242*2c23cb7cSEd Maste static const char *aeabi_virtual(uint64_t vt);
243*2c23cb7cSEd Maste static const char *aeabi_wmmx_arch(uint64_t wmmx);
244*2c23cb7cSEd Maste static const char *aeabi_wmmx_args(uint64_t wa);
245*2c23cb7cSEd Maste static const char *elf_class(unsigned int class);
246*2c23cb7cSEd Maste static const char *elf_endian(unsigned int endian);
247*2c23cb7cSEd Maste static const char *elf_machine(unsigned int mach);
248*2c23cb7cSEd Maste static const char *elf_osabi(unsigned int abi);
249*2c23cb7cSEd Maste static const char *elf_type(unsigned int type);
250*2c23cb7cSEd Maste static const char *elf_ver(unsigned int ver);
251*2c23cb7cSEd Maste static const char *dt_type(unsigned int mach, unsigned int dtype);
252*2c23cb7cSEd Maste static void dump_ar(struct readelf *re, int);
253*2c23cb7cSEd Maste static void dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe);
254*2c23cb7cSEd Maste static void dump_attributes(struct readelf *re);
255*2c23cb7cSEd Maste static uint8_t *dump_compatibility_tag(uint8_t *p);
256*2c23cb7cSEd Maste static void dump_dwarf(struct readelf *re);
257*2c23cb7cSEd Maste static void dump_eflags(struct readelf *re, uint64_t e_flags);
258*2c23cb7cSEd Maste static void dump_elf(struct readelf *re);
259*2c23cb7cSEd Maste static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab);
260*2c23cb7cSEd Maste static void dump_dynamic(struct readelf *re);
261*2c23cb7cSEd Maste static void dump_liblist(struct readelf *re);
262*2c23cb7cSEd Maste static void dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe);
263*2c23cb7cSEd Maste static void dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz);
264*2c23cb7cSEd Maste static void dump_mips_options(struct readelf *re, struct section *s);
265*2c23cb7cSEd Maste static void dump_mips_option_flags(const char *name, struct mips_option *opt,
266*2c23cb7cSEd Maste     uint64_t info);
267*2c23cb7cSEd Maste static void dump_mips_reginfo(struct readelf *re, struct section *s);
268*2c23cb7cSEd Maste static void dump_mips_specific_info(struct readelf *re);
269*2c23cb7cSEd Maste static void dump_notes(struct readelf *re);
270*2c23cb7cSEd Maste static void dump_notes_content(struct readelf *re, const char *buf, size_t sz,
271*2c23cb7cSEd Maste     off_t off);
272*2c23cb7cSEd Maste static void dump_svr4_hash(struct section *s);
273*2c23cb7cSEd Maste static void dump_svr4_hash64(struct readelf *re, struct section *s);
274*2c23cb7cSEd Maste static void dump_gnu_hash(struct readelf *re, struct section *s);
275*2c23cb7cSEd Maste static void dump_hash(struct readelf *re);
276*2c23cb7cSEd Maste static void dump_phdr(struct readelf *re);
277*2c23cb7cSEd Maste static void dump_ppc_attributes(uint8_t *p, uint8_t *pe);
278*2c23cb7cSEd Maste static void dump_symtab(struct readelf *re, int i);
279*2c23cb7cSEd Maste static void dump_symtabs(struct readelf *re);
280*2c23cb7cSEd Maste static uint8_t *dump_unknown_tag(uint64_t tag, uint8_t *p);
281*2c23cb7cSEd Maste static void dump_ver(struct readelf *re);
282*2c23cb7cSEd Maste static void dump_verdef(struct readelf *re, int dump);
283*2c23cb7cSEd Maste static void dump_verneed(struct readelf *re, int dump);
284*2c23cb7cSEd Maste static void dump_versym(struct readelf *re);
285*2c23cb7cSEd Maste static struct dumpop *find_dumpop(struct readelf *re, size_t si, const char *sn,
286*2c23cb7cSEd Maste     int op, int t);
287*2c23cb7cSEd Maste static const char *get_string(struct readelf *re, int strtab, size_t off);
288*2c23cb7cSEd Maste static const char *get_symbol_name(struct readelf *re, int symtab, int i);
289*2c23cb7cSEd Maste static uint64_t get_symbol_value(struct readelf *re, int symtab, int i);
290*2c23cb7cSEd Maste static void load_sections(struct readelf *re);
291*2c23cb7cSEd Maste static const char *mips_abi_fp(uint64_t fp);
292*2c23cb7cSEd Maste static const char *note_type(unsigned int osabi, unsigned int et,
293*2c23cb7cSEd Maste     unsigned int nt);
294*2c23cb7cSEd Maste static const char *option_kind(uint8_t kind);
295*2c23cb7cSEd Maste static const char *phdr_type(unsigned int ptype);
296*2c23cb7cSEd Maste static const char *ppc_abi_fp(uint64_t fp);
297*2c23cb7cSEd Maste static const char *ppc_abi_vector(uint64_t vec);
298*2c23cb7cSEd Maste static const char *r_type(unsigned int mach, unsigned int type);
299*2c23cb7cSEd Maste static void readelf_usage(void);
300*2c23cb7cSEd Maste static void readelf_version(void);
301*2c23cb7cSEd Maste static void search_ver(struct readelf *re);
302*2c23cb7cSEd Maste static const char *section_type(unsigned int mach, unsigned int stype);
303*2c23cb7cSEd Maste static const char *st_bind(unsigned int sbind);
304*2c23cb7cSEd Maste static const char *st_shndx(unsigned int shndx);
305*2c23cb7cSEd Maste static const char *st_type(unsigned int stype);
306*2c23cb7cSEd Maste static const char *st_vis(unsigned int svis);
307*2c23cb7cSEd Maste static const char *top_tag(unsigned int tag);
308*2c23cb7cSEd Maste static void unload_sections(struct readelf *re);
309*2c23cb7cSEd Maste static uint64_t _read_lsb(Elf_Data *d, uint64_t *offsetp,
310*2c23cb7cSEd Maste     int bytes_to_read);
311*2c23cb7cSEd Maste static uint64_t _read_msb(Elf_Data *d, uint64_t *offsetp,
312*2c23cb7cSEd Maste     int bytes_to_read);
313*2c23cb7cSEd Maste static uint64_t _decode_lsb(uint8_t **data, int bytes_to_read);
314*2c23cb7cSEd Maste static uint64_t _decode_msb(uint8_t **data, int bytes_to_read);
315*2c23cb7cSEd Maste static int64_t _decode_sleb128(uint8_t **dp);
316*2c23cb7cSEd Maste static uint64_t _decode_uleb128(uint8_t **dp);
317*2c23cb7cSEd Maste 
318*2c23cb7cSEd Maste static struct eflags_desc arm_eflags_desc[] = {
319*2c23cb7cSEd Maste 	{EF_ARM_RELEXEC, "relocatable executable"},
320*2c23cb7cSEd Maste 	{EF_ARM_HASENTRY, "has entry point"},
321*2c23cb7cSEd Maste 	{EF_ARM_SYMSARESORTED, "sorted symbol tables"},
322*2c23cb7cSEd Maste 	{EF_ARM_DYNSYMSUSESEGIDX, "dynamic symbols use segment index"},
323*2c23cb7cSEd Maste 	{EF_ARM_MAPSYMSFIRST, "mapping symbols precede others"},
324*2c23cb7cSEd Maste 	{EF_ARM_BE8, "BE8"},
325*2c23cb7cSEd Maste 	{EF_ARM_LE8, "LE8"},
326*2c23cb7cSEd Maste 	{EF_ARM_INTERWORK, "interworking enabled"},
327*2c23cb7cSEd Maste 	{EF_ARM_APCS_26, "uses APCS/26"},
328*2c23cb7cSEd Maste 	{EF_ARM_APCS_FLOAT, "uses APCS/float"},
329*2c23cb7cSEd Maste 	{EF_ARM_PIC, "position independent"},
330*2c23cb7cSEd Maste 	{EF_ARM_ALIGN8, "8 bit structure alignment"},
331*2c23cb7cSEd Maste 	{EF_ARM_NEW_ABI, "uses new ABI"},
332*2c23cb7cSEd Maste 	{EF_ARM_OLD_ABI, "uses old ABI"},
333*2c23cb7cSEd Maste 	{EF_ARM_SOFT_FLOAT, "software FP"},
334*2c23cb7cSEd Maste 	{EF_ARM_VFP_FLOAT, "VFP"},
335*2c23cb7cSEd Maste 	{EF_ARM_MAVERICK_FLOAT, "Maverick FP"},
336*2c23cb7cSEd Maste 	{0, NULL}
337*2c23cb7cSEd Maste };
338*2c23cb7cSEd Maste 
339*2c23cb7cSEd Maste static struct eflags_desc mips_eflags_desc[] = {
340*2c23cb7cSEd Maste 	{EF_MIPS_NOREORDER, "noreorder"},
341*2c23cb7cSEd Maste 	{EF_MIPS_PIC, "pic"},
342*2c23cb7cSEd Maste 	{EF_MIPS_CPIC, "cpic"},
343*2c23cb7cSEd Maste 	{EF_MIPS_UCODE, "ugen_reserved"},
344*2c23cb7cSEd Maste 	{EF_MIPS_ABI2, "abi2"},
345*2c23cb7cSEd Maste 	{EF_MIPS_OPTIONS_FIRST, "odk first"},
346*2c23cb7cSEd Maste 	{EF_MIPS_ARCH_ASE_MDMX, "mdmx"},
347*2c23cb7cSEd Maste 	{EF_MIPS_ARCH_ASE_M16, "mips16"},
348*2c23cb7cSEd Maste 	{0, NULL}
349*2c23cb7cSEd Maste };
350*2c23cb7cSEd Maste 
351*2c23cb7cSEd Maste static struct eflags_desc powerpc_eflags_desc[] = {
352*2c23cb7cSEd Maste 	{EF_PPC_EMB, "emb"},
353*2c23cb7cSEd Maste 	{EF_PPC_RELOCATABLE, "relocatable"},
354*2c23cb7cSEd Maste 	{EF_PPC_RELOCATABLE_LIB, "relocatable-lib"},
355*2c23cb7cSEd Maste 	{0, NULL}
356*2c23cb7cSEd Maste };
357*2c23cb7cSEd Maste 
358*2c23cb7cSEd Maste static struct eflags_desc sparc_eflags_desc[] = {
359*2c23cb7cSEd Maste 	{EF_SPARC_32PLUS, "v8+"},
360*2c23cb7cSEd Maste 	{EF_SPARC_SUN_US1, "ultrasparcI"},
361*2c23cb7cSEd Maste 	{EF_SPARC_HAL_R1, "halr1"},
362*2c23cb7cSEd Maste 	{EF_SPARC_SUN_US3, "ultrasparcIII"},
363*2c23cb7cSEd Maste 	{0, NULL}
364*2c23cb7cSEd Maste };
365*2c23cb7cSEd Maste 
366*2c23cb7cSEd Maste static const char *
367*2c23cb7cSEd Maste elf_osabi(unsigned int abi)
368*2c23cb7cSEd Maste {
369*2c23cb7cSEd Maste 	static char s_abi[32];
370*2c23cb7cSEd Maste 
371*2c23cb7cSEd Maste 	switch(abi) {
372*2c23cb7cSEd Maste 	case ELFOSABI_SYSV: return "SYSV";
373*2c23cb7cSEd Maste 	case ELFOSABI_HPUX: return "HPUS";
374*2c23cb7cSEd Maste 	case ELFOSABI_NETBSD: return "NetBSD";
375*2c23cb7cSEd Maste 	case ELFOSABI_GNU: return "GNU";
376*2c23cb7cSEd Maste 	case ELFOSABI_HURD: return "HURD";
377*2c23cb7cSEd Maste 	case ELFOSABI_86OPEN: return "86OPEN";
378*2c23cb7cSEd Maste 	case ELFOSABI_SOLARIS: return "Solaris";
379*2c23cb7cSEd Maste 	case ELFOSABI_AIX: return "AIX";
380*2c23cb7cSEd Maste 	case ELFOSABI_IRIX: return "IRIX";
381*2c23cb7cSEd Maste 	case ELFOSABI_FREEBSD: return "FreeBSD";
382*2c23cb7cSEd Maste 	case ELFOSABI_TRU64: return "TRU64";
383*2c23cb7cSEd Maste 	case ELFOSABI_MODESTO: return "MODESTO";
384*2c23cb7cSEd Maste 	case ELFOSABI_OPENBSD: return "OpenBSD";
385*2c23cb7cSEd Maste 	case ELFOSABI_OPENVMS: return "OpenVMS";
386*2c23cb7cSEd Maste 	case ELFOSABI_NSK: return "NSK";
387*2c23cb7cSEd Maste 	case ELFOSABI_ARM: return "ARM";
388*2c23cb7cSEd Maste 	case ELFOSABI_STANDALONE: return "StandAlone";
389*2c23cb7cSEd Maste 	default:
390*2c23cb7cSEd Maste 		snprintf(s_abi, sizeof(s_abi), "<unknown: %#x>", abi);
391*2c23cb7cSEd Maste 		return (s_abi);
392*2c23cb7cSEd Maste 	}
393*2c23cb7cSEd Maste };
394*2c23cb7cSEd Maste 
395*2c23cb7cSEd Maste static const char *
396*2c23cb7cSEd Maste elf_machine(unsigned int mach)
397*2c23cb7cSEd Maste {
398*2c23cb7cSEd Maste 	static char s_mach[32];
399*2c23cb7cSEd Maste 
400*2c23cb7cSEd Maste 	switch (mach) {
401*2c23cb7cSEd Maste 	case EM_NONE: return "Unknown machine";
402*2c23cb7cSEd Maste 	case EM_M32: return "AT&T WE32100";
403*2c23cb7cSEd Maste 	case EM_SPARC: return "Sun SPARC";
404*2c23cb7cSEd Maste 	case EM_386: return "Intel i386";
405*2c23cb7cSEd Maste 	case EM_68K: return "Motorola 68000";
406*2c23cb7cSEd Maste 	case EM_88K: return "Motorola 88000";
407*2c23cb7cSEd Maste 	case EM_860: return "Intel i860";
408*2c23cb7cSEd Maste 	case EM_MIPS: return "MIPS R3000 Big-Endian only";
409*2c23cb7cSEd Maste 	case EM_S370: return "IBM System/370";
410*2c23cb7cSEd Maste 	case EM_MIPS_RS3_LE: return "MIPS R3000 Little-Endian";
411*2c23cb7cSEd Maste 	case EM_PARISC: return "HP PA-RISC";
412*2c23cb7cSEd Maste 	case EM_VPP500: return "Fujitsu VPP500";
413*2c23cb7cSEd Maste 	case EM_SPARC32PLUS: return "SPARC v8plus";
414*2c23cb7cSEd Maste 	case EM_960: return "Intel 80960";
415*2c23cb7cSEd Maste 	case EM_PPC: return "PowerPC 32-bit";
416*2c23cb7cSEd Maste 	case EM_PPC64: return "PowerPC 64-bit";
417*2c23cb7cSEd Maste 	case EM_S390: return "IBM System/390";
418*2c23cb7cSEd Maste 	case EM_V800: return "NEC V800";
419*2c23cb7cSEd Maste 	case EM_FR20: return "Fujitsu FR20";
420*2c23cb7cSEd Maste 	case EM_RH32: return "TRW RH-32";
421*2c23cb7cSEd Maste 	case EM_RCE: return "Motorola RCE";
422*2c23cb7cSEd Maste 	case EM_ARM: return "ARM";
423*2c23cb7cSEd Maste 	case EM_SH: return "Hitachi SH";
424*2c23cb7cSEd Maste 	case EM_SPARCV9: return "SPARC v9 64-bit";
425*2c23cb7cSEd Maste 	case EM_TRICORE: return "Siemens TriCore embedded processor";
426*2c23cb7cSEd Maste 	case EM_ARC: return "Argonaut RISC Core";
427*2c23cb7cSEd Maste 	case EM_H8_300: return "Hitachi H8/300";
428*2c23cb7cSEd Maste 	case EM_H8_300H: return "Hitachi H8/300H";
429*2c23cb7cSEd Maste 	case EM_H8S: return "Hitachi H8S";
430*2c23cb7cSEd Maste 	case EM_H8_500: return "Hitachi H8/500";
431*2c23cb7cSEd Maste 	case EM_IA_64: return "Intel IA-64 Processor";
432*2c23cb7cSEd Maste 	case EM_MIPS_X: return "Stanford MIPS-X";
433*2c23cb7cSEd Maste 	case EM_COLDFIRE: return "Motorola ColdFire";
434*2c23cb7cSEd Maste 	case EM_68HC12: return "Motorola M68HC12";
435*2c23cb7cSEd Maste 	case EM_MMA: return "Fujitsu MMA";
436*2c23cb7cSEd Maste 	case EM_PCP: return "Siemens PCP";
437*2c23cb7cSEd Maste 	case EM_NCPU: return "Sony nCPU";
438*2c23cb7cSEd Maste 	case EM_NDR1: return "Denso NDR1 microprocessor";
439*2c23cb7cSEd Maste 	case EM_STARCORE: return "Motorola Star*Core processor";
440*2c23cb7cSEd Maste 	case EM_ME16: return "Toyota ME16 processor";
441*2c23cb7cSEd Maste 	case EM_ST100: return "STMicroelectronics ST100 processor";
442*2c23cb7cSEd Maste 	case EM_TINYJ: return "Advanced Logic Corp. TinyJ processor";
443*2c23cb7cSEd Maste 	case EM_X86_64: return "Advanced Micro Devices x86-64";
444*2c23cb7cSEd Maste 	case EM_PDSP: return "Sony DSP Processor";
445*2c23cb7cSEd Maste 	case EM_FX66: return "Siemens FX66 microcontroller";
446*2c23cb7cSEd Maste 	case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 microcontroller";
447*2c23cb7cSEd Maste 	case EM_ST7: return "STmicroelectronics ST7 8-bit microcontroller";
448*2c23cb7cSEd Maste 	case EM_68HC16: return "Motorola MC68HC16 microcontroller";
449*2c23cb7cSEd Maste 	case EM_68HC11: return "Motorola MC68HC11 microcontroller";
450*2c23cb7cSEd Maste 	case EM_68HC08: return "Motorola MC68HC08 microcontroller";
451*2c23cb7cSEd Maste 	case EM_68HC05: return "Motorola MC68HC05 microcontroller";
452*2c23cb7cSEd Maste 	case EM_SVX: return "Silicon Graphics SVx";
453*2c23cb7cSEd Maste 	case EM_ST19: return "STMicroelectronics ST19 8-bit mc";
454*2c23cb7cSEd Maste 	case EM_VAX: return "Digital VAX";
455*2c23cb7cSEd Maste 	case EM_CRIS: return "Axis Communications 32-bit embedded processor";
456*2c23cb7cSEd Maste 	case EM_JAVELIN: return "Infineon Tech. 32bit embedded processor";
457*2c23cb7cSEd Maste 	case EM_FIREPATH: return "Element 14 64-bit DSP Processor";
458*2c23cb7cSEd Maste 	case EM_ZSP: return "LSI Logic 16-bit DSP Processor";
459*2c23cb7cSEd Maste 	case EM_MMIX: return "Donald Knuth's educational 64-bit proc";
460*2c23cb7cSEd Maste 	case EM_HUANY: return "Harvard University MI object files";
461*2c23cb7cSEd Maste 	case EM_PRISM: return "SiTera Prism";
462*2c23cb7cSEd Maste 	case EM_AVR: return "Atmel AVR 8-bit microcontroller";
463*2c23cb7cSEd Maste 	case EM_FR30: return "Fujitsu FR30";
464*2c23cb7cSEd Maste 	case EM_D10V: return "Mitsubishi D10V";
465*2c23cb7cSEd Maste 	case EM_D30V: return "Mitsubishi D30V";
466*2c23cb7cSEd Maste 	case EM_V850: return "NEC v850";
467*2c23cb7cSEd Maste 	case EM_M32R: return "Mitsubishi M32R";
468*2c23cb7cSEd Maste 	case EM_MN10300: return "Matsushita MN10300";
469*2c23cb7cSEd Maste 	case EM_MN10200: return "Matsushita MN10200";
470*2c23cb7cSEd Maste 	case EM_PJ: return "picoJava";
471*2c23cb7cSEd Maste 	case EM_OPENRISC: return "OpenRISC 32-bit embedded processor";
472*2c23cb7cSEd Maste 	case EM_ARC_A5: return "ARC Cores Tangent-A5";
473*2c23cb7cSEd Maste 	case EM_XTENSA: return "Tensilica Xtensa Architecture";
474*2c23cb7cSEd Maste 	case EM_VIDEOCORE: return "Alphamosaic VideoCore processor";
475*2c23cb7cSEd Maste 	case EM_TMM_GPP: return "Thompson Multimedia General Purpose Processor";
476*2c23cb7cSEd Maste 	case EM_NS32K: return "National Semiconductor 32000 series";
477*2c23cb7cSEd Maste 	case EM_TPC: return "Tenor Network TPC processor";
478*2c23cb7cSEd Maste 	case EM_SNP1K: return "Trebia SNP 1000 processor";
479*2c23cb7cSEd Maste 	case EM_ST200: return "STMicroelectronics ST200 microcontroller";
480*2c23cb7cSEd Maste 	case EM_IP2K: return "Ubicom IP2xxx microcontroller family";
481*2c23cb7cSEd Maste 	case EM_MAX: return "MAX Processor";
482*2c23cb7cSEd Maste 	case EM_CR: return "National Semiconductor CompactRISC microprocessor";
483*2c23cb7cSEd Maste 	case EM_F2MC16: return "Fujitsu F2MC16";
484*2c23cb7cSEd Maste 	case EM_MSP430: return "TI embedded microcontroller msp430";
485*2c23cb7cSEd Maste 	case EM_BLACKFIN: return "Analog Devices Blackfin (DSP) processor";
486*2c23cb7cSEd Maste 	case EM_SE_C33: return "S1C33 Family of Seiko Epson processors";
487*2c23cb7cSEd Maste 	case EM_SEP: return "Sharp embedded microprocessor";
488*2c23cb7cSEd Maste 	case EM_ARCA: return "Arca RISC Microprocessor";
489*2c23cb7cSEd Maste 	case EM_UNICORE: return "Microprocessor series from PKU-Unity Ltd";
490*2c23cb7cSEd Maste 	default:
491*2c23cb7cSEd Maste 		snprintf(s_mach, sizeof(s_mach), "<unknown: %#x>", mach);
492*2c23cb7cSEd Maste 		return (s_mach);
493*2c23cb7cSEd Maste 	}
494*2c23cb7cSEd Maste 
495*2c23cb7cSEd Maste }
496*2c23cb7cSEd Maste 
497*2c23cb7cSEd Maste static const char *
498*2c23cb7cSEd Maste elf_class(unsigned int class)
499*2c23cb7cSEd Maste {
500*2c23cb7cSEd Maste 	static char s_class[32];
501*2c23cb7cSEd Maste 
502*2c23cb7cSEd Maste 	switch (class) {
503*2c23cb7cSEd Maste 	case ELFCLASSNONE: return "none";
504*2c23cb7cSEd Maste 	case ELFCLASS32: return "ELF32";
505*2c23cb7cSEd Maste 	case ELFCLASS64: return "ELF64";
506*2c23cb7cSEd Maste 	default:
507*2c23cb7cSEd Maste 		snprintf(s_class, sizeof(s_class), "<unknown: %#x>", class);
508*2c23cb7cSEd Maste 		return (s_class);
509*2c23cb7cSEd Maste 	}
510*2c23cb7cSEd Maste }
511*2c23cb7cSEd Maste 
512*2c23cb7cSEd Maste static const char *
513*2c23cb7cSEd Maste elf_endian(unsigned int endian)
514*2c23cb7cSEd Maste {
515*2c23cb7cSEd Maste 	static char s_endian[32];
516*2c23cb7cSEd Maste 
517*2c23cb7cSEd Maste 	switch (endian) {
518*2c23cb7cSEd Maste 	case ELFDATANONE: return "none";
519*2c23cb7cSEd Maste 	case ELFDATA2LSB: return "2's complement, little endian";
520*2c23cb7cSEd Maste 	case ELFDATA2MSB: return "2's complement, big endian";
521*2c23cb7cSEd Maste 	default:
522*2c23cb7cSEd Maste 		snprintf(s_endian, sizeof(s_endian), "<unknown: %#x>", endian);
523*2c23cb7cSEd Maste 		return (s_endian);
524*2c23cb7cSEd Maste 	}
525*2c23cb7cSEd Maste }
526*2c23cb7cSEd Maste 
527*2c23cb7cSEd Maste static const char *
528*2c23cb7cSEd Maste elf_type(unsigned int type)
529*2c23cb7cSEd Maste {
530*2c23cb7cSEd Maste 	static char s_type[32];
531*2c23cb7cSEd Maste 
532*2c23cb7cSEd Maste 	switch (type) {
533*2c23cb7cSEd Maste 	case ET_NONE: return "NONE (None)";
534*2c23cb7cSEd Maste 	case ET_REL: return "REL (Relocatable file)";
535*2c23cb7cSEd Maste 	case ET_EXEC: return "EXEC (Executable file)";
536*2c23cb7cSEd Maste 	case ET_DYN: return "DYN (Shared object file)";
537*2c23cb7cSEd Maste 	case ET_CORE: return "CORE (Core file)";
538*2c23cb7cSEd Maste 	default:
539*2c23cb7cSEd Maste 		if (type >= ET_LOPROC)
540*2c23cb7cSEd Maste 			snprintf(s_type, sizeof(s_type), "<proc: %#x>", type);
541*2c23cb7cSEd Maste 		else if (type >= ET_LOOS && type <= ET_HIOS)
542*2c23cb7cSEd Maste 			snprintf(s_type, sizeof(s_type), "<os: %#x>", type);
543*2c23cb7cSEd Maste 		else
544*2c23cb7cSEd Maste 			snprintf(s_type, sizeof(s_type), "<unknown: %#x>",
545*2c23cb7cSEd Maste 			    type);
546*2c23cb7cSEd Maste 		return (s_type);
547*2c23cb7cSEd Maste 	}
548*2c23cb7cSEd Maste }
549*2c23cb7cSEd Maste 
550*2c23cb7cSEd Maste static const char *
551*2c23cb7cSEd Maste elf_ver(unsigned int ver)
552*2c23cb7cSEd Maste {
553*2c23cb7cSEd Maste 	static char s_ver[32];
554*2c23cb7cSEd Maste 
555*2c23cb7cSEd Maste 	switch (ver) {
556*2c23cb7cSEd Maste 	case EV_CURRENT: return "(current)";
557*2c23cb7cSEd Maste 	case EV_NONE: return "(none)";
558*2c23cb7cSEd Maste 	default:
559*2c23cb7cSEd Maste 		snprintf(s_ver, sizeof(s_ver), "<unknown: %#x>",
560*2c23cb7cSEd Maste 		    ver);
561*2c23cb7cSEd Maste 		return (s_ver);
562*2c23cb7cSEd Maste 	}
563*2c23cb7cSEd Maste }
564*2c23cb7cSEd Maste 
565*2c23cb7cSEd Maste static const char *
566*2c23cb7cSEd Maste phdr_type(unsigned int ptype)
567*2c23cb7cSEd Maste {
568*2c23cb7cSEd Maste 	static char s_ptype[32];
569*2c23cb7cSEd Maste 
570*2c23cb7cSEd Maste 	switch (ptype) {
571*2c23cb7cSEd Maste 	case PT_NULL: return "NULL";
572*2c23cb7cSEd Maste 	case PT_LOAD: return "LOAD";
573*2c23cb7cSEd Maste 	case PT_DYNAMIC: return "DYNAMIC";
574*2c23cb7cSEd Maste 	case PT_INTERP: return "INTERP";
575*2c23cb7cSEd Maste 	case PT_NOTE: return "NOTE";
576*2c23cb7cSEd Maste 	case PT_SHLIB: return "SHLIB";
577*2c23cb7cSEd Maste 	case PT_PHDR: return "PHDR";
578*2c23cb7cSEd Maste 	case PT_TLS: return "TLS";
579*2c23cb7cSEd Maste 	case PT_GNU_EH_FRAME: return "GNU_EH_FRAME";
580*2c23cb7cSEd Maste 	case PT_GNU_STACK: return "GNU_STACK";
581*2c23cb7cSEd Maste 	case PT_GNU_RELRO: return "GNU_RELRO";
582*2c23cb7cSEd Maste 	default:
583*2c23cb7cSEd Maste 		if (ptype >= PT_LOPROC && ptype <= PT_HIPROC)
584*2c23cb7cSEd Maste 			snprintf(s_ptype, sizeof(s_ptype), "LOPROC+%#x",
585*2c23cb7cSEd Maste 			    ptype - PT_LOPROC);
586*2c23cb7cSEd Maste 		else if (ptype >= PT_LOOS && ptype <= PT_HIOS)
587*2c23cb7cSEd Maste 			snprintf(s_ptype, sizeof(s_ptype), "LOOS+%#x",
588*2c23cb7cSEd Maste 			    ptype - PT_LOOS);
589*2c23cb7cSEd Maste 		else
590*2c23cb7cSEd Maste 			snprintf(s_ptype, sizeof(s_ptype), "<unknown: %#x>",
591*2c23cb7cSEd Maste 			    ptype);
592*2c23cb7cSEd Maste 		return (s_ptype);
593*2c23cb7cSEd Maste 	}
594*2c23cb7cSEd Maste }
595*2c23cb7cSEd Maste 
596*2c23cb7cSEd Maste static const char *
597*2c23cb7cSEd Maste section_type(unsigned int mach, unsigned int stype)
598*2c23cb7cSEd Maste {
599*2c23cb7cSEd Maste 	static char s_stype[32];
600*2c23cb7cSEd Maste 
601*2c23cb7cSEd Maste 	if (stype >= SHT_LOPROC && stype <= SHT_HIPROC) {
602*2c23cb7cSEd Maste 		switch (mach) {
603*2c23cb7cSEd Maste 		case EM_X86_64:
604*2c23cb7cSEd Maste 			switch (stype) {
605*2c23cb7cSEd Maste 			case SHT_AMD64_UNWIND: return "AMD64_UNWIND";
606*2c23cb7cSEd Maste 			default:
607*2c23cb7cSEd Maste 				break;
608*2c23cb7cSEd Maste 			}
609*2c23cb7cSEd Maste 			break;
610*2c23cb7cSEd Maste 		case EM_MIPS:
611*2c23cb7cSEd Maste 		case EM_MIPS_RS3_LE:
612*2c23cb7cSEd Maste 			switch (stype) {
613*2c23cb7cSEd Maste 			case SHT_MIPS_LIBLIST: return "MIPS_LIBLIST";
614*2c23cb7cSEd Maste 			case SHT_MIPS_MSYM: return "MIPS_MSYM";
615*2c23cb7cSEd Maste 			case SHT_MIPS_CONFLICT: return "MIPS_CONFLICT";
616*2c23cb7cSEd Maste 			case SHT_MIPS_GPTAB: return "MIPS_GPTAB";
617*2c23cb7cSEd Maste 			case SHT_MIPS_UCODE: return "MIPS_UCODE";
618*2c23cb7cSEd Maste 			case SHT_MIPS_DEBUG: return "MIPS_DEBUG";
619*2c23cb7cSEd Maste 			case SHT_MIPS_REGINFO: return "MIPS_REGINFO";
620*2c23cb7cSEd Maste 			case SHT_MIPS_PACKAGE: return "MIPS_PACKAGE";
621*2c23cb7cSEd Maste 			case SHT_MIPS_PACKSYM: return "MIPS_PACKSYM";
622*2c23cb7cSEd Maste 			case SHT_MIPS_RELD: return "MIPS_RELD";
623*2c23cb7cSEd Maste 			case SHT_MIPS_IFACE: return "MIPS_IFACE";
624*2c23cb7cSEd Maste 			case SHT_MIPS_CONTENT: return "MIPS_CONTENT";
625*2c23cb7cSEd Maste 			case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS";
626*2c23cb7cSEd Maste 			case SHT_MIPS_DELTASYM: return "MIPS_DELTASYM";
627*2c23cb7cSEd Maste 			case SHT_MIPS_DELTAINST: return "MIPS_DELTAINST";
628*2c23cb7cSEd Maste 			case SHT_MIPS_DELTACLASS: return "MIPS_DELTACLASS";
629*2c23cb7cSEd Maste 			case SHT_MIPS_DWARF: return "MIPS_DWARF";
630*2c23cb7cSEd Maste 			case SHT_MIPS_DELTADECL: return "MIPS_DELTADECL";
631*2c23cb7cSEd Maste 			case SHT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB";
632*2c23cb7cSEd Maste 			case SHT_MIPS_EVENTS: return "MIPS_EVENTS";
633*2c23cb7cSEd Maste 			case SHT_MIPS_TRANSLATE: return "MIPS_TRANSLATE";
634*2c23cb7cSEd Maste 			case SHT_MIPS_PIXIE: return "MIPS_PIXIE";
635*2c23cb7cSEd Maste 			case SHT_MIPS_XLATE: return "MIPS_XLATE";
636*2c23cb7cSEd Maste 			case SHT_MIPS_XLATE_DEBUG: return "MIPS_XLATE_DEBUG";
637*2c23cb7cSEd Maste 			case SHT_MIPS_WHIRL: return "MIPS_WHIRL";
638*2c23cb7cSEd Maste 			case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION";
639*2c23cb7cSEd Maste 			case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD";
640*2c23cb7cSEd Maste 			case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";
641*2c23cb7cSEd Maste 			default:
642*2c23cb7cSEd Maste 				break;
643*2c23cb7cSEd Maste 			}
644*2c23cb7cSEd Maste 			break;
645*2c23cb7cSEd Maste 		default:
646*2c23cb7cSEd Maste 			break;
647*2c23cb7cSEd Maste 		}
648*2c23cb7cSEd Maste 
649*2c23cb7cSEd Maste 		snprintf(s_stype, sizeof(s_stype), "LOPROC+%#x",
650*2c23cb7cSEd Maste 		    stype - SHT_LOPROC);
651*2c23cb7cSEd Maste 		return (s_stype);
652*2c23cb7cSEd Maste 	}
653*2c23cb7cSEd Maste 
654*2c23cb7cSEd Maste 	switch (stype) {
655*2c23cb7cSEd Maste 	case SHT_NULL: return "NULL";
656*2c23cb7cSEd Maste 	case SHT_PROGBITS: return "PROGBITS";
657*2c23cb7cSEd Maste 	case SHT_SYMTAB: return "SYMTAB";
658*2c23cb7cSEd Maste 	case SHT_STRTAB: return "STRTAB";
659*2c23cb7cSEd Maste 	case SHT_RELA: return "RELA";
660*2c23cb7cSEd Maste 	case SHT_HASH: return "HASH";
661*2c23cb7cSEd Maste 	case SHT_DYNAMIC: return "DYNAMIC";
662*2c23cb7cSEd Maste 	case SHT_NOTE: return "NOTE";
663*2c23cb7cSEd Maste 	case SHT_NOBITS: return "NOBITS";
664*2c23cb7cSEd Maste 	case SHT_REL: return "REL";
665*2c23cb7cSEd Maste 	case SHT_SHLIB: return "SHLIB";
666*2c23cb7cSEd Maste 	case SHT_DYNSYM: return "DYNSYM";
667*2c23cb7cSEd Maste 	case SHT_INIT_ARRAY: return "INIT_ARRAY";
668*2c23cb7cSEd Maste 	case SHT_FINI_ARRAY: return "FINI_ARRAY";
669*2c23cb7cSEd Maste 	case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY";
670*2c23cb7cSEd Maste 	case SHT_GROUP: return "GROUP";
671*2c23cb7cSEd Maste 	case SHT_SYMTAB_SHNDX: return "SYMTAB_SHNDX";
672*2c23cb7cSEd Maste 	case SHT_SUNW_dof: return "SUNW_dof";
673*2c23cb7cSEd Maste 	case SHT_SUNW_cap: return "SUNW_cap";
674*2c23cb7cSEd Maste 	case SHT_GNU_HASH: return "GNU_HASH";
675*2c23cb7cSEd Maste 	case SHT_SUNW_ANNOTATE: return "SUNW_ANNOTATE";
676*2c23cb7cSEd Maste 	case SHT_SUNW_DEBUGSTR: return "SUNW_DEBUGSTR";
677*2c23cb7cSEd Maste 	case SHT_SUNW_DEBUG: return "SUNW_DEBUG";
678*2c23cb7cSEd Maste 	case SHT_SUNW_move: return "SUNW_move";
679*2c23cb7cSEd Maste 	case SHT_SUNW_COMDAT: return "SUNW_COMDAT";
680*2c23cb7cSEd Maste 	case SHT_SUNW_syminfo: return "SUNW_syminfo";
681*2c23cb7cSEd Maste 	case SHT_SUNW_verdef: return "SUNW_verdef";
682*2c23cb7cSEd Maste 	case SHT_SUNW_verneed: return "SUNW_verneed";
683*2c23cb7cSEd Maste 	case SHT_SUNW_versym: return "SUNW_versym";
684*2c23cb7cSEd Maste 	default:
685*2c23cb7cSEd Maste 		if (stype >= SHT_LOOS && stype <= SHT_HIOS)
686*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "LOOS+%#x",
687*2c23cb7cSEd Maste 			    stype - SHT_LOOS);
688*2c23cb7cSEd Maste 		else if (stype >= SHT_LOUSER)
689*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "LOUSER+%#x",
690*2c23cb7cSEd Maste 			    stype - SHT_LOUSER);
691*2c23cb7cSEd Maste 		else
692*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "<unknown: %#x>",
693*2c23cb7cSEd Maste 			    stype);
694*2c23cb7cSEd Maste 		return (s_stype);
695*2c23cb7cSEd Maste 	}
696*2c23cb7cSEd Maste }
697*2c23cb7cSEd Maste 
698*2c23cb7cSEd Maste static const char *
699*2c23cb7cSEd Maste dt_type(unsigned int mach, unsigned int dtype)
700*2c23cb7cSEd Maste {
701*2c23cb7cSEd Maste 	static char s_dtype[32];
702*2c23cb7cSEd Maste 
703*2c23cb7cSEd Maste 	if (dtype >= DT_LOPROC && dtype <= DT_HIPROC) {
704*2c23cb7cSEd Maste 		switch (mach) {
705*2c23cb7cSEd Maste 		case EM_ARM:
706*2c23cb7cSEd Maste 			switch (dtype) {
707*2c23cb7cSEd Maste 			case DT_ARM_SYMTABSZ:
708*2c23cb7cSEd Maste 				return "ARM_SYMTABSZ";
709*2c23cb7cSEd Maste 			default:
710*2c23cb7cSEd Maste 				break;
711*2c23cb7cSEd Maste 			}
712*2c23cb7cSEd Maste 			break;
713*2c23cb7cSEd Maste 		case EM_MIPS:
714*2c23cb7cSEd Maste 		case EM_MIPS_RS3_LE:
715*2c23cb7cSEd Maste 			switch (dtype) {
716*2c23cb7cSEd Maste 			case DT_MIPS_RLD_VERSION:
717*2c23cb7cSEd Maste 				return "MIPS_RLD_VERSION";
718*2c23cb7cSEd Maste 			case DT_MIPS_TIME_STAMP:
719*2c23cb7cSEd Maste 				return "MIPS_TIME_STAMP";
720*2c23cb7cSEd Maste 			case DT_MIPS_ICHECKSUM:
721*2c23cb7cSEd Maste 				return "MIPS_ICHECKSUM";
722*2c23cb7cSEd Maste 			case DT_MIPS_IVERSION:
723*2c23cb7cSEd Maste 				return "MIPS_IVERSION";
724*2c23cb7cSEd Maste 			case DT_MIPS_FLAGS:
725*2c23cb7cSEd Maste 				return "MIPS_FLAGS";
726*2c23cb7cSEd Maste 			case DT_MIPS_BASE_ADDRESS:
727*2c23cb7cSEd Maste 				return "MIPS_BASE_ADDRESS";
728*2c23cb7cSEd Maste 			case DT_MIPS_CONFLICT:
729*2c23cb7cSEd Maste 				return "MIPS_CONFLICT";
730*2c23cb7cSEd Maste 			case DT_MIPS_LIBLIST:
731*2c23cb7cSEd Maste 				return "MIPS_LIBLIST";
732*2c23cb7cSEd Maste 			case DT_MIPS_LOCAL_GOTNO:
733*2c23cb7cSEd Maste 				return "MIPS_LOCAL_GOTNO";
734*2c23cb7cSEd Maste 			case DT_MIPS_CONFLICTNO:
735*2c23cb7cSEd Maste 				return "MIPS_CONFLICTNO";
736*2c23cb7cSEd Maste 			case DT_MIPS_LIBLISTNO:
737*2c23cb7cSEd Maste 				return "MIPS_LIBLISTNO";
738*2c23cb7cSEd Maste 			case DT_MIPS_SYMTABNO:
739*2c23cb7cSEd Maste 				return "MIPS_SYMTABNO";
740*2c23cb7cSEd Maste 			case DT_MIPS_UNREFEXTNO:
741*2c23cb7cSEd Maste 				return "MIPS_UNREFEXTNO";
742*2c23cb7cSEd Maste 			case DT_MIPS_GOTSYM:
743*2c23cb7cSEd Maste 				return "MIPS_GOTSYM";
744*2c23cb7cSEd Maste 			case DT_MIPS_HIPAGENO:
745*2c23cb7cSEd Maste 				return "MIPS_HIPAGENO";
746*2c23cb7cSEd Maste 			case DT_MIPS_RLD_MAP:
747*2c23cb7cSEd Maste 				return "MIPS_RLD_MAP";
748*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_CLASS:
749*2c23cb7cSEd Maste 				return "MIPS_DELTA_CLASS";
750*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_CLASS_NO:
751*2c23cb7cSEd Maste 				return "MIPS_DELTA_CLASS_NO";
752*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_INSTANCE:
753*2c23cb7cSEd Maste 				return "MIPS_DELTA_INSTANCE";
754*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_INSTANCE_NO:
755*2c23cb7cSEd Maste 				return "MIPS_DELTA_INSTANCE_NO";
756*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_RELOC:
757*2c23cb7cSEd Maste 				return "MIPS_DELTA_RELOC";
758*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_RELOC_NO:
759*2c23cb7cSEd Maste 				return "MIPS_DELTA_RELOC_NO";
760*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_SYM:
761*2c23cb7cSEd Maste 				return "MIPS_DELTA_SYM";
762*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_SYM_NO:
763*2c23cb7cSEd Maste 				return "MIPS_DELTA_SYM_NO";
764*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_CLASSSYM:
765*2c23cb7cSEd Maste 				return "MIPS_DELTA_CLASSSYM";
766*2c23cb7cSEd Maste 			case DT_MIPS_DELTA_CLASSSYM_NO:
767*2c23cb7cSEd Maste 				return "MIPS_DELTA_CLASSSYM_NO";
768*2c23cb7cSEd Maste 			case DT_MIPS_CXX_FLAGS:
769*2c23cb7cSEd Maste 				return "MIPS_CXX_FLAGS";
770*2c23cb7cSEd Maste 			case DT_MIPS_PIXIE_INIT:
771*2c23cb7cSEd Maste 				return "MIPS_PIXIE_INIT";
772*2c23cb7cSEd Maste 			case DT_MIPS_SYMBOL_LIB:
773*2c23cb7cSEd Maste 				return "MIPS_SYMBOL_LIB";
774*2c23cb7cSEd Maste 			case DT_MIPS_LOCALPAGE_GOTIDX:
775*2c23cb7cSEd Maste 				return "MIPS_LOCALPAGE_GOTIDX";
776*2c23cb7cSEd Maste 			case DT_MIPS_LOCAL_GOTIDX:
777*2c23cb7cSEd Maste 				return "MIPS_LOCAL_GOTIDX";
778*2c23cb7cSEd Maste 			case DT_MIPS_HIDDEN_GOTIDX:
779*2c23cb7cSEd Maste 				return "MIPS_HIDDEN_GOTIDX";
780*2c23cb7cSEd Maste 			case DT_MIPS_PROTECTED_GOTIDX:
781*2c23cb7cSEd Maste 				return "MIPS_PROTECTED_GOTIDX";
782*2c23cb7cSEd Maste 			case DT_MIPS_OPTIONS:
783*2c23cb7cSEd Maste 				return "MIPS_OPTIONS";
784*2c23cb7cSEd Maste 			case DT_MIPS_INTERFACE:
785*2c23cb7cSEd Maste 				return "MIPS_INTERFACE";
786*2c23cb7cSEd Maste 			case DT_MIPS_DYNSTR_ALIGN:
787*2c23cb7cSEd Maste 				return "MIPS_DYNSTR_ALIGN";
788*2c23cb7cSEd Maste 			case DT_MIPS_INTERFACE_SIZE:
789*2c23cb7cSEd Maste 				return "MIPS_INTERFACE_SIZE";
790*2c23cb7cSEd Maste 			case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:
791*2c23cb7cSEd Maste 				return "MIPS_RLD_TEXT_RESOLVE_ADDR";
792*2c23cb7cSEd Maste 			case DT_MIPS_PERF_SUFFIX:
793*2c23cb7cSEd Maste 				return "MIPS_PERF_SUFFIX";
794*2c23cb7cSEd Maste 			case DT_MIPS_COMPACT_SIZE:
795*2c23cb7cSEd Maste 				return "MIPS_COMPACT_SIZE";
796*2c23cb7cSEd Maste 			case DT_MIPS_GP_VALUE:
797*2c23cb7cSEd Maste 				return "MIPS_GP_VALUE";
798*2c23cb7cSEd Maste 			case DT_MIPS_AUX_DYNAMIC:
799*2c23cb7cSEd Maste 				return "MIPS_AUX_DYNAMIC";
800*2c23cb7cSEd Maste 			case DT_MIPS_PLTGOT:
801*2c23cb7cSEd Maste 				return "MIPS_PLTGOT";
802*2c23cb7cSEd Maste 			case DT_MIPS_RLD_OBJ_UPDATE:
803*2c23cb7cSEd Maste 				return "MIPS_RLD_OBJ_UPDATE";
804*2c23cb7cSEd Maste 			case DT_MIPS_RWPLT:
805*2c23cb7cSEd Maste 				return "MIPS_RWPLT";
806*2c23cb7cSEd Maste 			default:
807*2c23cb7cSEd Maste 				break;
808*2c23cb7cSEd Maste 			}
809*2c23cb7cSEd Maste 			break;
810*2c23cb7cSEd Maste 		case EM_SPARC:
811*2c23cb7cSEd Maste 		case EM_SPARC32PLUS:
812*2c23cb7cSEd Maste 		case EM_SPARCV9:
813*2c23cb7cSEd Maste 			switch (dtype) {
814*2c23cb7cSEd Maste 			case DT_SPARC_REGISTER:
815*2c23cb7cSEd Maste 				return "DT_SPARC_REGISTER";
816*2c23cb7cSEd Maste 			default:
817*2c23cb7cSEd Maste 				break;
818*2c23cb7cSEd Maste 			}
819*2c23cb7cSEd Maste 			break;
820*2c23cb7cSEd Maste 		default:
821*2c23cb7cSEd Maste 			break;
822*2c23cb7cSEd Maste 		}
823*2c23cb7cSEd Maste 		snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype);
824*2c23cb7cSEd Maste 		return (s_dtype);
825*2c23cb7cSEd Maste 	}
826*2c23cb7cSEd Maste 
827*2c23cb7cSEd Maste 	switch (dtype) {
828*2c23cb7cSEd Maste 	case DT_NULL: return "NULL";
829*2c23cb7cSEd Maste 	case DT_NEEDED: return "NEEDED";
830*2c23cb7cSEd Maste 	case DT_PLTRELSZ: return "PLTRELSZ";
831*2c23cb7cSEd Maste 	case DT_PLTGOT: return "PLTGOT";
832*2c23cb7cSEd Maste 	case DT_HASH: return "HASH";
833*2c23cb7cSEd Maste 	case DT_STRTAB: return "STRTAB";
834*2c23cb7cSEd Maste 	case DT_SYMTAB: return "SYMTAB";
835*2c23cb7cSEd Maste 	case DT_RELA: return "RELA";
836*2c23cb7cSEd Maste 	case DT_RELASZ: return "RELASZ";
837*2c23cb7cSEd Maste 	case DT_RELAENT: return "RELAENT";
838*2c23cb7cSEd Maste 	case DT_STRSZ: return "STRSZ";
839*2c23cb7cSEd Maste 	case DT_SYMENT: return "SYMENT";
840*2c23cb7cSEd Maste 	case DT_INIT: return "INIT";
841*2c23cb7cSEd Maste 	case DT_FINI: return "FINI";
842*2c23cb7cSEd Maste 	case DT_SONAME: return "SONAME";
843*2c23cb7cSEd Maste 	case DT_RPATH: return "RPATH";
844*2c23cb7cSEd Maste 	case DT_SYMBOLIC: return "SYMBOLIC";
845*2c23cb7cSEd Maste 	case DT_REL: return "REL";
846*2c23cb7cSEd Maste 	case DT_RELSZ: return "RELSZ";
847*2c23cb7cSEd Maste 	case DT_RELENT: return "RELENT";
848*2c23cb7cSEd Maste 	case DT_PLTREL: return "PLTREL";
849*2c23cb7cSEd Maste 	case DT_DEBUG: return "DEBUG";
850*2c23cb7cSEd Maste 	case DT_TEXTREL: return "TEXTREL";
851*2c23cb7cSEd Maste 	case DT_JMPREL: return "JMPREL";
852*2c23cb7cSEd Maste 	case DT_BIND_NOW: return "BIND_NOW";
853*2c23cb7cSEd Maste 	case DT_INIT_ARRAY: return "INIT_ARRAY";
854*2c23cb7cSEd Maste 	case DT_FINI_ARRAY: return "FINI_ARRAY";
855*2c23cb7cSEd Maste 	case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ";
856*2c23cb7cSEd Maste 	case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ";
857*2c23cb7cSEd Maste 	case DT_RUNPATH: return "RUNPATH";
858*2c23cb7cSEd Maste 	case DT_FLAGS: return "FLAGS";
859*2c23cb7cSEd Maste 	case DT_PREINIT_ARRAY: return "PREINIT_ARRAY";
860*2c23cb7cSEd Maste 	case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ";
861*2c23cb7cSEd Maste 	case DT_MAXPOSTAGS: return "MAXPOSTAGS";
862*2c23cb7cSEd Maste 	case DT_SUNW_AUXILIARY: return "SUNW_AUXILIARY";
863*2c23cb7cSEd Maste 	case DT_SUNW_RTLDINF: return "SUNW_RTLDINF";
864*2c23cb7cSEd Maste 	case DT_SUNW_FILTER: return "SUNW_FILTER";
865*2c23cb7cSEd Maste 	case DT_SUNW_CAP: return "SUNW_CAP";
866*2c23cb7cSEd Maste 	case DT_CHECKSUM: return "CHECKSUM";
867*2c23cb7cSEd Maste 	case DT_PLTPADSZ: return "PLTPADSZ";
868*2c23cb7cSEd Maste 	case DT_MOVEENT: return "MOVEENT";
869*2c23cb7cSEd Maste 	case DT_MOVESZ: return "MOVESZ";
870*2c23cb7cSEd Maste 	case DT_FEATURE_1: return "FEATURE_1";
871*2c23cb7cSEd Maste 	case DT_POSFLAG_1: return "POSFLAG_1";
872*2c23cb7cSEd Maste 	case DT_SYMINSZ: return "SYMINSZ";
873*2c23cb7cSEd Maste 	case DT_SYMINENT: return "SYMINENT";
874*2c23cb7cSEd Maste 	case DT_GNU_HASH: return "GNU_HASH";
875*2c23cb7cSEd Maste 	case DT_GNU_CONFLICT: return "GNU_CONFLICT";
876*2c23cb7cSEd Maste 	case DT_GNU_LIBLIST: return "GNU_LIBLIST";
877*2c23cb7cSEd Maste 	case DT_CONFIG: return "CONFIG";
878*2c23cb7cSEd Maste 	case DT_DEPAUDIT: return "DEPAUDIT";
879*2c23cb7cSEd Maste 	case DT_AUDIT: return "AUDIT";
880*2c23cb7cSEd Maste 	case DT_PLTPAD: return "PLTPAD";
881*2c23cb7cSEd Maste 	case DT_MOVETAB: return "MOVETAB";
882*2c23cb7cSEd Maste 	case DT_SYMINFO: return "SYMINFO";
883*2c23cb7cSEd Maste 	case DT_VERSYM: return "VERSYM";
884*2c23cb7cSEd Maste 	case DT_RELACOUNT: return "RELACOUNT";
885*2c23cb7cSEd Maste 	case DT_RELCOUNT: return "RELCOUNT";
886*2c23cb7cSEd Maste 	case DT_FLAGS_1: return "FLAGS_1";
887*2c23cb7cSEd Maste 	case DT_VERDEF: return "VERDEF";
888*2c23cb7cSEd Maste 	case DT_VERDEFNUM: return "VERDEFNUM";
889*2c23cb7cSEd Maste 	case DT_VERNEED: return "VERNEED";
890*2c23cb7cSEd Maste 	case DT_VERNEEDNUM: return "VERNEEDNUM";
891*2c23cb7cSEd Maste 	case DT_AUXILIARY: return "AUXILIARY";
892*2c23cb7cSEd Maste 	case DT_USED: return "USED";
893*2c23cb7cSEd Maste 	case DT_FILTER: return "FILTER";
894*2c23cb7cSEd Maste 	case DT_GNU_PRELINKED: return "GNU_PRELINKED";
895*2c23cb7cSEd Maste 	case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ";
896*2c23cb7cSEd Maste 	case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ";
897*2c23cb7cSEd Maste 	default:
898*2c23cb7cSEd Maste 		snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype);
899*2c23cb7cSEd Maste 		return (s_dtype);
900*2c23cb7cSEd Maste 	}
901*2c23cb7cSEd Maste }
902*2c23cb7cSEd Maste 
903*2c23cb7cSEd Maste static const char *
904*2c23cb7cSEd Maste st_bind(unsigned int sbind)
905*2c23cb7cSEd Maste {
906*2c23cb7cSEd Maste 	static char s_sbind[32];
907*2c23cb7cSEd Maste 
908*2c23cb7cSEd Maste 	switch (sbind) {
909*2c23cb7cSEd Maste 	case STB_LOCAL: return "LOCAL";
910*2c23cb7cSEd Maste 	case STB_GLOBAL: return "GLOBAL";
911*2c23cb7cSEd Maste 	case STB_WEAK: return "WEAK";
912*2c23cb7cSEd Maste 	default:
913*2c23cb7cSEd Maste 		if (sbind >= STB_LOOS && sbind <= STB_HIOS)
914*2c23cb7cSEd Maste 			return "OS";
915*2c23cb7cSEd Maste 		else if (sbind >= STB_LOPROC && sbind <= STB_HIPROC)
916*2c23cb7cSEd Maste 			return "PROC";
917*2c23cb7cSEd Maste 		else
918*2c23cb7cSEd Maste 			snprintf(s_sbind, sizeof(s_sbind), "<unknown: %#x>",
919*2c23cb7cSEd Maste 			    sbind);
920*2c23cb7cSEd Maste 		return (s_sbind);
921*2c23cb7cSEd Maste 	}
922*2c23cb7cSEd Maste }
923*2c23cb7cSEd Maste 
924*2c23cb7cSEd Maste static const char *
925*2c23cb7cSEd Maste st_type(unsigned int stype)
926*2c23cb7cSEd Maste {
927*2c23cb7cSEd Maste 	static char s_stype[32];
928*2c23cb7cSEd Maste 
929*2c23cb7cSEd Maste 	switch (stype) {
930*2c23cb7cSEd Maste 	case STT_NOTYPE: return "NOTYPE";
931*2c23cb7cSEd Maste 	case STT_OBJECT: return "OBJECT";
932*2c23cb7cSEd Maste 	case STT_FUNC: return "FUNC";
933*2c23cb7cSEd Maste 	case STT_SECTION: return "SECTION";
934*2c23cb7cSEd Maste 	case STT_FILE: return "FILE";
935*2c23cb7cSEd Maste 	case STT_COMMON: return "COMMON";
936*2c23cb7cSEd Maste 	case STT_TLS: return "TLS";
937*2c23cb7cSEd Maste 	default:
938*2c23cb7cSEd Maste 		if (stype >= STT_LOOS && stype <= STT_HIOS)
939*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "OS+%#x",
940*2c23cb7cSEd Maste 			    stype - STT_LOOS);
941*2c23cb7cSEd Maste 		else if (stype >= STT_LOPROC && stype <= STT_HIPROC)
942*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "PROC+%#x",
943*2c23cb7cSEd Maste 			    stype - STT_LOPROC);
944*2c23cb7cSEd Maste 		else
945*2c23cb7cSEd Maste 			snprintf(s_stype, sizeof(s_stype), "<unknown: %#x>",
946*2c23cb7cSEd Maste 			    stype);
947*2c23cb7cSEd Maste 		return (s_stype);
948*2c23cb7cSEd Maste 	}
949*2c23cb7cSEd Maste }
950*2c23cb7cSEd Maste 
951*2c23cb7cSEd Maste static const char *
952*2c23cb7cSEd Maste st_vis(unsigned int svis)
953*2c23cb7cSEd Maste {
954*2c23cb7cSEd Maste 	static char s_svis[32];
955*2c23cb7cSEd Maste 
956*2c23cb7cSEd Maste 	switch(svis) {
957*2c23cb7cSEd Maste 	case STV_DEFAULT: return "DEFAULT";
958*2c23cb7cSEd Maste 	case STV_INTERNAL: return "INTERNAL";
959*2c23cb7cSEd Maste 	case STV_HIDDEN: return "HIDDEN";
960*2c23cb7cSEd Maste 	case STV_PROTECTED: return "PROTECTED";
961*2c23cb7cSEd Maste 	default:
962*2c23cb7cSEd Maste 		snprintf(s_svis, sizeof(s_svis), "<unknown: %#x>", svis);
963*2c23cb7cSEd Maste 		return (s_svis);
964*2c23cb7cSEd Maste 	}
965*2c23cb7cSEd Maste }
966*2c23cb7cSEd Maste 
967*2c23cb7cSEd Maste static const char *
968*2c23cb7cSEd Maste st_shndx(unsigned int shndx)
969*2c23cb7cSEd Maste {
970*2c23cb7cSEd Maste 	static char s_shndx[32];
971*2c23cb7cSEd Maste 
972*2c23cb7cSEd Maste 	switch (shndx) {
973*2c23cb7cSEd Maste 	case SHN_UNDEF: return "UND";
974*2c23cb7cSEd Maste 	case SHN_ABS: return "ABS";
975*2c23cb7cSEd Maste 	case SHN_COMMON: return "COM";
976*2c23cb7cSEd Maste 	default:
977*2c23cb7cSEd Maste 		if (shndx >= SHN_LOPROC && shndx <= SHN_HIPROC)
978*2c23cb7cSEd Maste 			return "PRC";
979*2c23cb7cSEd Maste 		else if (shndx >= SHN_LOOS && shndx <= SHN_HIOS)
980*2c23cb7cSEd Maste 			return "OS";
981*2c23cb7cSEd Maste 		else
982*2c23cb7cSEd Maste 			snprintf(s_shndx, sizeof(s_shndx), "%u", shndx);
983*2c23cb7cSEd Maste 		return (s_shndx);
984*2c23cb7cSEd Maste 	}
985*2c23cb7cSEd Maste }
986*2c23cb7cSEd Maste 
987*2c23cb7cSEd Maste static struct {
988*2c23cb7cSEd Maste 	const char *ln;
989*2c23cb7cSEd Maste 	char sn;
990*2c23cb7cSEd Maste 	int value;
991*2c23cb7cSEd Maste } section_flag[] = {
992*2c23cb7cSEd Maste 	{"WRITE", 'W', SHF_WRITE},
993*2c23cb7cSEd Maste 	{"ALLOC", 'A', SHF_ALLOC},
994*2c23cb7cSEd Maste 	{"EXEC", 'X', SHF_EXECINSTR},
995*2c23cb7cSEd Maste 	{"MERGE", 'M', SHF_MERGE},
996*2c23cb7cSEd Maste 	{"STRINGS", 'S', SHF_STRINGS},
997*2c23cb7cSEd Maste 	{"INFO LINK", 'I', SHF_INFO_LINK},
998*2c23cb7cSEd Maste 	{"OS NONCONF", 'O', SHF_OS_NONCONFORMING},
999*2c23cb7cSEd Maste 	{"GROUP", 'G', SHF_GROUP},
1000*2c23cb7cSEd Maste 	{"TLS", 'T', SHF_TLS},
1001*2c23cb7cSEd Maste 	{NULL, 0, 0}
1002*2c23cb7cSEd Maste };
1003*2c23cb7cSEd Maste 
1004*2c23cb7cSEd Maste static const char *
1005*2c23cb7cSEd Maste r_type(unsigned int mach, unsigned int type)
1006*2c23cb7cSEd Maste {
1007*2c23cb7cSEd Maste 	switch(mach) {
1008*2c23cb7cSEd Maste 	case EM_NONE: return "";
1009*2c23cb7cSEd Maste 	case EM_386:
1010*2c23cb7cSEd Maste 		switch(type) {
1011*2c23cb7cSEd Maste 		case 0: return "R_386_NONE";
1012*2c23cb7cSEd Maste 		case 1: return "R_386_32";
1013*2c23cb7cSEd Maste 		case 2: return "R_386_PC32";
1014*2c23cb7cSEd Maste 		case 3: return "R_386_GOT32";
1015*2c23cb7cSEd Maste 		case 4: return "R_386_PLT32";
1016*2c23cb7cSEd Maste 		case 5: return "R_386_COPY";
1017*2c23cb7cSEd Maste 		case 6: return "R_386_GLOB_DAT";
1018*2c23cb7cSEd Maste 		case 7: return "R_386_JMP_SLOT";
1019*2c23cb7cSEd Maste 		case 8: return "R_386_RELATIVE";
1020*2c23cb7cSEd Maste 		case 9: return "R_386_GOTOFF";
1021*2c23cb7cSEd Maste 		case 10: return "R_386_GOTPC";
1022*2c23cb7cSEd Maste 		case 14: return "R_386_TLS_TPOFF";
1023*2c23cb7cSEd Maste 		case 15: return "R_386_TLS_IE";
1024*2c23cb7cSEd Maste 		case 16: return "R_386_TLS_GOTIE";
1025*2c23cb7cSEd Maste 		case 17: return "R_386_TLS_LE";
1026*2c23cb7cSEd Maste 		case 18: return "R_386_TLS_GD";
1027*2c23cb7cSEd Maste 		case 19: return "R_386_TLS_LDM";
1028*2c23cb7cSEd Maste 		case 24: return "R_386_TLS_GD_32";
1029*2c23cb7cSEd Maste 		case 25: return "R_386_TLS_GD_PUSH";
1030*2c23cb7cSEd Maste 		case 26: return "R_386_TLS_GD_CALL";
1031*2c23cb7cSEd Maste 		case 27: return "R_386_TLS_GD_POP";
1032*2c23cb7cSEd Maste 		case 28: return "R_386_TLS_LDM_32";
1033*2c23cb7cSEd Maste 		case 29: return "R_386_TLS_LDM_PUSH";
1034*2c23cb7cSEd Maste 		case 30: return "R_386_TLS_LDM_CALL";
1035*2c23cb7cSEd Maste 		case 31: return "R_386_TLS_LDM_POP";
1036*2c23cb7cSEd Maste 		case 32: return "R_386_TLS_LDO_32";
1037*2c23cb7cSEd Maste 		case 33: return "R_386_TLS_IE_32";
1038*2c23cb7cSEd Maste 		case 34: return "R_386_TLS_LE_32";
1039*2c23cb7cSEd Maste 		case 35: return "R_386_TLS_DTPMOD32";
1040*2c23cb7cSEd Maste 		case 36: return "R_386_TLS_DTPOFF32";
1041*2c23cb7cSEd Maste 		case 37: return "R_386_TLS_TPOFF32";
1042*2c23cb7cSEd Maste 		default: return "";
1043*2c23cb7cSEd Maste 		}
1044*2c23cb7cSEd Maste 	case EM_ARM:
1045*2c23cb7cSEd Maste 		switch(type) {
1046*2c23cb7cSEd Maste 		case 0: return "R_ARM_NONE";
1047*2c23cb7cSEd Maste 		case 1: return "R_ARM_PC24";
1048*2c23cb7cSEd Maste 		case 2: return "R_ARM_ABS32";
1049*2c23cb7cSEd Maste 		case 3: return "R_ARM_REL32";
1050*2c23cb7cSEd Maste 		case 4: return "R_ARM_PC13";
1051*2c23cb7cSEd Maste 		case 5: return "R_ARM_ABS16";
1052*2c23cb7cSEd Maste 		case 6: return "R_ARM_ABS12";
1053*2c23cb7cSEd Maste 		case 7: return "R_ARM_THM_ABS5";
1054*2c23cb7cSEd Maste 		case 8: return "R_ARM_ABS8";
1055*2c23cb7cSEd Maste 		case 9: return "R_ARM_SBREL32";
1056*2c23cb7cSEd Maste 		case 10: return "R_ARM_THM_PC22";
1057*2c23cb7cSEd Maste 		case 11: return "R_ARM_THM_PC8";
1058*2c23cb7cSEd Maste 		case 12: return "R_ARM_AMP_VCALL9";
1059*2c23cb7cSEd Maste 		case 13: return "R_ARM_SWI24";
1060*2c23cb7cSEd Maste 		case 14: return "R_ARM_THM_SWI8";
1061*2c23cb7cSEd Maste 		case 15: return "R_ARM_XPC25";
1062*2c23cb7cSEd Maste 		case 16: return "R_ARM_THM_XPC22";
1063*2c23cb7cSEd Maste 		case 20: return "R_ARM_COPY";
1064*2c23cb7cSEd Maste 		case 21: return "R_ARM_GLOB_DAT";
1065*2c23cb7cSEd Maste 		case 22: return "R_ARM_JUMP_SLOT";
1066*2c23cb7cSEd Maste 		case 23: return "R_ARM_RELATIVE";
1067*2c23cb7cSEd Maste 		case 24: return "R_ARM_GOTOFF";
1068*2c23cb7cSEd Maste 		case 25: return "R_ARM_GOTPC";
1069*2c23cb7cSEd Maste 		case 26: return "R_ARM_GOT32";
1070*2c23cb7cSEd Maste 		case 27: return "R_ARM_PLT32";
1071*2c23cb7cSEd Maste 		case 100: return "R_ARM_GNU_VTENTRY";
1072*2c23cb7cSEd Maste 		case 101: return "R_ARM_GNU_VTINHERIT";
1073*2c23cb7cSEd Maste 		case 250: return "R_ARM_RSBREL32";
1074*2c23cb7cSEd Maste 		case 251: return "R_ARM_THM_RPC22";
1075*2c23cb7cSEd Maste 		case 252: return "R_ARM_RREL32";
1076*2c23cb7cSEd Maste 		case 253: return "R_ARM_RABS32";
1077*2c23cb7cSEd Maste 		case 254: return "R_ARM_RPC24";
1078*2c23cb7cSEd Maste 		case 255: return "R_ARM_RBASE";
1079*2c23cb7cSEd Maste 		default: return "";
1080*2c23cb7cSEd Maste 		}
1081*2c23cb7cSEd Maste 	case EM_IA_64:
1082*2c23cb7cSEd Maste 		switch(type) {
1083*2c23cb7cSEd Maste 		case 0: return "R_IA_64_NONE";
1084*2c23cb7cSEd Maste 		case 33: return "R_IA_64_IMM14";
1085*2c23cb7cSEd Maste 		case 34: return "R_IA_64_IMM22";
1086*2c23cb7cSEd Maste 		case 35: return "R_IA_64_IMM64";
1087*2c23cb7cSEd Maste 		case 36: return "R_IA_64_DIR32MSB";
1088*2c23cb7cSEd Maste 		case 37: return "R_IA_64_DIR32LSB";
1089*2c23cb7cSEd Maste 		case 38: return "R_IA_64_DIR64MSB";
1090*2c23cb7cSEd Maste 		case 39: return "R_IA_64_DIR64LSB";
1091*2c23cb7cSEd Maste 		case 42: return "R_IA_64_GPREL22";
1092*2c23cb7cSEd Maste 		case 43: return "R_IA_64_GPREL64I";
1093*2c23cb7cSEd Maste 		case 44: return "R_IA_64_GPREL32MSB";
1094*2c23cb7cSEd Maste 		case 45: return "R_IA_64_GPREL32LSB";
1095*2c23cb7cSEd Maste 		case 46: return "R_IA_64_GPREL64MSB";
1096*2c23cb7cSEd Maste 		case 47: return "R_IA_64_GPREL64LSB";
1097*2c23cb7cSEd Maste 		case 50: return "R_IA_64_LTOFF22";
1098*2c23cb7cSEd Maste 		case 51: return "R_IA_64_LTOFF64I";
1099*2c23cb7cSEd Maste 		case 58: return "R_IA_64_PLTOFF22";
1100*2c23cb7cSEd Maste 		case 59: return "R_IA_64_PLTOFF64I";
1101*2c23cb7cSEd Maste 		case 62: return "R_IA_64_PLTOFF64MSB";
1102*2c23cb7cSEd Maste 		case 63: return "R_IA_64_PLTOFF64LSB";
1103*2c23cb7cSEd Maste 		case 67: return "R_IA_64_FPTR64I";
1104*2c23cb7cSEd Maste 		case 68: return "R_IA_64_FPTR32MSB";
1105*2c23cb7cSEd Maste 		case 69: return "R_IA_64_FPTR32LSB";
1106*2c23cb7cSEd Maste 		case 70: return "R_IA_64_FPTR64MSB";
1107*2c23cb7cSEd Maste 		case 71: return "R_IA_64_FPTR64LSB";
1108*2c23cb7cSEd Maste 		case 72: return "R_IA_64_PCREL60B";
1109*2c23cb7cSEd Maste 		case 73: return "R_IA_64_PCREL21B";
1110*2c23cb7cSEd Maste 		case 74: return "R_IA_64_PCREL21M";
1111*2c23cb7cSEd Maste 		case 75: return "R_IA_64_PCREL21F";
1112*2c23cb7cSEd Maste 		case 76: return "R_IA_64_PCREL32MSB";
1113*2c23cb7cSEd Maste 		case 77: return "R_IA_64_PCREL32LSB";
1114*2c23cb7cSEd Maste 		case 78: return "R_IA_64_PCREL64MSB";
1115*2c23cb7cSEd Maste 		case 79: return "R_IA_64_PCREL64LSB";
1116*2c23cb7cSEd Maste 		case 82: return "R_IA_64_LTOFF_FPTR22";
1117*2c23cb7cSEd Maste 		case 83: return "R_IA_64_LTOFF_FPTR64I";
1118*2c23cb7cSEd Maste 		case 84: return "R_IA_64_LTOFF_FPTR32MSB";
1119*2c23cb7cSEd Maste 		case 85: return "R_IA_64_LTOFF_FPTR32LSB";
1120*2c23cb7cSEd Maste 		case 86: return "R_IA_64_LTOFF_FPTR64MSB";
1121*2c23cb7cSEd Maste 		case 87: return "R_IA_64_LTOFF_FPTR64LSB";
1122*2c23cb7cSEd Maste 		case 92: return "R_IA_64_SEGREL32MSB";
1123*2c23cb7cSEd Maste 		case 93: return "R_IA_64_SEGREL32LSB";
1124*2c23cb7cSEd Maste 		case 94: return "R_IA_64_SEGREL64MSB";
1125*2c23cb7cSEd Maste 		case 95: return "R_IA_64_SEGREL64LSB";
1126*2c23cb7cSEd Maste 		case 100: return "R_IA_64_SECREL32MSB";
1127*2c23cb7cSEd Maste 		case 101: return "R_IA_64_SECREL32LSB";
1128*2c23cb7cSEd Maste 		case 102: return "R_IA_64_SECREL64MSB";
1129*2c23cb7cSEd Maste 		case 103: return "R_IA_64_SECREL64LSB";
1130*2c23cb7cSEd Maste 		case 108: return "R_IA_64_REL32MSB";
1131*2c23cb7cSEd Maste 		case 109: return "R_IA_64_REL32LSB";
1132*2c23cb7cSEd Maste 		case 110: return "R_IA_64_REL64MSB";
1133*2c23cb7cSEd Maste 		case 111: return "R_IA_64_REL64LSB";
1134*2c23cb7cSEd Maste 		case 116: return "R_IA_64_LTV32MSB";
1135*2c23cb7cSEd Maste 		case 117: return "R_IA_64_LTV32LSB";
1136*2c23cb7cSEd Maste 		case 118: return "R_IA_64_LTV64MSB";
1137*2c23cb7cSEd Maste 		case 119: return "R_IA_64_LTV64LSB";
1138*2c23cb7cSEd Maste 		case 121: return "R_IA_64_PCREL21BI";
1139*2c23cb7cSEd Maste 		case 122: return "R_IA_64_PCREL22";
1140*2c23cb7cSEd Maste 		case 123: return "R_IA_64_PCREL64I";
1141*2c23cb7cSEd Maste 		case 128: return "R_IA_64_IPLTMSB";
1142*2c23cb7cSEd Maste 		case 129: return "R_IA_64_IPLTLSB";
1143*2c23cb7cSEd Maste 		case 133: return "R_IA_64_SUB";
1144*2c23cb7cSEd Maste 		case 134: return "R_IA_64_LTOFF22X";
1145*2c23cb7cSEd Maste 		case 135: return "R_IA_64_LDXMOV";
1146*2c23cb7cSEd Maste 		case 145: return "R_IA_64_TPREL14";
1147*2c23cb7cSEd Maste 		case 146: return "R_IA_64_TPREL22";
1148*2c23cb7cSEd Maste 		case 147: return "R_IA_64_TPREL64I";
1149*2c23cb7cSEd Maste 		case 150: return "R_IA_64_TPREL64MSB";
1150*2c23cb7cSEd Maste 		case 151: return "R_IA_64_TPREL64LSB";
1151*2c23cb7cSEd Maste 		case 154: return "R_IA_64_LTOFF_TPREL22";
1152*2c23cb7cSEd Maste 		case 166: return "R_IA_64_DTPMOD64MSB";
1153*2c23cb7cSEd Maste 		case 167: return "R_IA_64_DTPMOD64LSB";
1154*2c23cb7cSEd Maste 		case 170: return "R_IA_64_LTOFF_DTPMOD22";
1155*2c23cb7cSEd Maste 		case 177: return "R_IA_64_DTPREL14";
1156*2c23cb7cSEd Maste 		case 178: return "R_IA_64_DTPREL22";
1157*2c23cb7cSEd Maste 		case 179: return "R_IA_64_DTPREL64I";
1158*2c23cb7cSEd Maste 		case 180: return "R_IA_64_DTPREL32MSB";
1159*2c23cb7cSEd Maste 		case 181: return "R_IA_64_DTPREL32LSB";
1160*2c23cb7cSEd Maste 		case 182: return "R_IA_64_DTPREL64MSB";
1161*2c23cb7cSEd Maste 		case 183: return "R_IA_64_DTPREL64LSB";
1162*2c23cb7cSEd Maste 		case 186: return "R_IA_64_LTOFF_DTPREL22";
1163*2c23cb7cSEd Maste 		default: return "";
1164*2c23cb7cSEd Maste 		}
1165*2c23cb7cSEd Maste 	case EM_MIPS:
1166*2c23cb7cSEd Maste 		switch(type) {
1167*2c23cb7cSEd Maste 		case 0: return "R_MIPS_NONE";
1168*2c23cb7cSEd Maste 		case 1: return "R_MIPS_16";
1169*2c23cb7cSEd Maste 		case 2: return "R_MIPS_32";
1170*2c23cb7cSEd Maste 		case 3: return "R_MIPS_REL32";
1171*2c23cb7cSEd Maste 		case 4: return "R_MIPS_26";
1172*2c23cb7cSEd Maste 		case 5: return "R_MIPS_HI16";
1173*2c23cb7cSEd Maste 		case 6: return "R_MIPS_LO16";
1174*2c23cb7cSEd Maste 		case 7: return "R_MIPS_GPREL16";
1175*2c23cb7cSEd Maste 		case 8: return "R_MIPS_LITERAL";
1176*2c23cb7cSEd Maste 		case 9: return "R_MIPS_GOT16";
1177*2c23cb7cSEd Maste 		case 10: return "R_MIPS_PC16";
1178*2c23cb7cSEd Maste 		case 11: return "R_MIPS_CALL16";
1179*2c23cb7cSEd Maste 		case 12: return "R_MIPS_GPREL32";
1180*2c23cb7cSEd Maste 		case 21: return "R_MIPS_GOTHI16";
1181*2c23cb7cSEd Maste 		case 22: return "R_MIPS_GOTLO16";
1182*2c23cb7cSEd Maste 		case 30: return "R_MIPS_CALLHI16";
1183*2c23cb7cSEd Maste 		case 31: return "R_MIPS_CALLLO16";
1184*2c23cb7cSEd Maste 		default: return "";
1185*2c23cb7cSEd Maste 		}
1186*2c23cb7cSEd Maste 	case EM_PPC:
1187*2c23cb7cSEd Maste 		switch(type) {
1188*2c23cb7cSEd Maste 		case 0: return "R_PPC_NONE";
1189*2c23cb7cSEd Maste 		case 1: return "R_PPC_ADDR32";
1190*2c23cb7cSEd Maste 		case 2: return "R_PPC_ADDR24";
1191*2c23cb7cSEd Maste 		case 3: return "R_PPC_ADDR16";
1192*2c23cb7cSEd Maste 		case 4: return "R_PPC_ADDR16_LO";
1193*2c23cb7cSEd Maste 		case 5: return "R_PPC_ADDR16_HI";
1194*2c23cb7cSEd Maste 		case 6: return "R_PPC_ADDR16_HA";
1195*2c23cb7cSEd Maste 		case 7: return "R_PPC_ADDR14";
1196*2c23cb7cSEd Maste 		case 8: return "R_PPC_ADDR14_BRTAKEN";
1197*2c23cb7cSEd Maste 		case 9: return "R_PPC_ADDR14_BRNTAKEN";
1198*2c23cb7cSEd Maste 		case 10: return "R_PPC_REL24";
1199*2c23cb7cSEd Maste 		case 11: return "R_PPC_REL14";
1200*2c23cb7cSEd Maste 		case 12: return "R_PPC_REL14_BRTAKEN";
1201*2c23cb7cSEd Maste 		case 13: return "R_PPC_REL14_BRNTAKEN";
1202*2c23cb7cSEd Maste 		case 14: return "R_PPC_GOT16";
1203*2c23cb7cSEd Maste 		case 15: return "R_PPC_GOT16_LO";
1204*2c23cb7cSEd Maste 		case 16: return "R_PPC_GOT16_HI";
1205*2c23cb7cSEd Maste 		case 17: return "R_PPC_GOT16_HA";
1206*2c23cb7cSEd Maste 		case 18: return "R_PPC_PLTREL24";
1207*2c23cb7cSEd Maste 		case 19: return "R_PPC_COPY";
1208*2c23cb7cSEd Maste 		case 20: return "R_PPC_GLOB_DAT";
1209*2c23cb7cSEd Maste 		case 21: return "R_PPC_JMP_SLOT";
1210*2c23cb7cSEd Maste 		case 22: return "R_PPC_RELATIVE";
1211*2c23cb7cSEd Maste 		case 23: return "R_PPC_LOCAL24PC";
1212*2c23cb7cSEd Maste 		case 24: return "R_PPC_UADDR32";
1213*2c23cb7cSEd Maste 		case 25: return "R_PPC_UADDR16";
1214*2c23cb7cSEd Maste 		case 26: return "R_PPC_REL32";
1215*2c23cb7cSEd Maste 		case 27: return "R_PPC_PLT32";
1216*2c23cb7cSEd Maste 		case 28: return "R_PPC_PLTREL32";
1217*2c23cb7cSEd Maste 		case 29: return "R_PPC_PLT16_LO";
1218*2c23cb7cSEd Maste 		case 30: return "R_PPC_PLT16_HI";
1219*2c23cb7cSEd Maste 		case 31: return "R_PPC_PLT16_HA";
1220*2c23cb7cSEd Maste 		case 32: return "R_PPC_SDAREL16";
1221*2c23cb7cSEd Maste 		case 33: return "R_PPC_SECTOFF";
1222*2c23cb7cSEd Maste 		case 34: return "R_PPC_SECTOFF_LO";
1223*2c23cb7cSEd Maste 		case 35: return "R_PPC_SECTOFF_HI";
1224*2c23cb7cSEd Maste 		case 36: return "R_PPC_SECTOFF_HA";
1225*2c23cb7cSEd Maste 		case 67: return "R_PPC_TLS";
1226*2c23cb7cSEd Maste 		case 68: return "R_PPC_DTPMOD32";
1227*2c23cb7cSEd Maste 		case 69: return "R_PPC_TPREL16";
1228*2c23cb7cSEd Maste 		case 70: return "R_PPC_TPREL16_LO";
1229*2c23cb7cSEd Maste 		case 71: return "R_PPC_TPREL16_HI";
1230*2c23cb7cSEd Maste 		case 72: return "R_PPC_TPREL16_HA";
1231*2c23cb7cSEd Maste 		case 73: return "R_PPC_TPREL32";
1232*2c23cb7cSEd Maste 		case 74: return "R_PPC_DTPREL16";
1233*2c23cb7cSEd Maste 		case 75: return "R_PPC_DTPREL16_LO";
1234*2c23cb7cSEd Maste 		case 76: return "R_PPC_DTPREL16_HI";
1235*2c23cb7cSEd Maste 		case 77: return "R_PPC_DTPREL16_HA";
1236*2c23cb7cSEd Maste 		case 78: return "R_PPC_DTPREL32";
1237*2c23cb7cSEd Maste 		case 79: return "R_PPC_GOT_TLSGD16";
1238*2c23cb7cSEd Maste 		case 80: return "R_PPC_GOT_TLSGD16_LO";
1239*2c23cb7cSEd Maste 		case 81: return "R_PPC_GOT_TLSGD16_HI";
1240*2c23cb7cSEd Maste 		case 82: return "R_PPC_GOT_TLSGD16_HA";
1241*2c23cb7cSEd Maste 		case 83: return "R_PPC_GOT_TLSLD16";
1242*2c23cb7cSEd Maste 		case 84: return "R_PPC_GOT_TLSLD16_LO";
1243*2c23cb7cSEd Maste 		case 85: return "R_PPC_GOT_TLSLD16_HI";
1244*2c23cb7cSEd Maste 		case 86: return "R_PPC_GOT_TLSLD16_HA";
1245*2c23cb7cSEd Maste 		case 87: return "R_PPC_GOT_TPREL16";
1246*2c23cb7cSEd Maste 		case 88: return "R_PPC_GOT_TPREL16_LO";
1247*2c23cb7cSEd Maste 		case 89: return "R_PPC_GOT_TPREL16_HI";
1248*2c23cb7cSEd Maste 		case 90: return "R_PPC_GOT_TPREL16_HA";
1249*2c23cb7cSEd Maste 		case 101: return "R_PPC_EMB_NADDR32";
1250*2c23cb7cSEd Maste 		case 102: return "R_PPC_EMB_NADDR16";
1251*2c23cb7cSEd Maste 		case 103: return "R_PPC_EMB_NADDR16_LO";
1252*2c23cb7cSEd Maste 		case 104: return "R_PPC_EMB_NADDR16_HI";
1253*2c23cb7cSEd Maste 		case 105: return "R_PPC_EMB_NADDR16_HA";
1254*2c23cb7cSEd Maste 		case 106: return "R_PPC_EMB_SDAI16";
1255*2c23cb7cSEd Maste 		case 107: return "R_PPC_EMB_SDA2I16";
1256*2c23cb7cSEd Maste 		case 108: return "R_PPC_EMB_SDA2REL";
1257*2c23cb7cSEd Maste 		case 109: return "R_PPC_EMB_SDA21";
1258*2c23cb7cSEd Maste 		case 110: return "R_PPC_EMB_MRKREF";
1259*2c23cb7cSEd Maste 		case 111: return "R_PPC_EMB_RELSEC16";
1260*2c23cb7cSEd Maste 		case 112: return "R_PPC_EMB_RELST_LO";
1261*2c23cb7cSEd Maste 		case 113: return "R_PPC_EMB_RELST_HI";
1262*2c23cb7cSEd Maste 		case 114: return "R_PPC_EMB_RELST_HA";
1263*2c23cb7cSEd Maste 		case 115: return "R_PPC_EMB_BIT_FLD";
1264*2c23cb7cSEd Maste 		case 116: return "R_PPC_EMB_RELSDA";
1265*2c23cb7cSEd Maste 		default: return "";
1266*2c23cb7cSEd Maste 		}
1267*2c23cb7cSEd Maste 	case EM_SPARC:
1268*2c23cb7cSEd Maste 	case EM_SPARCV9:
1269*2c23cb7cSEd Maste 		switch(type) {
1270*2c23cb7cSEd Maste 		case 0: return "R_SPARC_NONE";
1271*2c23cb7cSEd Maste 		case 1: return "R_SPARC_8";
1272*2c23cb7cSEd Maste 		case 2: return "R_SPARC_16";
1273*2c23cb7cSEd Maste 		case 3: return "R_SPARC_32";
1274*2c23cb7cSEd Maste 		case 4: return "R_SPARC_DISP8";
1275*2c23cb7cSEd Maste 		case 5: return "R_SPARC_DISP16";
1276*2c23cb7cSEd Maste 		case 6: return "R_SPARC_DISP32";
1277*2c23cb7cSEd Maste 		case 7: return "R_SPARC_WDISP30";
1278*2c23cb7cSEd Maste 		case 8: return "R_SPARC_WDISP22";
1279*2c23cb7cSEd Maste 		case 9: return "R_SPARC_HI22";
1280*2c23cb7cSEd Maste 		case 10: return "R_SPARC_22";
1281*2c23cb7cSEd Maste 		case 11: return "R_SPARC_13";
1282*2c23cb7cSEd Maste 		case 12: return "R_SPARC_LO10";
1283*2c23cb7cSEd Maste 		case 13: return "R_SPARC_GOT10";
1284*2c23cb7cSEd Maste 		case 14: return "R_SPARC_GOT13";
1285*2c23cb7cSEd Maste 		case 15: return "R_SPARC_GOT22";
1286*2c23cb7cSEd Maste 		case 16: return "R_SPARC_PC10";
1287*2c23cb7cSEd Maste 		case 17: return "R_SPARC_PC22";
1288*2c23cb7cSEd Maste 		case 18: return "R_SPARC_WPLT30";
1289*2c23cb7cSEd Maste 		case 19: return "R_SPARC_COPY";
1290*2c23cb7cSEd Maste 		case 20: return "R_SPARC_GLOB_DAT";
1291*2c23cb7cSEd Maste 		case 21: return "R_SPARC_JMP_SLOT";
1292*2c23cb7cSEd Maste 		case 22: return "R_SPARC_RELATIVE";
1293*2c23cb7cSEd Maste 		case 23: return "R_SPARC_UA32";
1294*2c23cb7cSEd Maste 		case 24: return "R_SPARC_PLT32";
1295*2c23cb7cSEd Maste 		case 25: return "R_SPARC_HIPLT22";
1296*2c23cb7cSEd Maste 		case 26: return "R_SPARC_LOPLT10";
1297*2c23cb7cSEd Maste 		case 27: return "R_SPARC_PCPLT32";
1298*2c23cb7cSEd Maste 		case 28: return "R_SPARC_PCPLT22";
1299*2c23cb7cSEd Maste 		case 29: return "R_SPARC_PCPLT10";
1300*2c23cb7cSEd Maste 		case 30: return "R_SPARC_10";
1301*2c23cb7cSEd Maste 		case 31: return "R_SPARC_11";
1302*2c23cb7cSEd Maste 		case 32: return "R_SPARC_64";
1303*2c23cb7cSEd Maste 		case 33: return "R_SPARC_OLO10";
1304*2c23cb7cSEd Maste 		case 34: return "R_SPARC_HH22";
1305*2c23cb7cSEd Maste 		case 35: return "R_SPARC_HM10";
1306*2c23cb7cSEd Maste 		case 36: return "R_SPARC_LM22";
1307*2c23cb7cSEd Maste 		case 37: return "R_SPARC_PC_HH22";
1308*2c23cb7cSEd Maste 		case 38: return "R_SPARC_PC_HM10";
1309*2c23cb7cSEd Maste 		case 39: return "R_SPARC_PC_LM22";
1310*2c23cb7cSEd Maste 		case 40: return "R_SPARC_WDISP16";
1311*2c23cb7cSEd Maste 		case 41: return "R_SPARC_WDISP19";
1312*2c23cb7cSEd Maste 		case 42: return "R_SPARC_GLOB_JMP";
1313*2c23cb7cSEd Maste 		case 43: return "R_SPARC_7";
1314*2c23cb7cSEd Maste 		case 44: return "R_SPARC_5";
1315*2c23cb7cSEd Maste 		case 45: return "R_SPARC_6";
1316*2c23cb7cSEd Maste 		case 46: return "R_SPARC_DISP64";
1317*2c23cb7cSEd Maste 		case 47: return "R_SPARC_PLT64";
1318*2c23cb7cSEd Maste 		case 48: return "R_SPARC_HIX22";
1319*2c23cb7cSEd Maste 		case 49: return "R_SPARC_LOX10";
1320*2c23cb7cSEd Maste 		case 50: return "R_SPARC_H44";
1321*2c23cb7cSEd Maste 		case 51: return "R_SPARC_M44";
1322*2c23cb7cSEd Maste 		case 52: return "R_SPARC_L44";
1323*2c23cb7cSEd Maste 		case 53: return "R_SPARC_REGISTER";
1324*2c23cb7cSEd Maste 		case 54: return "R_SPARC_UA64";
1325*2c23cb7cSEd Maste 		case 55: return "R_SPARC_UA16";
1326*2c23cb7cSEd Maste 		case 56: return "R_SPARC_TLS_GD_HI22";
1327*2c23cb7cSEd Maste 		case 57: return "R_SPARC_TLS_GD_LO10";
1328*2c23cb7cSEd Maste 		case 58: return "R_SPARC_TLS_GD_ADD";
1329*2c23cb7cSEd Maste 		case 59: return "R_SPARC_TLS_GD_CALL";
1330*2c23cb7cSEd Maste 		case 60: return "R_SPARC_TLS_LDM_HI22";
1331*2c23cb7cSEd Maste 		case 61: return "R_SPARC_TLS_LDM_LO10";
1332*2c23cb7cSEd Maste 		case 62: return "R_SPARC_TLS_LDM_ADD";
1333*2c23cb7cSEd Maste 		case 63: return "R_SPARC_TLS_LDM_CALL";
1334*2c23cb7cSEd Maste 		case 64: return "R_SPARC_TLS_LDO_HIX22";
1335*2c23cb7cSEd Maste 		case 65: return "R_SPARC_TLS_LDO_LOX10";
1336*2c23cb7cSEd Maste 		case 66: return "R_SPARC_TLS_LDO_ADD";
1337*2c23cb7cSEd Maste 		case 67: return "R_SPARC_TLS_IE_HI22";
1338*2c23cb7cSEd Maste 		case 68: return "R_SPARC_TLS_IE_LO10";
1339*2c23cb7cSEd Maste 		case 69: return "R_SPARC_TLS_IE_LD";
1340*2c23cb7cSEd Maste 		case 70: return "R_SPARC_TLS_IE_LDX";
1341*2c23cb7cSEd Maste 		case 71: return "R_SPARC_TLS_IE_ADD";
1342*2c23cb7cSEd Maste 		case 72: return "R_SPARC_TLS_LE_HIX22";
1343*2c23cb7cSEd Maste 		case 73: return "R_SPARC_TLS_LE_LOX10";
1344*2c23cb7cSEd Maste 		case 74: return "R_SPARC_TLS_DTPMOD32";
1345*2c23cb7cSEd Maste 		case 75: return "R_SPARC_TLS_DTPMOD64";
1346*2c23cb7cSEd Maste 		case 76: return "R_SPARC_TLS_DTPOFF32";
1347*2c23cb7cSEd Maste 		case 77: return "R_SPARC_TLS_DTPOFF64";
1348*2c23cb7cSEd Maste 		case 78: return "R_SPARC_TLS_TPOFF32";
1349*2c23cb7cSEd Maste 		case 79: return "R_SPARC_TLS_TPOFF64";
1350*2c23cb7cSEd Maste 		default: return "";
1351*2c23cb7cSEd Maste 		}
1352*2c23cb7cSEd Maste 	case EM_X86_64:
1353*2c23cb7cSEd Maste 		switch(type) {
1354*2c23cb7cSEd Maste 		case 0: return "R_X86_64_NONE";
1355*2c23cb7cSEd Maste 		case 1: return "R_X86_64_64";
1356*2c23cb7cSEd Maste 		case 2: return "R_X86_64_PC32";
1357*2c23cb7cSEd Maste 		case 3: return "R_X86_64_GOT32";
1358*2c23cb7cSEd Maste 		case 4: return "R_X86_64_PLT32";
1359*2c23cb7cSEd Maste 		case 5: return "R_X86_64_COPY";
1360*2c23cb7cSEd Maste 		case 6: return "R_X86_64_GLOB_DAT";
1361*2c23cb7cSEd Maste 		case 7: return "R_X86_64_JMP_SLOT";
1362*2c23cb7cSEd Maste 		case 8: return "R_X86_64_RELATIVE";
1363*2c23cb7cSEd Maste 		case 9: return "R_X86_64_GOTPCREL";
1364*2c23cb7cSEd Maste 		case 10: return "R_X86_64_32";
1365*2c23cb7cSEd Maste 		case 11: return "R_X86_64_32S";
1366*2c23cb7cSEd Maste 		case 12: return "R_X86_64_16";
1367*2c23cb7cSEd Maste 		case 13: return "R_X86_64_PC16";
1368*2c23cb7cSEd Maste 		case 14: return "R_X86_64_8";
1369*2c23cb7cSEd Maste 		case 15: return "R_X86_64_PC8";
1370*2c23cb7cSEd Maste 		case 16: return "R_X86_64_DTPMOD64";
1371*2c23cb7cSEd Maste 		case 17: return "R_X86_64_DTPOFF64";
1372*2c23cb7cSEd Maste 		case 18: return "R_X86_64_TPOFF64";
1373*2c23cb7cSEd Maste 		case 19: return "R_X86_64_TLSGD";
1374*2c23cb7cSEd Maste 		case 20: return "R_X86_64_TLSLD";
1375*2c23cb7cSEd Maste 		case 21: return "R_X86_64_DTPOFF32";
1376*2c23cb7cSEd Maste 		case 22: return "R_X86_64_GOTTPOFF";
1377*2c23cb7cSEd Maste 		case 23: return "R_X86_64_TPOFF32";
1378*2c23cb7cSEd Maste 		default: return "";
1379*2c23cb7cSEd Maste 		}
1380*2c23cb7cSEd Maste 	default: return "";
1381*2c23cb7cSEd Maste 	}
1382*2c23cb7cSEd Maste }
1383*2c23cb7cSEd Maste 
1384*2c23cb7cSEd Maste static const char *
1385*2c23cb7cSEd Maste note_type(unsigned int osabi, unsigned int et, unsigned int nt)
1386*2c23cb7cSEd Maste {
1387*2c23cb7cSEd Maste 	static char s_nt[32];
1388*2c23cb7cSEd Maste 
1389*2c23cb7cSEd Maste 	if (et == ET_CORE) {
1390*2c23cb7cSEd Maste 		switch (nt) {
1391*2c23cb7cSEd Maste 		case NT_PRSTATUS:
1392*2c23cb7cSEd Maste 			return "NT_PRSTATUS (Process status)";
1393*2c23cb7cSEd Maste 		case NT_FPREGSET:
1394*2c23cb7cSEd Maste 			return "NT_FPREGSET (Floating point information)";
1395*2c23cb7cSEd Maste 		case NT_PRPSINFO:
1396*2c23cb7cSEd Maste 			return "NT_PRPSINFO (Process information)";
1397*2c23cb7cSEd Maste 		case NT_AUXV:
1398*2c23cb7cSEd Maste 			return "NT_AUXV (Auxiliary vector)";
1399*2c23cb7cSEd Maste 		case NT_PRXFPREG:
1400*2c23cb7cSEd Maste 			return "NT_PRXFPREG (Linux user_xfpregs structure)";
1401*2c23cb7cSEd Maste 		case NT_PSTATUS:
1402*2c23cb7cSEd Maste 			return "NT_PSTATUS (Linux process status)";
1403*2c23cb7cSEd Maste 		case NT_FPREGS:
1404*2c23cb7cSEd Maste 			return "NT_FPREGS (Linux floating point regset)";
1405*2c23cb7cSEd Maste 		case NT_PSINFO:
1406*2c23cb7cSEd Maste 			return "NT_PSINFO (Linux process information)";
1407*2c23cb7cSEd Maste 		case NT_LWPSTATUS:
1408*2c23cb7cSEd Maste 			return "NT_LWPSTATUS (Linux lwpstatus_t type)";
1409*2c23cb7cSEd Maste 		case NT_LWPSINFO:
1410*2c23cb7cSEd Maste 			return "NT_LWPSINFO (Linux lwpinfo_t type)";
1411*2c23cb7cSEd Maste 		default:
1412*2c23cb7cSEd Maste 			snprintf(s_nt, sizeof(s_nt), "<unknown: %u>", nt);
1413*2c23cb7cSEd Maste 			return (s_nt);
1414*2c23cb7cSEd Maste 		}
1415*2c23cb7cSEd Maste 	} else {
1416*2c23cb7cSEd Maste 		switch (nt) {
1417*2c23cb7cSEd Maste 		case NT_ABI_TAG:
1418*2c23cb7cSEd Maste 			switch (osabi) {
1419*2c23cb7cSEd Maste 			case ELFOSABI_FREEBSD:
1420*2c23cb7cSEd Maste 				return "NT_FREEBSD_ABI_TAG";
1421*2c23cb7cSEd Maste 			case ELFOSABI_NETBSD:
1422*2c23cb7cSEd Maste 				return "NT_NETBSD_IDENT";
1423*2c23cb7cSEd Maste 			case ELFOSABI_OPENBSD:
1424*2c23cb7cSEd Maste 				return "NT_OPENBSD_IDENT";
1425*2c23cb7cSEd Maste 			default:
1426*2c23cb7cSEd Maste 				return "NT_GNU_ABI_TAG";
1427*2c23cb7cSEd Maste 			}
1428*2c23cb7cSEd Maste 		case NT_GNU_HWCAP:
1429*2c23cb7cSEd Maste 			return "NT_GNU_HWCAP (Hardware capabilities)";
1430*2c23cb7cSEd Maste 		case NT_GNU_BUILD_ID:
1431*2c23cb7cSEd Maste 			return "NT_GNU_BUILD_ID (Build id set by ld(1))";
1432*2c23cb7cSEd Maste 		case NT_GNU_GOLD_VERSION:
1433*2c23cb7cSEd Maste 			return "NT_GNU_GOLD_VERSION (GNU gold version)";
1434*2c23cb7cSEd Maste 		default:
1435*2c23cb7cSEd Maste 			snprintf(s_nt, sizeof(s_nt), "<unknown: %u>", nt);
1436*2c23cb7cSEd Maste 			return (s_nt);
1437*2c23cb7cSEd Maste 		}
1438*2c23cb7cSEd Maste 	}
1439*2c23cb7cSEd Maste }
1440*2c23cb7cSEd Maste 
1441*2c23cb7cSEd Maste static struct {
1442*2c23cb7cSEd Maste 	const char *name;
1443*2c23cb7cSEd Maste 	int value;
1444*2c23cb7cSEd Maste } l_flag[] = {
1445*2c23cb7cSEd Maste 	{"EXACT_MATCH", LL_EXACT_MATCH},
1446*2c23cb7cSEd Maste 	{"IGNORE_INT_VER", LL_IGNORE_INT_VER},
1447*2c23cb7cSEd Maste 	{"REQUIRE_MINOR", LL_REQUIRE_MINOR},
1448*2c23cb7cSEd Maste 	{"EXPORTS", LL_EXPORTS},
1449*2c23cb7cSEd Maste 	{"DELAY_LOAD", LL_DELAY_LOAD},
1450*2c23cb7cSEd Maste 	{"DELTA", LL_DELTA},
1451*2c23cb7cSEd Maste 	{NULL, 0}
1452*2c23cb7cSEd Maste };
1453*2c23cb7cSEd Maste 
1454*2c23cb7cSEd Maste static struct mips_option mips_exceptions_option[] = {
1455*2c23cb7cSEd Maste 	{OEX_PAGE0, "PAGE0"},
1456*2c23cb7cSEd Maste 	{OEX_SMM, "SMM"},
1457*2c23cb7cSEd Maste 	{OEX_PRECISEFP, "PRECISEFP"},
1458*2c23cb7cSEd Maste 	{OEX_DISMISS, "DISMISS"},
1459*2c23cb7cSEd Maste 	{0, NULL}
1460*2c23cb7cSEd Maste };
1461*2c23cb7cSEd Maste 
1462*2c23cb7cSEd Maste static struct mips_option mips_pad_option[] = {
1463*2c23cb7cSEd Maste 	{OPAD_PREFIX, "PREFIX"},
1464*2c23cb7cSEd Maste 	{OPAD_POSTFIX, "POSTFIX"},
1465*2c23cb7cSEd Maste 	{OPAD_SYMBOL, "SYMBOL"},
1466*2c23cb7cSEd Maste 	{0, NULL}
1467*2c23cb7cSEd Maste };
1468*2c23cb7cSEd Maste 
1469*2c23cb7cSEd Maste static struct mips_option mips_hwpatch_option[] = {
1470*2c23cb7cSEd Maste 	{OHW_R4KEOP, "R4KEOP"},
1471*2c23cb7cSEd Maste 	{OHW_R8KPFETCH, "R8KPFETCH"},
1472*2c23cb7cSEd Maste 	{OHW_R5KEOP, "R5KEOP"},
1473*2c23cb7cSEd Maste 	{OHW_R5KCVTL, "R5KCVTL"},
1474*2c23cb7cSEd Maste 	{0, NULL}
1475*2c23cb7cSEd Maste };
1476*2c23cb7cSEd Maste 
1477*2c23cb7cSEd Maste static struct mips_option mips_hwa_option[] = {
1478*2c23cb7cSEd Maste 	{OHWA0_R4KEOP_CHECKED, "R4KEOP_CHECKED"},
1479*2c23cb7cSEd Maste 	{OHWA0_R4KEOP_CLEAN, "R4KEOP_CLEAN"},
1480*2c23cb7cSEd Maste 	{0, NULL}
1481*2c23cb7cSEd Maste };
1482*2c23cb7cSEd Maste 
1483*2c23cb7cSEd Maste static struct mips_option mips_hwo_option[] = {
1484*2c23cb7cSEd Maste 	{OHWO0_FIXADE, "FIXADE"},
1485*2c23cb7cSEd Maste 	{0, NULL}
1486*2c23cb7cSEd Maste };
1487*2c23cb7cSEd Maste 
1488*2c23cb7cSEd Maste static const char *
1489*2c23cb7cSEd Maste option_kind(uint8_t kind)
1490*2c23cb7cSEd Maste {
1491*2c23cb7cSEd Maste 	static char s_kind[32];
1492*2c23cb7cSEd Maste 
1493*2c23cb7cSEd Maste 	switch (kind) {
1494*2c23cb7cSEd Maste 	case ODK_NULL: return "NULL";
1495*2c23cb7cSEd Maste 	case ODK_REGINFO: return "REGINFO";
1496*2c23cb7cSEd Maste 	case ODK_EXCEPTIONS: return "EXCEPTIONS";
1497*2c23cb7cSEd Maste 	case ODK_PAD: return "PAD";
1498*2c23cb7cSEd Maste 	case ODK_HWPATCH: return "HWPATCH";
1499*2c23cb7cSEd Maste 	case ODK_FILL: return "FILL";
1500*2c23cb7cSEd Maste 	case ODK_TAGS: return "TAGS";
1501*2c23cb7cSEd Maste 	case ODK_HWAND: return "HWAND";
1502*2c23cb7cSEd Maste 	case ODK_HWOR: return "HWOR";
1503*2c23cb7cSEd Maste 	case ODK_GP_GROUP: return "GP_GROUP";
1504*2c23cb7cSEd Maste 	case ODK_IDENT: return "IDENT";
1505*2c23cb7cSEd Maste 	default:
1506*2c23cb7cSEd Maste 		snprintf(s_kind, sizeof(s_kind), "<unknown: %u>", kind);
1507*2c23cb7cSEd Maste 		return (s_kind);
1508*2c23cb7cSEd Maste 	}
1509*2c23cb7cSEd Maste }
1510*2c23cb7cSEd Maste 
1511*2c23cb7cSEd Maste static const char *
1512*2c23cb7cSEd Maste top_tag(unsigned int tag)
1513*2c23cb7cSEd Maste {
1514*2c23cb7cSEd Maste 	static char s_top_tag[32];
1515*2c23cb7cSEd Maste 
1516*2c23cb7cSEd Maste 	switch (tag) {
1517*2c23cb7cSEd Maste 	case 1: return "File Attributes";
1518*2c23cb7cSEd Maste 	case 2: return "Section Attributes";
1519*2c23cb7cSEd Maste 	case 3: return "Symbol Attributes";
1520*2c23cb7cSEd Maste 	default:
1521*2c23cb7cSEd Maste 		snprintf(s_top_tag, sizeof(s_top_tag), "Unknown tag: %u", tag);
1522*2c23cb7cSEd Maste 		return (s_top_tag);
1523*2c23cb7cSEd Maste 	}
1524*2c23cb7cSEd Maste }
1525*2c23cb7cSEd Maste 
1526*2c23cb7cSEd Maste static const char *
1527*2c23cb7cSEd Maste aeabi_cpu_arch(uint64_t arch)
1528*2c23cb7cSEd Maste {
1529*2c23cb7cSEd Maste 	static char s_cpu_arch[32];
1530*2c23cb7cSEd Maste 
1531*2c23cb7cSEd Maste 	switch (arch) {
1532*2c23cb7cSEd Maste 	case 0: return "Pre-V4";
1533*2c23cb7cSEd Maste 	case 1: return "ARM v4";
1534*2c23cb7cSEd Maste 	case 2: return "ARM v4T";
1535*2c23cb7cSEd Maste 	case 3: return "ARM v5T";
1536*2c23cb7cSEd Maste 	case 4: return "ARM v5TE";
1537*2c23cb7cSEd Maste 	case 5: return "ARM v5TEJ";
1538*2c23cb7cSEd Maste 	case 6: return "ARM v6";
1539*2c23cb7cSEd Maste 	case 7: return "ARM v6KZ";
1540*2c23cb7cSEd Maste 	case 8: return "ARM v6T2";
1541*2c23cb7cSEd Maste 	case 9: return "ARM v6K";
1542*2c23cb7cSEd Maste 	case 10: return "ARM v7";
1543*2c23cb7cSEd Maste 	case 11: return "ARM v6-M";
1544*2c23cb7cSEd Maste 	case 12: return "ARM v6S-M";
1545*2c23cb7cSEd Maste 	case 13: return "ARM v7E-M";
1546*2c23cb7cSEd Maste 	default:
1547*2c23cb7cSEd Maste 		snprintf(s_cpu_arch, sizeof(s_cpu_arch),
1548*2c23cb7cSEd Maste 		    "Unknown (%ju)", (uintmax_t) arch);
1549*2c23cb7cSEd Maste 		return (s_cpu_arch);
1550*2c23cb7cSEd Maste 	}
1551*2c23cb7cSEd Maste }
1552*2c23cb7cSEd Maste 
1553*2c23cb7cSEd Maste static const char *
1554*2c23cb7cSEd Maste aeabi_cpu_arch_profile(uint64_t pf)
1555*2c23cb7cSEd Maste {
1556*2c23cb7cSEd Maste 	static char s_arch_profile[32];
1557*2c23cb7cSEd Maste 
1558*2c23cb7cSEd Maste 	switch (pf) {
1559*2c23cb7cSEd Maste 	case 0:
1560*2c23cb7cSEd Maste 		return "Not applicable";
1561*2c23cb7cSEd Maste 	case 0x41:		/* 'A' */
1562*2c23cb7cSEd Maste 		return "Application Profile";
1563*2c23cb7cSEd Maste 	case 0x52:		/* 'R' */
1564*2c23cb7cSEd Maste 		return "Real-Time Profile";
1565*2c23cb7cSEd Maste 	case 0x4D:		/* 'M' */
1566*2c23cb7cSEd Maste 		return "Microcontroller Profile";
1567*2c23cb7cSEd Maste 	case 0x53:		/* 'S' */
1568*2c23cb7cSEd Maste 		return "Application or Real-Time Profile";
1569*2c23cb7cSEd Maste 	default:
1570*2c23cb7cSEd Maste 		snprintf(s_arch_profile, sizeof(s_arch_profile),
1571*2c23cb7cSEd Maste 		    "Unknown (%ju)\n", (uintmax_t) pf);
1572*2c23cb7cSEd Maste 		return (s_arch_profile);
1573*2c23cb7cSEd Maste 	}
1574*2c23cb7cSEd Maste }
1575*2c23cb7cSEd Maste 
1576*2c23cb7cSEd Maste static const char *
1577*2c23cb7cSEd Maste aeabi_arm_isa(uint64_t ai)
1578*2c23cb7cSEd Maste {
1579*2c23cb7cSEd Maste 	static char s_ai[32];
1580*2c23cb7cSEd Maste 
1581*2c23cb7cSEd Maste 	switch (ai) {
1582*2c23cb7cSEd Maste 	case 0: return "No";
1583*2c23cb7cSEd Maste 	case 1: return "Yes";
1584*2c23cb7cSEd Maste 	default:
1585*2c23cb7cSEd Maste 		snprintf(s_ai, sizeof(s_ai), "Unknown (%ju)\n",
1586*2c23cb7cSEd Maste 		    (uintmax_t) ai);
1587*2c23cb7cSEd Maste 		return (s_ai);
1588*2c23cb7cSEd Maste 	}
1589*2c23cb7cSEd Maste }
1590*2c23cb7cSEd Maste 
1591*2c23cb7cSEd Maste static const char *
1592*2c23cb7cSEd Maste aeabi_thumb_isa(uint64_t ti)
1593*2c23cb7cSEd Maste {
1594*2c23cb7cSEd Maste 	static char s_ti[32];
1595*2c23cb7cSEd Maste 
1596*2c23cb7cSEd Maste 	switch (ti) {
1597*2c23cb7cSEd Maste 	case 0: return "No";
1598*2c23cb7cSEd Maste 	case 1: return "16-bit Thumb";
1599*2c23cb7cSEd Maste 	case 2: return "32-bit Thumb";
1600*2c23cb7cSEd Maste 	default:
1601*2c23cb7cSEd Maste 		snprintf(s_ti, sizeof(s_ti), "Unknown (%ju)\n",
1602*2c23cb7cSEd Maste 		    (uintmax_t) ti);
1603*2c23cb7cSEd Maste 		return (s_ti);
1604*2c23cb7cSEd Maste 	}
1605*2c23cb7cSEd Maste }
1606*2c23cb7cSEd Maste 
1607*2c23cb7cSEd Maste static const char *
1608*2c23cb7cSEd Maste aeabi_fp_arch(uint64_t fp)
1609*2c23cb7cSEd Maste {
1610*2c23cb7cSEd Maste 	static char s_fp_arch[32];
1611*2c23cb7cSEd Maste 
1612*2c23cb7cSEd Maste 	switch (fp) {
1613*2c23cb7cSEd Maste 	case 0: return "No";
1614*2c23cb7cSEd Maste 	case 1: return "VFPv1";
1615*2c23cb7cSEd Maste 	case 2: return "VFPv2";
1616*2c23cb7cSEd Maste 	case 3: return "VFPv3";
1617*2c23cb7cSEd Maste 	case 4: return "VFPv3-D16";
1618*2c23cb7cSEd Maste 	case 5: return "VFPv4";
1619*2c23cb7cSEd Maste 	case 6: return "VFPv4-D16";
1620*2c23cb7cSEd Maste 	default:
1621*2c23cb7cSEd Maste 		snprintf(s_fp_arch, sizeof(s_fp_arch), "Unknown (%ju)",
1622*2c23cb7cSEd Maste 		    (uintmax_t) fp);
1623*2c23cb7cSEd Maste 		return (s_fp_arch);
1624*2c23cb7cSEd Maste 	}
1625*2c23cb7cSEd Maste }
1626*2c23cb7cSEd Maste 
1627*2c23cb7cSEd Maste static const char *
1628*2c23cb7cSEd Maste aeabi_wmmx_arch(uint64_t wmmx)
1629*2c23cb7cSEd Maste {
1630*2c23cb7cSEd Maste 	static char s_wmmx[32];
1631*2c23cb7cSEd Maste 
1632*2c23cb7cSEd Maste 	switch (wmmx) {
1633*2c23cb7cSEd Maste 	case 0: return "No";
1634*2c23cb7cSEd Maste 	case 1: return "WMMXv1";
1635*2c23cb7cSEd Maste 	case 2: return "WMMXv2";
1636*2c23cb7cSEd Maste 	default:
1637*2c23cb7cSEd Maste 		snprintf(s_wmmx, sizeof(s_wmmx), "Unknown (%ju)",
1638*2c23cb7cSEd Maste 		    (uintmax_t) wmmx);
1639*2c23cb7cSEd Maste 		return (s_wmmx);
1640*2c23cb7cSEd Maste 	}
1641*2c23cb7cSEd Maste }
1642*2c23cb7cSEd Maste 
1643*2c23cb7cSEd Maste static const char *
1644*2c23cb7cSEd Maste aeabi_adv_simd_arch(uint64_t simd)
1645*2c23cb7cSEd Maste {
1646*2c23cb7cSEd Maste 	static char s_simd[32];
1647*2c23cb7cSEd Maste 
1648*2c23cb7cSEd Maste 	switch (simd) {
1649*2c23cb7cSEd Maste 	case 0: return "No";
1650*2c23cb7cSEd Maste 	case 1: return "NEONv1";
1651*2c23cb7cSEd Maste 	case 2: return "NEONv2";
1652*2c23cb7cSEd Maste 	default:
1653*2c23cb7cSEd Maste 		snprintf(s_simd, sizeof(s_simd), "Unknown (%ju)",
1654*2c23cb7cSEd Maste 		    (uintmax_t) simd);
1655*2c23cb7cSEd Maste 		return (s_simd);
1656*2c23cb7cSEd Maste 	}
1657*2c23cb7cSEd Maste }
1658*2c23cb7cSEd Maste 
1659*2c23cb7cSEd Maste static const char *
1660*2c23cb7cSEd Maste aeabi_pcs_config(uint64_t pcs)
1661*2c23cb7cSEd Maste {
1662*2c23cb7cSEd Maste 	static char s_pcs[32];
1663*2c23cb7cSEd Maste 
1664*2c23cb7cSEd Maste 	switch (pcs) {
1665*2c23cb7cSEd Maste 	case 0: return "None";
1666*2c23cb7cSEd Maste 	case 1: return "Bare platform";
1667*2c23cb7cSEd Maste 	case 2: return "Linux";
1668*2c23cb7cSEd Maste 	case 3: return "Linux DSO";
1669*2c23cb7cSEd Maste 	case 4: return "Palm OS 2004";
1670*2c23cb7cSEd Maste 	case 5: return "Palm OS (future)";
1671*2c23cb7cSEd Maste 	case 6: return "Symbian OS 2004";
1672*2c23cb7cSEd Maste 	case 7: return "Symbian OS (future)";
1673*2c23cb7cSEd Maste 	default:
1674*2c23cb7cSEd Maste 		snprintf(s_pcs, sizeof(s_pcs), "Unknown (%ju)",
1675*2c23cb7cSEd Maste 		    (uintmax_t) pcs);
1676*2c23cb7cSEd Maste 		return (s_pcs);
1677*2c23cb7cSEd Maste 	}
1678*2c23cb7cSEd Maste }
1679*2c23cb7cSEd Maste 
1680*2c23cb7cSEd Maste static const char *
1681*2c23cb7cSEd Maste aeabi_pcs_r9(uint64_t r9)
1682*2c23cb7cSEd Maste {
1683*2c23cb7cSEd Maste 	static char s_r9[32];
1684*2c23cb7cSEd Maste 
1685*2c23cb7cSEd Maste 	switch (r9) {
1686*2c23cb7cSEd Maste 	case 0: return "V6";
1687*2c23cb7cSEd Maste 	case 1: return "SB";
1688*2c23cb7cSEd Maste 	case 2: return "TLS pointer";
1689*2c23cb7cSEd Maste 	case 3: return "Unused";
1690*2c23cb7cSEd Maste 	default:
1691*2c23cb7cSEd Maste 		snprintf(s_r9, sizeof(s_r9), "Unknown (%ju)", (uintmax_t) r9);
1692*2c23cb7cSEd Maste 		return (s_r9);
1693*2c23cb7cSEd Maste 	}
1694*2c23cb7cSEd Maste }
1695*2c23cb7cSEd Maste 
1696*2c23cb7cSEd Maste static const char *
1697*2c23cb7cSEd Maste aeabi_pcs_rw(uint64_t rw)
1698*2c23cb7cSEd Maste {
1699*2c23cb7cSEd Maste 	static char s_rw[32];
1700*2c23cb7cSEd Maste 
1701*2c23cb7cSEd Maste 	switch (rw) {
1702*2c23cb7cSEd Maste 	case 0: return "Absolute";
1703*2c23cb7cSEd Maste 	case 1: return "PC-relative";
1704*2c23cb7cSEd Maste 	case 2: return "SB-relative";
1705*2c23cb7cSEd Maste 	case 3: return "None";
1706*2c23cb7cSEd Maste 	default:
1707*2c23cb7cSEd Maste 		snprintf(s_rw, sizeof(s_rw), "Unknown (%ju)", (uintmax_t) rw);
1708*2c23cb7cSEd Maste 		return (s_rw);
1709*2c23cb7cSEd Maste 	}
1710*2c23cb7cSEd Maste }
1711*2c23cb7cSEd Maste 
1712*2c23cb7cSEd Maste static const char *
1713*2c23cb7cSEd Maste aeabi_pcs_ro(uint64_t ro)
1714*2c23cb7cSEd Maste {
1715*2c23cb7cSEd Maste 	static char s_ro[32];
1716*2c23cb7cSEd Maste 
1717*2c23cb7cSEd Maste 	switch (ro) {
1718*2c23cb7cSEd Maste 	case 0: return "Absolute";
1719*2c23cb7cSEd Maste 	case 1: return "PC-relative";
1720*2c23cb7cSEd Maste 	case 2: return "None";
1721*2c23cb7cSEd Maste 	default:
1722*2c23cb7cSEd Maste 		snprintf(s_ro, sizeof(s_ro), "Unknown (%ju)", (uintmax_t) ro);
1723*2c23cb7cSEd Maste 		return (s_ro);
1724*2c23cb7cSEd Maste 	}
1725*2c23cb7cSEd Maste }
1726*2c23cb7cSEd Maste 
1727*2c23cb7cSEd Maste static const char *
1728*2c23cb7cSEd Maste aeabi_pcs_got(uint64_t got)
1729*2c23cb7cSEd Maste {
1730*2c23cb7cSEd Maste 	static char s_got[32];
1731*2c23cb7cSEd Maste 
1732*2c23cb7cSEd Maste 	switch (got) {
1733*2c23cb7cSEd Maste 	case 0: return "None";
1734*2c23cb7cSEd Maste 	case 1: return "direct";
1735*2c23cb7cSEd Maste 	case 2: return "indirect via GOT";
1736*2c23cb7cSEd Maste 	default:
1737*2c23cb7cSEd Maste 		snprintf(s_got, sizeof(s_got), "Unknown (%ju)",
1738*2c23cb7cSEd Maste 		    (uintmax_t) got);
1739*2c23cb7cSEd Maste 		return (s_got);
1740*2c23cb7cSEd Maste 	}
1741*2c23cb7cSEd Maste }
1742*2c23cb7cSEd Maste 
1743*2c23cb7cSEd Maste static const char *
1744*2c23cb7cSEd Maste aeabi_pcs_wchar_t(uint64_t wt)
1745*2c23cb7cSEd Maste {
1746*2c23cb7cSEd Maste 	static char s_wt[32];
1747*2c23cb7cSEd Maste 
1748*2c23cb7cSEd Maste 	switch (wt) {
1749*2c23cb7cSEd Maste 	case 0: return "None";
1750*2c23cb7cSEd Maste 	case 2: return "wchar_t size 2";
1751*2c23cb7cSEd Maste 	case 4: return "wchar_t size 4";
1752*2c23cb7cSEd Maste 	default:
1753*2c23cb7cSEd Maste 		snprintf(s_wt, sizeof(s_wt), "Unknown (%ju)", (uintmax_t) wt);
1754*2c23cb7cSEd Maste 		return (s_wt);
1755*2c23cb7cSEd Maste 	}
1756*2c23cb7cSEd Maste }
1757*2c23cb7cSEd Maste 
1758*2c23cb7cSEd Maste static const char *
1759*2c23cb7cSEd Maste aeabi_enum_size(uint64_t es)
1760*2c23cb7cSEd Maste {
1761*2c23cb7cSEd Maste 	static char s_es[32];
1762*2c23cb7cSEd Maste 
1763*2c23cb7cSEd Maste 	switch (es) {
1764*2c23cb7cSEd Maste 	case 0: return "None";
1765*2c23cb7cSEd Maste 	case 1: return "smallest";
1766*2c23cb7cSEd Maste 	case 2: return "32-bit";
1767*2c23cb7cSEd Maste 	case 3: return "visible 32-bit";
1768*2c23cb7cSEd Maste 	default:
1769*2c23cb7cSEd Maste 		snprintf(s_es, sizeof(s_es), "Unknown (%ju)", (uintmax_t) es);
1770*2c23cb7cSEd Maste 		return (s_es);
1771*2c23cb7cSEd Maste 	}
1772*2c23cb7cSEd Maste }
1773*2c23cb7cSEd Maste 
1774*2c23cb7cSEd Maste static const char *
1775*2c23cb7cSEd Maste aeabi_align_needed(uint64_t an)
1776*2c23cb7cSEd Maste {
1777*2c23cb7cSEd Maste 	static char s_align_n[64];
1778*2c23cb7cSEd Maste 
1779*2c23cb7cSEd Maste 	switch (an) {
1780*2c23cb7cSEd Maste 	case 0: return "No";
1781*2c23cb7cSEd Maste 	case 1: return "8-byte align";
1782*2c23cb7cSEd Maste 	case 2: return "4-byte align";
1783*2c23cb7cSEd Maste 	case 3: return "Reserved";
1784*2c23cb7cSEd Maste 	default:
1785*2c23cb7cSEd Maste 		if (an >= 4 && an <= 12)
1786*2c23cb7cSEd Maste 			snprintf(s_align_n, sizeof(s_align_n), "8-byte align"
1787*2c23cb7cSEd Maste 			    " and up to 2^%ju-byte extended align",
1788*2c23cb7cSEd Maste 			    (uintmax_t) an);
1789*2c23cb7cSEd Maste 		else
1790*2c23cb7cSEd Maste 			snprintf(s_align_n, sizeof(s_align_n), "Unknown (%ju)",
1791*2c23cb7cSEd Maste 			    (uintmax_t) an);
1792*2c23cb7cSEd Maste 		return (s_align_n);
1793*2c23cb7cSEd Maste 	}
1794*2c23cb7cSEd Maste }
1795*2c23cb7cSEd Maste 
1796*2c23cb7cSEd Maste static const char *
1797*2c23cb7cSEd Maste aeabi_align_preserved(uint64_t ap)
1798*2c23cb7cSEd Maste {
1799*2c23cb7cSEd Maste 	static char s_align_p[128];
1800*2c23cb7cSEd Maste 
1801*2c23cb7cSEd Maste 	switch (ap) {
1802*2c23cb7cSEd Maste 	case 0: return "No";
1803*2c23cb7cSEd Maste 	case 1: return "8-byte align";
1804*2c23cb7cSEd Maste 	case 2: return "8-byte align and SP % 8 == 0";
1805*2c23cb7cSEd Maste 	case 3: return "Reserved";
1806*2c23cb7cSEd Maste 	default:
1807*2c23cb7cSEd Maste 		if (ap >= 4 && ap <= 12)
1808*2c23cb7cSEd Maste 			snprintf(s_align_p, sizeof(s_align_p), "8-byte align"
1809*2c23cb7cSEd Maste 			    " and SP %% 8 == 0 and up to 2^%ju-byte extended"
1810*2c23cb7cSEd Maste 			    " align", (uintmax_t) ap);
1811*2c23cb7cSEd Maste 		else
1812*2c23cb7cSEd Maste 			snprintf(s_align_p, sizeof(s_align_p), "Unknown (%ju)",
1813*2c23cb7cSEd Maste 			    (uintmax_t) ap);
1814*2c23cb7cSEd Maste 		return (s_align_p);
1815*2c23cb7cSEd Maste 	}
1816*2c23cb7cSEd Maste }
1817*2c23cb7cSEd Maste 
1818*2c23cb7cSEd Maste static const char *
1819*2c23cb7cSEd Maste aeabi_fp_rounding(uint64_t fr)
1820*2c23cb7cSEd Maste {
1821*2c23cb7cSEd Maste 	static char s_fp_r[32];
1822*2c23cb7cSEd Maste 
1823*2c23cb7cSEd Maste 	switch (fr) {
1824*2c23cb7cSEd Maste 	case 0: return "Unused";
1825*2c23cb7cSEd Maste 	case 1: return "Needed";
1826*2c23cb7cSEd Maste 	default:
1827*2c23cb7cSEd Maste 		snprintf(s_fp_r, sizeof(s_fp_r), "Unknown (%ju)",
1828*2c23cb7cSEd Maste 		    (uintmax_t) fr);
1829*2c23cb7cSEd Maste 		return (s_fp_r);
1830*2c23cb7cSEd Maste 	}
1831*2c23cb7cSEd Maste }
1832*2c23cb7cSEd Maste 
1833*2c23cb7cSEd Maste static const char *
1834*2c23cb7cSEd Maste aeabi_fp_denormal(uint64_t fd)
1835*2c23cb7cSEd Maste {
1836*2c23cb7cSEd Maste 	static char s_fp_d[32];
1837*2c23cb7cSEd Maste 
1838*2c23cb7cSEd Maste 	switch (fd) {
1839*2c23cb7cSEd Maste 	case 0: return "Unused";
1840*2c23cb7cSEd Maste 	case 1: return "Needed";
1841*2c23cb7cSEd Maste 	case 2: return "Sign Only";
1842*2c23cb7cSEd Maste 	default:
1843*2c23cb7cSEd Maste 		snprintf(s_fp_d, sizeof(s_fp_d), "Unknown (%ju)",
1844*2c23cb7cSEd Maste 		    (uintmax_t) fd);
1845*2c23cb7cSEd Maste 		return (s_fp_d);
1846*2c23cb7cSEd Maste 	}
1847*2c23cb7cSEd Maste }
1848*2c23cb7cSEd Maste 
1849*2c23cb7cSEd Maste static const char *
1850*2c23cb7cSEd Maste aeabi_fp_exceptions(uint64_t fe)
1851*2c23cb7cSEd Maste {
1852*2c23cb7cSEd Maste 	static char s_fp_e[32];
1853*2c23cb7cSEd Maste 
1854*2c23cb7cSEd Maste 	switch (fe) {
1855*2c23cb7cSEd Maste 	case 0: return "Unused";
1856*2c23cb7cSEd Maste 	case 1: return "Needed";
1857*2c23cb7cSEd Maste 	default:
1858*2c23cb7cSEd Maste 		snprintf(s_fp_e, sizeof(s_fp_e), "Unknown (%ju)",
1859*2c23cb7cSEd Maste 		    (uintmax_t) fe);
1860*2c23cb7cSEd Maste 		return (s_fp_e);
1861*2c23cb7cSEd Maste 	}
1862*2c23cb7cSEd Maste }
1863*2c23cb7cSEd Maste 
1864*2c23cb7cSEd Maste static const char *
1865*2c23cb7cSEd Maste aeabi_fp_user_exceptions(uint64_t fu)
1866*2c23cb7cSEd Maste {
1867*2c23cb7cSEd Maste 	static char s_fp_u[32];
1868*2c23cb7cSEd Maste 
1869*2c23cb7cSEd Maste 	switch (fu) {
1870*2c23cb7cSEd Maste 	case 0: return "Unused";
1871*2c23cb7cSEd Maste 	case 1: return "Needed";
1872*2c23cb7cSEd Maste 	default:
1873*2c23cb7cSEd Maste 		snprintf(s_fp_u, sizeof(s_fp_u), "Unknown (%ju)",
1874*2c23cb7cSEd Maste 		    (uintmax_t) fu);
1875*2c23cb7cSEd Maste 		return (s_fp_u);
1876*2c23cb7cSEd Maste 	}
1877*2c23cb7cSEd Maste }
1878*2c23cb7cSEd Maste 
1879*2c23cb7cSEd Maste static const char *
1880*2c23cb7cSEd Maste aeabi_fp_number_model(uint64_t fn)
1881*2c23cb7cSEd Maste {
1882*2c23cb7cSEd Maste 	static char s_fp_n[32];
1883*2c23cb7cSEd Maste 
1884*2c23cb7cSEd Maste 	switch (fn) {
1885*2c23cb7cSEd Maste 	case 0: return "Unused";
1886*2c23cb7cSEd Maste 	case 1: return "IEEE 754 normal";
1887*2c23cb7cSEd Maste 	case 2: return "RTABI";
1888*2c23cb7cSEd Maste 	case 3: return "IEEE 754";
1889*2c23cb7cSEd Maste 	default:
1890*2c23cb7cSEd Maste 		snprintf(s_fp_n, sizeof(s_fp_n), "Unknown (%ju)",
1891*2c23cb7cSEd Maste 		    (uintmax_t) fn);
1892*2c23cb7cSEd Maste 		return (s_fp_n);
1893*2c23cb7cSEd Maste 	}
1894*2c23cb7cSEd Maste }
1895*2c23cb7cSEd Maste 
1896*2c23cb7cSEd Maste static const char *
1897*2c23cb7cSEd Maste aeabi_fp_16bit_format(uint64_t fp16)
1898*2c23cb7cSEd Maste {
1899*2c23cb7cSEd Maste 	static char s_fp_16[64];
1900*2c23cb7cSEd Maste 
1901*2c23cb7cSEd Maste 	switch (fp16) {
1902*2c23cb7cSEd Maste 	case 0: return "None";
1903*2c23cb7cSEd Maste 	case 1: return "IEEE 754";
1904*2c23cb7cSEd Maste 	case 2: return "VFPv3/Advanced SIMD (alternative format)";
1905*2c23cb7cSEd Maste 	default:
1906*2c23cb7cSEd Maste 		snprintf(s_fp_16, sizeof(s_fp_16), "Unknown (%ju)",
1907*2c23cb7cSEd Maste 		    (uintmax_t) fp16);
1908*2c23cb7cSEd Maste 		return (s_fp_16);
1909*2c23cb7cSEd Maste 	}
1910*2c23cb7cSEd Maste }
1911*2c23cb7cSEd Maste 
1912*2c23cb7cSEd Maste static const char *
1913*2c23cb7cSEd Maste aeabi_mpext(uint64_t mp)
1914*2c23cb7cSEd Maste {
1915*2c23cb7cSEd Maste 	static char s_mp[32];
1916*2c23cb7cSEd Maste 
1917*2c23cb7cSEd Maste 	switch (mp) {
1918*2c23cb7cSEd Maste 	case 0: return "Not allowed";
1919*2c23cb7cSEd Maste 	case 1: return "Allowed";
1920*2c23cb7cSEd Maste 	default:
1921*2c23cb7cSEd Maste 		snprintf(s_mp, sizeof(s_mp), "Unknown (%ju)",
1922*2c23cb7cSEd Maste 		    (uintmax_t) mp);
1923*2c23cb7cSEd Maste 		return (s_mp);
1924*2c23cb7cSEd Maste 	}
1925*2c23cb7cSEd Maste }
1926*2c23cb7cSEd Maste 
1927*2c23cb7cSEd Maste static const char *
1928*2c23cb7cSEd Maste aeabi_div(uint64_t du)
1929*2c23cb7cSEd Maste {
1930*2c23cb7cSEd Maste 	static char s_du[32];
1931*2c23cb7cSEd Maste 
1932*2c23cb7cSEd Maste 	switch (du) {
1933*2c23cb7cSEd Maste 	case 0: return "Yes (V7-R/V7-M)";
1934*2c23cb7cSEd Maste 	case 1: return "No";
1935*2c23cb7cSEd Maste 	case 2: return "Yes (V7-A)";
1936*2c23cb7cSEd Maste 	default:
1937*2c23cb7cSEd Maste 		snprintf(s_du, sizeof(s_du), "Unknown (%ju)",
1938*2c23cb7cSEd Maste 		    (uintmax_t) du);
1939*2c23cb7cSEd Maste 		return (s_du);
1940*2c23cb7cSEd Maste 	}
1941*2c23cb7cSEd Maste }
1942*2c23cb7cSEd Maste 
1943*2c23cb7cSEd Maste static const char *
1944*2c23cb7cSEd Maste aeabi_t2ee(uint64_t t2ee)
1945*2c23cb7cSEd Maste {
1946*2c23cb7cSEd Maste 	static char s_t2ee[32];
1947*2c23cb7cSEd Maste 
1948*2c23cb7cSEd Maste 	switch (t2ee) {
1949*2c23cb7cSEd Maste 	case 0: return "Not allowed";
1950*2c23cb7cSEd Maste 	case 1: return "Allowed";
1951*2c23cb7cSEd Maste 	default:
1952*2c23cb7cSEd Maste 		snprintf(s_t2ee, sizeof(s_t2ee), "Unknown(%ju)",
1953*2c23cb7cSEd Maste 		    (uintmax_t) t2ee);
1954*2c23cb7cSEd Maste 		return (s_t2ee);
1955*2c23cb7cSEd Maste 	}
1956*2c23cb7cSEd Maste 
1957*2c23cb7cSEd Maste }
1958*2c23cb7cSEd Maste 
1959*2c23cb7cSEd Maste static const char *
1960*2c23cb7cSEd Maste aeabi_hardfp(uint64_t hfp)
1961*2c23cb7cSEd Maste {
1962*2c23cb7cSEd Maste 	static char s_hfp[32];
1963*2c23cb7cSEd Maste 
1964*2c23cb7cSEd Maste 	switch (hfp) {
1965*2c23cb7cSEd Maste 	case 0: return "Tag_FP_arch";
1966*2c23cb7cSEd Maste 	case 1: return "only SP";
1967*2c23cb7cSEd Maste 	case 2: return "only DP";
1968*2c23cb7cSEd Maste 	case 3: return "both SP and DP";
1969*2c23cb7cSEd Maste 	default:
1970*2c23cb7cSEd Maste 		snprintf(s_hfp, sizeof(s_hfp), "Unknown (%ju)",
1971*2c23cb7cSEd Maste 		    (uintmax_t) hfp);
1972*2c23cb7cSEd Maste 		return (s_hfp);
1973*2c23cb7cSEd Maste 	}
1974*2c23cb7cSEd Maste }
1975*2c23cb7cSEd Maste 
1976*2c23cb7cSEd Maste static const char *
1977*2c23cb7cSEd Maste aeabi_vfp_args(uint64_t va)
1978*2c23cb7cSEd Maste {
1979*2c23cb7cSEd Maste 	static char s_va[32];
1980*2c23cb7cSEd Maste 
1981*2c23cb7cSEd Maste 	switch (va) {
1982*2c23cb7cSEd Maste 	case 0: return "AAPCS (base variant)";
1983*2c23cb7cSEd Maste 	case 1: return "AAPCS (VFP variant)";
1984*2c23cb7cSEd Maste 	case 2: return "toolchain-specific";
1985*2c23cb7cSEd Maste 	default:
1986*2c23cb7cSEd Maste 		snprintf(s_va, sizeof(s_va), "Unknown (%ju)", (uintmax_t) va);
1987*2c23cb7cSEd Maste 		return (s_va);
1988*2c23cb7cSEd Maste 	}
1989*2c23cb7cSEd Maste }
1990*2c23cb7cSEd Maste 
1991*2c23cb7cSEd Maste static const char *
1992*2c23cb7cSEd Maste aeabi_wmmx_args(uint64_t wa)
1993*2c23cb7cSEd Maste {
1994*2c23cb7cSEd Maste 	static char s_wa[32];
1995*2c23cb7cSEd Maste 
1996*2c23cb7cSEd Maste 	switch (wa) {
1997*2c23cb7cSEd Maste 	case 0: return "AAPCS (base variant)";
1998*2c23cb7cSEd Maste 	case 1: return "Intel WMMX";
1999*2c23cb7cSEd Maste 	case 2: return "toolchain-specific";
2000*2c23cb7cSEd Maste 	default:
2001*2c23cb7cSEd Maste 		snprintf(s_wa, sizeof(s_wa), "Unknown(%ju)", (uintmax_t) wa);
2002*2c23cb7cSEd Maste 		return (s_wa);
2003*2c23cb7cSEd Maste 	}
2004*2c23cb7cSEd Maste }
2005*2c23cb7cSEd Maste 
2006*2c23cb7cSEd Maste static const char *
2007*2c23cb7cSEd Maste aeabi_unaligned_access(uint64_t ua)
2008*2c23cb7cSEd Maste {
2009*2c23cb7cSEd Maste 	static char s_ua[32];
2010*2c23cb7cSEd Maste 
2011*2c23cb7cSEd Maste 	switch (ua) {
2012*2c23cb7cSEd Maste 	case 0: return "Not allowed";
2013*2c23cb7cSEd Maste 	case 1: return "Allowed";
2014*2c23cb7cSEd Maste 	default:
2015*2c23cb7cSEd Maste 		snprintf(s_ua, sizeof(s_ua), "Unknown(%ju)", (uintmax_t) ua);
2016*2c23cb7cSEd Maste 		return (s_ua);
2017*2c23cb7cSEd Maste 	}
2018*2c23cb7cSEd Maste }
2019*2c23cb7cSEd Maste 
2020*2c23cb7cSEd Maste static const char *
2021*2c23cb7cSEd Maste aeabi_fp_hpext(uint64_t fh)
2022*2c23cb7cSEd Maste {
2023*2c23cb7cSEd Maste 	static char s_fh[32];
2024*2c23cb7cSEd Maste 
2025*2c23cb7cSEd Maste 	switch (fh) {
2026*2c23cb7cSEd Maste 	case 0: return "Not allowed";
2027*2c23cb7cSEd Maste 	case 1: return "Allowed";
2028*2c23cb7cSEd Maste 	default:
2029*2c23cb7cSEd Maste 		snprintf(s_fh, sizeof(s_fh), "Unknown(%ju)", (uintmax_t) fh);
2030*2c23cb7cSEd Maste 		return (s_fh);
2031*2c23cb7cSEd Maste 	}
2032*2c23cb7cSEd Maste }
2033*2c23cb7cSEd Maste 
2034*2c23cb7cSEd Maste static const char *
2035*2c23cb7cSEd Maste aeabi_optm_goal(uint64_t og)
2036*2c23cb7cSEd Maste {
2037*2c23cb7cSEd Maste 	static char s_og[32];
2038*2c23cb7cSEd Maste 
2039*2c23cb7cSEd Maste 	switch (og) {
2040*2c23cb7cSEd Maste 	case 0: return "None";
2041*2c23cb7cSEd Maste 	case 1: return "Speed";
2042*2c23cb7cSEd Maste 	case 2: return "Speed aggressive";
2043*2c23cb7cSEd Maste 	case 3: return "Space";
2044*2c23cb7cSEd Maste 	case 4: return "Space aggressive";
2045*2c23cb7cSEd Maste 	case 5: return "Debugging";
2046*2c23cb7cSEd Maste 	case 6: return "Best Debugging";
2047*2c23cb7cSEd Maste 	default:
2048*2c23cb7cSEd Maste 		snprintf(s_og, sizeof(s_og), "Unknown(%ju)", (uintmax_t) og);
2049*2c23cb7cSEd Maste 		return (s_og);
2050*2c23cb7cSEd Maste 	}
2051*2c23cb7cSEd Maste }
2052*2c23cb7cSEd Maste 
2053*2c23cb7cSEd Maste static const char *
2054*2c23cb7cSEd Maste aeabi_fp_optm_goal(uint64_t fog)
2055*2c23cb7cSEd Maste {
2056*2c23cb7cSEd Maste 	static char s_fog[32];
2057*2c23cb7cSEd Maste 
2058*2c23cb7cSEd Maste 	switch (fog) {
2059*2c23cb7cSEd Maste 	case 0: return "None";
2060*2c23cb7cSEd Maste 	case 1: return "Speed";
2061*2c23cb7cSEd Maste 	case 2: return "Speed aggressive";
2062*2c23cb7cSEd Maste 	case 3: return "Space";
2063*2c23cb7cSEd Maste 	case 4: return "Space aggressive";
2064*2c23cb7cSEd Maste 	case 5: return "Accurary";
2065*2c23cb7cSEd Maste 	case 6: return "Best Accurary";
2066*2c23cb7cSEd Maste 	default:
2067*2c23cb7cSEd Maste 		snprintf(s_fog, sizeof(s_fog), "Unknown(%ju)",
2068*2c23cb7cSEd Maste 		    (uintmax_t) fog);
2069*2c23cb7cSEd Maste 		return (s_fog);
2070*2c23cb7cSEd Maste 	}
2071*2c23cb7cSEd Maste }
2072*2c23cb7cSEd Maste 
2073*2c23cb7cSEd Maste static const char *
2074*2c23cb7cSEd Maste aeabi_virtual(uint64_t vt)
2075*2c23cb7cSEd Maste {
2076*2c23cb7cSEd Maste 	static char s_virtual[64];
2077*2c23cb7cSEd Maste 
2078*2c23cb7cSEd Maste 	switch (vt) {
2079*2c23cb7cSEd Maste 	case 0: return "No";
2080*2c23cb7cSEd Maste 	case 1: return "TrustZone";
2081*2c23cb7cSEd Maste 	case 2: return "Virtualization extension";
2082*2c23cb7cSEd Maste 	case 3: return "TrustZone and virtualization extension";
2083*2c23cb7cSEd Maste 	default:
2084*2c23cb7cSEd Maste 		snprintf(s_virtual, sizeof(s_virtual), "Unknown(%ju)",
2085*2c23cb7cSEd Maste 		    (uintmax_t) vt);
2086*2c23cb7cSEd Maste 		return (s_virtual);
2087*2c23cb7cSEd Maste 	}
2088*2c23cb7cSEd Maste }
2089*2c23cb7cSEd Maste 
2090*2c23cb7cSEd Maste static struct {
2091*2c23cb7cSEd Maste 	uint64_t tag;
2092*2c23cb7cSEd Maste 	const char *s_tag;
2093*2c23cb7cSEd Maste 	const char *(*get_desc)(uint64_t val);
2094*2c23cb7cSEd Maste } aeabi_tags[] = {
2095*2c23cb7cSEd Maste 	{4, "Tag_CPU_raw_name", NULL},
2096*2c23cb7cSEd Maste 	{5, "Tag_CPU_name", NULL},
2097*2c23cb7cSEd Maste 	{6, "Tag_CPU_arch", aeabi_cpu_arch},
2098*2c23cb7cSEd Maste 	{7, "Tag_CPU_arch_profile", aeabi_cpu_arch_profile},
2099*2c23cb7cSEd Maste 	{8, "Tag_ARM_ISA_use", aeabi_arm_isa},
2100*2c23cb7cSEd Maste 	{9, "Tag_THUMB_ISA_use", aeabi_thumb_isa},
2101*2c23cb7cSEd Maste 	{10, "Tag_FP_arch", aeabi_fp_arch},
2102*2c23cb7cSEd Maste 	{11, "Tag_WMMX_arch", aeabi_wmmx_arch},
2103*2c23cb7cSEd Maste 	{12, "Tag_Advanced_SIMD_arch", aeabi_adv_simd_arch},
2104*2c23cb7cSEd Maste 	{13, "Tag_PCS_config", aeabi_pcs_config},
2105*2c23cb7cSEd Maste 	{14, "Tag_ABI_PCS_R9_use", aeabi_pcs_r9},
2106*2c23cb7cSEd Maste 	{15, "Tag_ABI_PCS_RW_data", aeabi_pcs_rw},
2107*2c23cb7cSEd Maste 	{16, "Tag_ABI_PCS_RO_data", aeabi_pcs_ro},
2108*2c23cb7cSEd Maste 	{17, "Tag_ABI_PCS_GOT_use", aeabi_pcs_got},
2109*2c23cb7cSEd Maste 	{18, "Tag_ABI_PCS_wchar_t", aeabi_pcs_wchar_t},
2110*2c23cb7cSEd Maste 	{19, "Tag_ABI_FP_rounding", aeabi_fp_rounding},
2111*2c23cb7cSEd Maste 	{20, "Tag_ABI_FP_denormal", aeabi_fp_denormal},
2112*2c23cb7cSEd Maste 	{21, "Tag_ABI_FP_exceptions", aeabi_fp_exceptions},
2113*2c23cb7cSEd Maste 	{22, "Tag_ABI_FP_user_exceptions", aeabi_fp_user_exceptions},
2114*2c23cb7cSEd Maste 	{23, "Tag_ABI_FP_number_model", aeabi_fp_number_model},
2115*2c23cb7cSEd Maste 	{24, "Tag_ABI_align_needed", aeabi_align_needed},
2116*2c23cb7cSEd Maste 	{25, "Tag_ABI_align_preserved", aeabi_align_preserved},
2117*2c23cb7cSEd Maste 	{26, "Tag_ABI_enum_size", aeabi_enum_size},
2118*2c23cb7cSEd Maste 	{27, "Tag_ABI_HardFP_use", aeabi_hardfp},
2119*2c23cb7cSEd Maste 	{28, "Tag_ABI_VFP_args", aeabi_vfp_args},
2120*2c23cb7cSEd Maste 	{29, "Tag_ABI_WMMX_args", aeabi_wmmx_args},
2121*2c23cb7cSEd Maste 	{30, "Tag_ABI_optimization_goals", aeabi_optm_goal},
2122*2c23cb7cSEd Maste 	{31, "Tag_ABI_FP_optimization_goals", aeabi_fp_optm_goal},
2123*2c23cb7cSEd Maste 	{32, "Tag_compatibility", NULL},
2124*2c23cb7cSEd Maste 	{34, "Tag_CPU_unaligned_access", aeabi_unaligned_access},
2125*2c23cb7cSEd Maste 	{36, "Tag_FP_HP_extension", aeabi_fp_hpext},
2126*2c23cb7cSEd Maste 	{38, "Tag_ABI_FP_16bit_format", aeabi_fp_16bit_format},
2127*2c23cb7cSEd Maste 	{42, "Tag_MPextension_use", aeabi_mpext},
2128*2c23cb7cSEd Maste 	{44, "Tag_DIV_use", aeabi_div},
2129*2c23cb7cSEd Maste 	{64, "Tag_nodefaults", NULL},
2130*2c23cb7cSEd Maste 	{65, "Tag_also_compatible_with", NULL},
2131*2c23cb7cSEd Maste 	{66, "Tag_T2EE_use", aeabi_t2ee},
2132*2c23cb7cSEd Maste 	{67, "Tag_conformance", NULL},
2133*2c23cb7cSEd Maste 	{68, "Tag_Virtualization_use", aeabi_virtual},
2134*2c23cb7cSEd Maste 	{70, "Tag_MPextension_use", aeabi_mpext},
2135*2c23cb7cSEd Maste };
2136*2c23cb7cSEd Maste 
2137*2c23cb7cSEd Maste static const char *
2138*2c23cb7cSEd Maste mips_abi_fp(uint64_t fp)
2139*2c23cb7cSEd Maste {
2140*2c23cb7cSEd Maste 	static char s_mips_abi_fp[64];
2141*2c23cb7cSEd Maste 
2142*2c23cb7cSEd Maste 	switch (fp) {
2143*2c23cb7cSEd Maste 	case 0: return "N/A";
2144*2c23cb7cSEd Maste 	case 1: return "Hard float (double precision)";
2145*2c23cb7cSEd Maste 	case 2: return "Hard float (single precision)";
2146*2c23cb7cSEd Maste 	case 3: return "Soft float";
2147*2c23cb7cSEd Maste 	case 4: return "64-bit float (-mips32r2 -mfp64)";
2148*2c23cb7cSEd Maste 	default:
2149*2c23cb7cSEd Maste 		snprintf(s_mips_abi_fp, sizeof(s_mips_abi_fp), "Unknown(%ju)",
2150*2c23cb7cSEd Maste 		    (uintmax_t) fp);
2151*2c23cb7cSEd Maste 		return (s_mips_abi_fp);
2152*2c23cb7cSEd Maste 	}
2153*2c23cb7cSEd Maste }
2154*2c23cb7cSEd Maste 
2155*2c23cb7cSEd Maste static const char *
2156*2c23cb7cSEd Maste ppc_abi_fp(uint64_t fp)
2157*2c23cb7cSEd Maste {
2158*2c23cb7cSEd Maste 	static char s_ppc_abi_fp[64];
2159*2c23cb7cSEd Maste 
2160*2c23cb7cSEd Maste 	switch (fp) {
2161*2c23cb7cSEd Maste 	case 0: return "N/A";
2162*2c23cb7cSEd Maste 	case 1: return "Hard float (double precision)";
2163*2c23cb7cSEd Maste 	case 2: return "Soft float";
2164*2c23cb7cSEd Maste 	case 3: return "Hard float (single precision)";
2165*2c23cb7cSEd Maste 	default:
2166*2c23cb7cSEd Maste 		snprintf(s_ppc_abi_fp, sizeof(s_ppc_abi_fp), "Unknown(%ju)",
2167*2c23cb7cSEd Maste 		    (uintmax_t) fp);
2168*2c23cb7cSEd Maste 		return (s_ppc_abi_fp);
2169*2c23cb7cSEd Maste 	}
2170*2c23cb7cSEd Maste }
2171*2c23cb7cSEd Maste 
2172*2c23cb7cSEd Maste static const char *
2173*2c23cb7cSEd Maste ppc_abi_vector(uint64_t vec)
2174*2c23cb7cSEd Maste {
2175*2c23cb7cSEd Maste 	static char s_vec[64];
2176*2c23cb7cSEd Maste 
2177*2c23cb7cSEd Maste 	switch (vec) {
2178*2c23cb7cSEd Maste 	case 0: return "N/A";
2179*2c23cb7cSEd Maste 	case 1: return "Generic purpose registers";
2180*2c23cb7cSEd Maste 	case 2: return "AltiVec registers";
2181*2c23cb7cSEd Maste 	case 3: return "SPE registers";
2182*2c23cb7cSEd Maste 	default:
2183*2c23cb7cSEd Maste 		snprintf(s_vec, sizeof(s_vec), "Unknown(%ju)", (uintmax_t) vec);
2184*2c23cb7cSEd Maste 		return (s_vec);
2185*2c23cb7cSEd Maste 	}
2186*2c23cb7cSEd Maste }
2187*2c23cb7cSEd Maste 
2188*2c23cb7cSEd Maste static void
2189*2c23cb7cSEd Maste dump_ehdr(struct readelf *re)
2190*2c23cb7cSEd Maste {
2191*2c23cb7cSEd Maste 	size_t		 shnum, shstrndx;
2192*2c23cb7cSEd Maste 	int		 i;
2193*2c23cb7cSEd Maste 
2194*2c23cb7cSEd Maste 	printf("ELF Header:\n");
2195*2c23cb7cSEd Maste 
2196*2c23cb7cSEd Maste 	/* e_ident[]. */
2197*2c23cb7cSEd Maste 	printf("  Magic:   ");
2198*2c23cb7cSEd Maste 	for (i = 0; i < EI_NIDENT; i++)
2199*2c23cb7cSEd Maste 		printf("%.2x ", re->ehdr.e_ident[i]);
2200*2c23cb7cSEd Maste 	putchar('\n');
2201*2c23cb7cSEd Maste 
2202*2c23cb7cSEd Maste 	/* EI_CLASS. */
2203*2c23cb7cSEd Maste 	printf("%-37s%s\n", "  Class:", elf_class(re->ehdr.e_ident[EI_CLASS]));
2204*2c23cb7cSEd Maste 
2205*2c23cb7cSEd Maste 	/* EI_DATA. */
2206*2c23cb7cSEd Maste 	printf("%-37s%s\n", "  Data:", elf_endian(re->ehdr.e_ident[EI_DATA]));
2207*2c23cb7cSEd Maste 
2208*2c23cb7cSEd Maste 	/* EI_VERSION. */
2209*2c23cb7cSEd Maste 	printf("%-37s%d %s\n", "  Version:", re->ehdr.e_ident[EI_VERSION],
2210*2c23cb7cSEd Maste 	    elf_ver(re->ehdr.e_ident[EI_VERSION]));
2211*2c23cb7cSEd Maste 
2212*2c23cb7cSEd Maste 	/* EI_OSABI. */
2213*2c23cb7cSEd Maste 	printf("%-37s%s\n", "  OS/ABI:", elf_osabi(re->ehdr.e_ident[EI_OSABI]));
2214*2c23cb7cSEd Maste 
2215*2c23cb7cSEd Maste 	/* EI_ABIVERSION. */
2216*2c23cb7cSEd Maste 	printf("%-37s%d\n", "  ABI Version:", re->ehdr.e_ident[EI_ABIVERSION]);
2217*2c23cb7cSEd Maste 
2218*2c23cb7cSEd Maste 	/* e_type. */
2219*2c23cb7cSEd Maste 	printf("%-37s%s\n", "  Type:", elf_type(re->ehdr.e_type));
2220*2c23cb7cSEd Maste 
2221*2c23cb7cSEd Maste 	/* e_machine. */
2222*2c23cb7cSEd Maste 	printf("%-37s%s\n", "  Machine:", elf_machine(re->ehdr.e_machine));
2223*2c23cb7cSEd Maste 
2224*2c23cb7cSEd Maste 	/* e_version. */
2225*2c23cb7cSEd Maste 	printf("%-37s%#x\n", "  Version:", re->ehdr.e_version);
2226*2c23cb7cSEd Maste 
2227*2c23cb7cSEd Maste 	/* e_entry. */
2228*2c23cb7cSEd Maste 	printf("%-37s%#jx\n", "  Entry point address:",
2229*2c23cb7cSEd Maste 	    (uintmax_t)re->ehdr.e_entry);
2230*2c23cb7cSEd Maste 
2231*2c23cb7cSEd Maste 	/* e_phoff. */
2232*2c23cb7cSEd Maste 	printf("%-37s%ju (bytes into file)\n", "  Start of program headers:",
2233*2c23cb7cSEd Maste 	    (uintmax_t)re->ehdr.e_phoff);
2234*2c23cb7cSEd Maste 
2235*2c23cb7cSEd Maste 	/* e_shoff. */
2236*2c23cb7cSEd Maste 	printf("%-37s%ju (bytes into file)\n", "  Start of section headers:",
2237*2c23cb7cSEd Maste 	    (uintmax_t)re->ehdr.e_shoff);
2238*2c23cb7cSEd Maste 
2239*2c23cb7cSEd Maste 	/* e_flags. */
2240*2c23cb7cSEd Maste 	printf("%-37s%#x", "  Flags:", re->ehdr.e_flags);
2241*2c23cb7cSEd Maste 	dump_eflags(re, re->ehdr.e_flags);
2242*2c23cb7cSEd Maste 	putchar('\n');
2243*2c23cb7cSEd Maste 
2244*2c23cb7cSEd Maste 	/* e_ehsize. */
2245*2c23cb7cSEd Maste 	printf("%-37s%u (bytes)\n", "  Size of this header:",
2246*2c23cb7cSEd Maste 	    re->ehdr.e_ehsize);
2247*2c23cb7cSEd Maste 
2248*2c23cb7cSEd Maste 	/* e_phentsize. */
2249*2c23cb7cSEd Maste 	printf("%-37s%u (bytes)\n", "  Size of program headers:",
2250*2c23cb7cSEd Maste 	    re->ehdr.e_phentsize);
2251*2c23cb7cSEd Maste 
2252*2c23cb7cSEd Maste 	/* e_phnum. */
2253*2c23cb7cSEd Maste 	printf("%-37s%u\n", "  Number of program headers:", re->ehdr.e_phnum);
2254*2c23cb7cSEd Maste 
2255*2c23cb7cSEd Maste 	/* e_shentsize. */
2256*2c23cb7cSEd Maste 	printf("%-37s%u (bytes)\n", "  Size of section headers:",
2257*2c23cb7cSEd Maste 	    re->ehdr.e_shentsize);
2258*2c23cb7cSEd Maste 
2259*2c23cb7cSEd Maste 	/* e_shnum. */
2260*2c23cb7cSEd Maste 	printf("%-37s%u", "  Number of section headers:", re->ehdr.e_shnum);
2261*2c23cb7cSEd Maste 	if (re->ehdr.e_shnum == SHN_UNDEF) {
2262*2c23cb7cSEd Maste 		/* Extended section numbering is in use. */
2263*2c23cb7cSEd Maste 		if (elf_getshnum(re->elf, &shnum))
2264*2c23cb7cSEd Maste 			printf(" (%ju)", (uintmax_t)shnum);
2265*2c23cb7cSEd Maste 	}
2266*2c23cb7cSEd Maste 	putchar('\n');
2267*2c23cb7cSEd Maste 
2268*2c23cb7cSEd Maste 	/* e_shstrndx. */
2269*2c23cb7cSEd Maste 	printf("%-37s%u", "  Section header string table index:",
2270*2c23cb7cSEd Maste 	    re->ehdr.e_shstrndx);
2271*2c23cb7cSEd Maste 	if (re->ehdr.e_shstrndx == SHN_XINDEX) {
2272*2c23cb7cSEd Maste 		/* Extended section numbering is in use. */
2273*2c23cb7cSEd Maste 		if (elf_getshstrndx(re->elf, &shstrndx))
2274*2c23cb7cSEd Maste 			printf(" (%ju)", (uintmax_t)shstrndx);
2275*2c23cb7cSEd Maste 	}
2276*2c23cb7cSEd Maste 	putchar('\n');
2277*2c23cb7cSEd Maste }
2278*2c23cb7cSEd Maste 
2279*2c23cb7cSEd Maste static void
2280*2c23cb7cSEd Maste dump_eflags(struct readelf *re, uint64_t e_flags)
2281*2c23cb7cSEd Maste {
2282*2c23cb7cSEd Maste 	struct eflags_desc *edesc;
2283*2c23cb7cSEd Maste 	int arm_eabi;
2284*2c23cb7cSEd Maste 
2285*2c23cb7cSEd Maste 	edesc = NULL;
2286*2c23cb7cSEd Maste 	switch (re->ehdr.e_machine) {
2287*2c23cb7cSEd Maste 	case EM_ARM:
2288*2c23cb7cSEd Maste 		arm_eabi = (e_flags & EF_ARM_EABIMASK) >> 24;
2289*2c23cb7cSEd Maste 		if (arm_eabi == 0)
2290*2c23cb7cSEd Maste 			printf(", GNU EABI");
2291*2c23cb7cSEd Maste 		else if (arm_eabi <= 5)
2292*2c23cb7cSEd Maste 			printf(", Version%d EABI", arm_eabi);
2293*2c23cb7cSEd Maste 		edesc = arm_eflags_desc;
2294*2c23cb7cSEd Maste 		break;
2295*2c23cb7cSEd Maste 	case EM_MIPS:
2296*2c23cb7cSEd Maste 	case EM_MIPS_RS3_LE:
2297*2c23cb7cSEd Maste 		switch ((e_flags & EF_MIPS_ARCH) >> 28) {
2298*2c23cb7cSEd Maste 		case 0:	printf(", mips1"); break;
2299*2c23cb7cSEd Maste 		case 1: printf(", mips2"); break;
2300*2c23cb7cSEd Maste 		case 2: printf(", mips3"); break;
2301*2c23cb7cSEd Maste 		case 3: printf(", mips4"); break;
2302*2c23cb7cSEd Maste 		case 4: printf(", mips5"); break;
2303*2c23cb7cSEd Maste 		case 5: printf(", mips32"); break;
2304*2c23cb7cSEd Maste 		case 6: printf(", mips64"); break;
2305*2c23cb7cSEd Maste 		case 7: printf(", mips32r2"); break;
2306*2c23cb7cSEd Maste 		case 8: printf(", mips64r2"); break;
2307*2c23cb7cSEd Maste 		default: break;
2308*2c23cb7cSEd Maste 		}
2309*2c23cb7cSEd Maste 		switch ((e_flags & 0x00FF0000) >> 16) {
2310*2c23cb7cSEd Maste 		case 0x81: printf(", 3900"); break;
2311*2c23cb7cSEd Maste 		case 0x82: printf(", 4010"); break;
2312*2c23cb7cSEd Maste 		case 0x83: printf(", 4100"); break;
2313*2c23cb7cSEd Maste 		case 0x85: printf(", 4650"); break;
2314*2c23cb7cSEd Maste 		case 0x87: printf(", 4120"); break;
2315*2c23cb7cSEd Maste 		case 0x88: printf(", 4111"); break;
2316*2c23cb7cSEd Maste 		case 0x8a: printf(", sb1"); break;
2317*2c23cb7cSEd Maste 		case 0x8b: printf(", octeon"); break;
2318*2c23cb7cSEd Maste 		case 0x8c: printf(", xlr"); break;
2319*2c23cb7cSEd Maste 		case 0x91: printf(", 5400"); break;
2320*2c23cb7cSEd Maste 		case 0x98: printf(", 5500"); break;
2321*2c23cb7cSEd Maste 		case 0x99: printf(", 9000"); break;
2322*2c23cb7cSEd Maste 		case 0xa0: printf(", loongson-2e"); break;
2323*2c23cb7cSEd Maste 		case 0xa1: printf(", loongson-2f"); break;
2324*2c23cb7cSEd Maste 		default: break;
2325*2c23cb7cSEd Maste 		}
2326*2c23cb7cSEd Maste 		switch ((e_flags & 0x0000F000) >> 12) {
2327*2c23cb7cSEd Maste 		case 1: printf(", o32"); break;
2328*2c23cb7cSEd Maste 		case 2: printf(", o64"); break;
2329*2c23cb7cSEd Maste 		case 3: printf(", eabi32"); break;
2330*2c23cb7cSEd Maste 		case 4: printf(", eabi64"); break;
2331*2c23cb7cSEd Maste 		default: break;
2332*2c23cb7cSEd Maste 		}
2333*2c23cb7cSEd Maste 		edesc = mips_eflags_desc;
2334*2c23cb7cSEd Maste 		break;
2335*2c23cb7cSEd Maste 	case EM_PPC:
2336*2c23cb7cSEd Maste 	case EM_PPC64:
2337*2c23cb7cSEd Maste 		edesc = powerpc_eflags_desc;
2338*2c23cb7cSEd Maste 		break;
2339*2c23cb7cSEd Maste 	case EM_SPARC:
2340*2c23cb7cSEd Maste 	case EM_SPARC32PLUS:
2341*2c23cb7cSEd Maste 	case EM_SPARCV9:
2342*2c23cb7cSEd Maste 		switch ((e_flags & EF_SPARCV9_MM)) {
2343*2c23cb7cSEd Maste 		case EF_SPARCV9_TSO: printf(", tso"); break;
2344*2c23cb7cSEd Maste 		case EF_SPARCV9_PSO: printf(", pso"); break;
2345*2c23cb7cSEd Maste 		case EF_SPARCV9_MM: printf(", rmo"); break;
2346*2c23cb7cSEd Maste 		default: break;
2347*2c23cb7cSEd Maste 		}
2348*2c23cb7cSEd Maste 		edesc = sparc_eflags_desc;
2349*2c23cb7cSEd Maste 		break;
2350*2c23cb7cSEd Maste 	default:
2351*2c23cb7cSEd Maste 		break;
2352*2c23cb7cSEd Maste 	}
2353*2c23cb7cSEd Maste 
2354*2c23cb7cSEd Maste 	if (edesc != NULL) {
2355*2c23cb7cSEd Maste 		while (edesc->desc != NULL) {
2356*2c23cb7cSEd Maste 			if (e_flags & edesc->flag)
2357*2c23cb7cSEd Maste 				printf(", %s", edesc->desc);
2358*2c23cb7cSEd Maste 			edesc++;
2359*2c23cb7cSEd Maste 		}
2360*2c23cb7cSEd Maste 	}
2361*2c23cb7cSEd Maste }
2362*2c23cb7cSEd Maste 
2363*2c23cb7cSEd Maste static void
2364*2c23cb7cSEd Maste dump_phdr(struct readelf *re)
2365*2c23cb7cSEd Maste {
2366*2c23cb7cSEd Maste 	const char	*rawfile;
2367*2c23cb7cSEd Maste 	GElf_Phdr	 phdr;
2368*2c23cb7cSEd Maste 	size_t		 phnum;
2369*2c23cb7cSEd Maste 	int		 i, j;
2370*2c23cb7cSEd Maste 
2371*2c23cb7cSEd Maste #define	PH_HDR	"Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz",	\
2372*2c23cb7cSEd Maste 		"MemSiz", "Flg", "Align"
2373*2c23cb7cSEd Maste #define	PH_CT	phdr_type(phdr.p_type), (uintmax_t)phdr.p_offset,	\
2374*2c23cb7cSEd Maste 		(uintmax_t)phdr.p_vaddr, (uintmax_t)phdr.p_paddr,	\
2375*2c23cb7cSEd Maste 		(uintmax_t)phdr.p_filesz, (uintmax_t)phdr.p_memsz,	\
2376*2c23cb7cSEd Maste 		phdr.p_flags & PF_R ? 'R' : ' ',			\
2377*2c23cb7cSEd Maste 		phdr.p_flags & PF_W ? 'W' : ' ',			\
2378*2c23cb7cSEd Maste 		phdr.p_flags & PF_X ? 'E' : ' ',			\
2379*2c23cb7cSEd Maste 		(uintmax_t)phdr.p_align
2380*2c23cb7cSEd Maste 
2381*2c23cb7cSEd Maste 	if (elf_getphnum(re->elf, &phnum) == 0) {
2382*2c23cb7cSEd Maste 		warnx("elf_getphnum failed: %s", elf_errmsg(-1));
2383*2c23cb7cSEd Maste 		return;
2384*2c23cb7cSEd Maste 	}
2385*2c23cb7cSEd Maste 	if (phnum == 0) {
2386*2c23cb7cSEd Maste 		printf("\nThere are no program headers in this file.\n");
2387*2c23cb7cSEd Maste 		return;
2388*2c23cb7cSEd Maste 	}
2389*2c23cb7cSEd Maste 
2390*2c23cb7cSEd Maste 	printf("\nElf file type is %s", elf_type(re->ehdr.e_type));
2391*2c23cb7cSEd Maste 	printf("\nEntry point 0x%jx\n", (uintmax_t)re->ehdr.e_entry);
2392*2c23cb7cSEd Maste 	printf("There are %ju program headers, starting at offset %ju\n",
2393*2c23cb7cSEd Maste 	    (uintmax_t)phnum, (uintmax_t)re->ehdr.e_phoff);
2394*2c23cb7cSEd Maste 
2395*2c23cb7cSEd Maste 	/* Dump program headers. */
2396*2c23cb7cSEd Maste 	printf("\nProgram Headers:\n");
2397*2c23cb7cSEd Maste 	if (re->ec == ELFCLASS32)
2398*2c23cb7cSEd Maste 		printf("  %-15s%-9s%-11s%-11s%-8s%-8s%-4s%s\n", PH_HDR);
2399*2c23cb7cSEd Maste 	else if (re->options & RE_WW)
2400*2c23cb7cSEd Maste 		printf("  %-15s%-9s%-19s%-19s%-9s%-9s%-4s%s\n", PH_HDR);
2401*2c23cb7cSEd Maste 	else
2402*2c23cb7cSEd Maste 		printf("  %-15s%-19s%-19s%s\n                 %-19s%-20s"
2403*2c23cb7cSEd Maste 		    "%-7s%s\n", PH_HDR);
2404*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < phnum; i++) {
2405*2c23cb7cSEd Maste 		if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {
2406*2c23cb7cSEd Maste 			warnx("gelf_getphdr failed: %s", elf_errmsg(-1));
2407*2c23cb7cSEd Maste 			continue;
2408*2c23cb7cSEd Maste 		}
2409*2c23cb7cSEd Maste 		/* TODO: Add arch-specific segment type dump. */
2410*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32)
2411*2c23cb7cSEd Maste 			printf("  %-14.14s 0x%6.6jx 0x%8.8jx 0x%8.8jx "
2412*2c23cb7cSEd Maste 			    "0x%5.5jx 0x%5.5jx %c%c%c %#jx\n", PH_CT);
2413*2c23cb7cSEd Maste 		else if (re->options & RE_WW)
2414*2c23cb7cSEd Maste 			printf("  %-14.14s 0x%6.6jx 0x%16.16jx 0x%16.16jx "
2415*2c23cb7cSEd Maste 			    "0x%6.6jx 0x%6.6jx %c%c%c %#jx\n", PH_CT);
2416*2c23cb7cSEd Maste 		else
2417*2c23cb7cSEd Maste 			printf("  %-14.14s 0x%16.16jx 0x%16.16jx 0x%16.16jx\n"
2418*2c23cb7cSEd Maste 			    "                 0x%16.16jx 0x%16.16jx  %c%c%c"
2419*2c23cb7cSEd Maste 			    "    %#jx\n", PH_CT);
2420*2c23cb7cSEd Maste 		if (phdr.p_type == PT_INTERP) {
2421*2c23cb7cSEd Maste 			if ((rawfile = elf_rawfile(re->elf, NULL)) == NULL) {
2422*2c23cb7cSEd Maste 				warnx("elf_rawfile failed: %s", elf_errmsg(-1));
2423*2c23cb7cSEd Maste 				continue;
2424*2c23cb7cSEd Maste 			}
2425*2c23cb7cSEd Maste 			printf("      [Requesting program interpreter: %s]\n",
2426*2c23cb7cSEd Maste 				rawfile + phdr.p_offset);
2427*2c23cb7cSEd Maste 		}
2428*2c23cb7cSEd Maste 	}
2429*2c23cb7cSEd Maste 
2430*2c23cb7cSEd Maste 	/* Dump section to segment mapping. */
2431*2c23cb7cSEd Maste 	if (re->shnum == 0)
2432*2c23cb7cSEd Maste 		return;
2433*2c23cb7cSEd Maste 	printf("\n Section to Segment mapping:\n");
2434*2c23cb7cSEd Maste 	printf("  Segment Sections...\n");
2435*2c23cb7cSEd Maste 	for (i = 0; (size_t)i < phnum; i++) {
2436*2c23cb7cSEd Maste 		if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {
2437*2c23cb7cSEd Maste 			warnx("gelf_getphdr failed: %s", elf_errmsg(-1));
2438*2c23cb7cSEd Maste 			continue;
2439*2c23cb7cSEd Maste 		}
2440*2c23cb7cSEd Maste 		printf("   %2.2d     ", i);
2441*2c23cb7cSEd Maste 		/* skip NULL section. */
2442*2c23cb7cSEd Maste 		for (j = 1; (size_t)j < re->shnum; j++)
2443*2c23cb7cSEd Maste 			if (re->sl[j].off >= phdr.p_offset &&
2444*2c23cb7cSEd Maste 			    re->sl[j].off + re->sl[j].sz <=
2445*2c23cb7cSEd Maste 			    phdr.p_offset + phdr.p_memsz)
2446*2c23cb7cSEd Maste 				printf("%s ", re->sl[j].name);
2447*2c23cb7cSEd Maste 		printf("\n");
2448*2c23cb7cSEd Maste 	}
2449*2c23cb7cSEd Maste #undef	PH_HDR
2450*2c23cb7cSEd Maste #undef	PH_CT
2451*2c23cb7cSEd Maste }
2452*2c23cb7cSEd Maste 
2453*2c23cb7cSEd Maste static char *
2454*2c23cb7cSEd Maste section_flags(struct readelf *re, struct section *s)
2455*2c23cb7cSEd Maste {
2456*2c23cb7cSEd Maste #define BUF_SZ 256
2457*2c23cb7cSEd Maste 	static char	buf[BUF_SZ];
2458*2c23cb7cSEd Maste 	int		i, p, nb;
2459*2c23cb7cSEd Maste 
2460*2c23cb7cSEd Maste 	p = 0;
2461*2c23cb7cSEd Maste 	nb = re->ec == ELFCLASS32 ? 8 : 16;
2462*2c23cb7cSEd Maste 	if (re->options & RE_T) {
2463*2c23cb7cSEd Maste 		snprintf(buf, BUF_SZ, "[%*.*jx]: ", nb, nb,
2464*2c23cb7cSEd Maste 		    (uintmax_t)s->flags);
2465*2c23cb7cSEd Maste 		p += nb + 4;
2466*2c23cb7cSEd Maste 	}
2467*2c23cb7cSEd Maste 	for (i = 0; section_flag[i].ln != NULL; i++) {
2468*2c23cb7cSEd Maste 		if ((s->flags & section_flag[i].value) == 0)
2469*2c23cb7cSEd Maste 			continue;
2470*2c23cb7cSEd Maste 		if (re->options & RE_T) {
2471*2c23cb7cSEd Maste 			snprintf(&buf[p], BUF_SZ - p, "%s, ",
2472*2c23cb7cSEd Maste 			    section_flag[i].ln);
2473*2c23cb7cSEd Maste 			p += strlen(section_flag[i].ln) + 2;
2474*2c23cb7cSEd Maste 		} else
2475*2c23cb7cSEd Maste 			buf[p++] = section_flag[i].sn;
2476*2c23cb7cSEd Maste 	}
2477*2c23cb7cSEd Maste 	if (re->options & RE_T && p > nb + 4)
2478*2c23cb7cSEd Maste 		p -= 2;
2479*2c23cb7cSEd Maste 	buf[p] = '\0';
2480*2c23cb7cSEd Maste 
2481*2c23cb7cSEd Maste 	return (buf);
2482*2c23cb7cSEd Maste }
2483*2c23cb7cSEd Maste 
2484*2c23cb7cSEd Maste static void
2485*2c23cb7cSEd Maste dump_shdr(struct readelf *re)
2486*2c23cb7cSEd Maste {
2487*2c23cb7cSEd Maste 	struct section	*s;
2488*2c23cb7cSEd Maste 	int		 i;
2489*2c23cb7cSEd Maste 
2490*2c23cb7cSEd Maste #define	S_HDR	"[Nr] Name", "Type", "Addr", "Off", "Size", "ES",	\
2491*2c23cb7cSEd Maste 		"Flg", "Lk", "Inf", "Al"
2492*2c23cb7cSEd Maste #define	S_HDRL	"[Nr] Name", "Type", "Address", "Offset", "Size",	\
2493*2c23cb7cSEd Maste 		"EntSize", "Flags", "Link", "Info", "Align"
2494*2c23cb7cSEd Maste #define	ST_HDR	"[Nr] Name", "Type", "Addr", "Off", "Size", "ES",	\
2495*2c23cb7cSEd Maste 		"Lk", "Inf", "Al", "Flags"
2496*2c23cb7cSEd Maste #define	ST_HDRL	"[Nr] Name", "Type", "Address", "Offset", "Link",	\
2497*2c23cb7cSEd Maste 		"Size", "EntSize", "Info", "Align", "Flags"
2498*2c23cb7cSEd Maste #define	S_CT	i, s->name, section_type(re->ehdr.e_machine, s->type),	\
2499*2c23cb7cSEd Maste 		(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\
2500*2c23cb7cSEd Maste 		(uintmax_t)s->entsize, section_flags(re, s),		\
2501*2c23cb7cSEd Maste 		s->link, s->info, (uintmax_t)s->align
2502*2c23cb7cSEd Maste #define	ST_CT	i, s->name, section_type(re->ehdr.e_machine, s->type),  \
2503*2c23cb7cSEd Maste 		(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\
2504*2c23cb7cSEd Maste 		(uintmax_t)s->entsize, s->link, s->info,		\
2505*2c23cb7cSEd Maste 		(uintmax_t)s->align, section_flags(re, s)
2506*2c23cb7cSEd Maste #define	ST_CTL	i, s->name, section_type(re->ehdr.e_machine, s->type),  \
2507*2c23cb7cSEd Maste 		(uintmax_t)s->addr, (uintmax_t)s->off, s->link,		\
2508*2c23cb7cSEd Maste 		(uintmax_t)s->sz, (uintmax_t)s->entsize, s->info,	\
2509*2c23cb7cSEd Maste 		(uintmax_t)s->align, section_flags(re, s)
2510*2c23cb7cSEd Maste 
2511*2c23cb7cSEd Maste 	if (re->shnum == 0) {
2512*2c23cb7cSEd Maste 		printf("\nThere are no sections in this file.\n");
2513*2c23cb7cSEd Maste 		return;
2514*2c23cb7cSEd Maste 	}
2515*2c23cb7cSEd Maste 	printf("There are %ju section headers, starting at offset 0x%jx:\n",
2516*2c23cb7cSEd Maste 	    (uintmax_t)re->shnum, (uintmax_t)re->ehdr.e_shoff);
2517*2c23cb7cSEd Maste 	printf("\nSection Headers:\n");
2518*2c23cb7cSEd Maste 	if (re->ec == ELFCLASS32) {
2519*2c23cb7cSEd Maste 		if (re->options & RE_T)
2520*2c23cb7cSEd Maste 			printf("  %s\n       %-16s%-9s%-7s%-7s%-5s%-3s%-4s%s\n"
2521*2c23cb7cSEd Maste 			    "%12s\n", ST_HDR);
2522*2c23cb7cSEd Maste 		else
2523*2c23cb7cSEd Maste 			printf("  %-23s%-16s%-9s%-7s%-7s%-3s%-4s%-3s%-4s%s\n",
2524*2c23cb7cSEd Maste 			    S_HDR);
2525*2c23cb7cSEd Maste 	} else if (re->options & RE_WW) {
2526*2c23cb7cSEd Maste 		if (re->options & RE_T)
2527*2c23cb7cSEd Maste 			printf("  %s\n       %-16s%-17s%-7s%-7s%-5s%-3s%-4s%s\n"
2528*2c23cb7cSEd Maste 			    "%12s\n", ST_HDR);
2529*2c23cb7cSEd Maste 		else
2530*2c23cb7cSEd Maste 			printf("  %-23s%-16s%-17s%-7s%-7s%-3s%-4s%-3s%-4s%s\n",
2531*2c23cb7cSEd Maste 			    S_HDR);
2532*2c23cb7cSEd Maste 	} else {
2533*2c23cb7cSEd Maste 		if (re->options & RE_T)
2534*2c23cb7cSEd Maste 			printf("  %s\n       %-18s%-17s%-18s%s\n       %-18s"
2535*2c23cb7cSEd Maste 			    "%-17s%-18s%s\n%12s\n", ST_HDRL);
2536*2c23cb7cSEd Maste 		else
2537*2c23cb7cSEd Maste 			printf("  %-23s%-17s%-18s%s\n       %-18s%-17s%-7s%"
2538*2c23cb7cSEd Maste 			    "-6s%-6s%s\n", S_HDRL);
2539*2c23cb7cSEd Maste 	}
2540*2c23cb7cSEd Maste 	for (i = 0; (size_t)i < re->shnum; i++) {
2541*2c23cb7cSEd Maste 		s = &re->sl[i];
2542*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32) {
2543*2c23cb7cSEd Maste 			if (re->options & RE_T)
2544*2c23cb7cSEd Maste 				printf("  [%2d] %s\n       %-15.15s %8.8jx"
2545*2c23cb7cSEd Maste 				    " %6.6jx %6.6jx %2.2jx  %2u %3u %2ju\n"
2546*2c23cb7cSEd Maste 				    "       %s\n", ST_CT);
2547*2c23cb7cSEd Maste 			else
2548*2c23cb7cSEd Maste 				printf("  [%2d] %-17.17s %-15.15s %8.8jx"
2549*2c23cb7cSEd Maste 				    " %6.6jx %6.6jx %2.2jx %3s %2u %3u %2ju\n",
2550*2c23cb7cSEd Maste 				    S_CT);
2551*2c23cb7cSEd Maste 		} else if (re->options & RE_WW) {
2552*2c23cb7cSEd Maste 			if (re->options & RE_T)
2553*2c23cb7cSEd Maste 				printf("  [%2d] %s\n       %-15.15s %16.16jx"
2554*2c23cb7cSEd Maste 				    " %6.6jx %6.6jx %2.2jx  %2u %3u %2ju\n"
2555*2c23cb7cSEd Maste 				    "       %s\n", ST_CT);
2556*2c23cb7cSEd Maste 			else
2557*2c23cb7cSEd Maste 				printf("  [%2d] %-17.17s %-15.15s %16.16jx"
2558*2c23cb7cSEd Maste 				    " %6.6jx %6.6jx %2.2jx %3s %2u %3u %2ju\n",
2559*2c23cb7cSEd Maste 				    S_CT);
2560*2c23cb7cSEd Maste 		} else {
2561*2c23cb7cSEd Maste 			if (re->options & RE_T)
2562*2c23cb7cSEd Maste 				printf("  [%2d] %s\n       %-15.15s  %16.16jx"
2563*2c23cb7cSEd Maste 				    "  %16.16jx  %u\n       %16.16jx %16.16jx"
2564*2c23cb7cSEd Maste 				    "  %-16u  %ju\n       %s\n", ST_CTL);
2565*2c23cb7cSEd Maste 			else
2566*2c23cb7cSEd Maste 				printf("  [%2d] %-17.17s %-15.15s  %16.16jx"
2567*2c23cb7cSEd Maste 				    "  %8.8jx\n       %16.16jx  %16.16jx "
2568*2c23cb7cSEd Maste 				    "%3s      %2u   %3u     %ju\n", S_CT);
2569*2c23cb7cSEd Maste 		}
2570*2c23cb7cSEd Maste 	}
2571*2c23cb7cSEd Maste 	if ((re->options & RE_T) == 0)
2572*2c23cb7cSEd Maste 		printf("Key to Flags:\n  W (write), A (alloc),"
2573*2c23cb7cSEd Maste 		    " X (execute), M (merge), S (strings)\n"
2574*2c23cb7cSEd Maste 		    "  I (info), L (link order), G (group), x (unknown)\n"
2575*2c23cb7cSEd Maste 		    "  O (extra OS processing required)"
2576*2c23cb7cSEd Maste 		    " o (OS specific), p (processor specific)\n");
2577*2c23cb7cSEd Maste 
2578*2c23cb7cSEd Maste #undef	S_HDR
2579*2c23cb7cSEd Maste #undef	S_HDRL
2580*2c23cb7cSEd Maste #undef	ST_HDR
2581*2c23cb7cSEd Maste #undef	ST_HDRL
2582*2c23cb7cSEd Maste #undef	S_CT
2583*2c23cb7cSEd Maste #undef	ST_CT
2584*2c23cb7cSEd Maste #undef	ST_CTL
2585*2c23cb7cSEd Maste }
2586*2c23cb7cSEd Maste 
2587*2c23cb7cSEd Maste static void
2588*2c23cb7cSEd Maste dump_dynamic(struct readelf *re)
2589*2c23cb7cSEd Maste {
2590*2c23cb7cSEd Maste 	GElf_Dyn	 dyn;
2591*2c23cb7cSEd Maste 	Elf_Data	*d;
2592*2c23cb7cSEd Maste 	struct section	*s;
2593*2c23cb7cSEd Maste 	int		 elferr, i, is_dynamic, j, jmax, nentries;
2594*2c23cb7cSEd Maste 
2595*2c23cb7cSEd Maste 	is_dynamic = 0;
2596*2c23cb7cSEd Maste 
2597*2c23cb7cSEd Maste 	for (i = 0; (size_t)i < re->shnum; i++) {
2598*2c23cb7cSEd Maste 		s = &re->sl[i];
2599*2c23cb7cSEd Maste 		if (s->type != SHT_DYNAMIC)
2600*2c23cb7cSEd Maste 			continue;
2601*2c23cb7cSEd Maste 		(void) elf_errno();
2602*2c23cb7cSEd Maste 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
2603*2c23cb7cSEd Maste 			elferr = elf_errno();
2604*2c23cb7cSEd Maste 			if (elferr != 0)
2605*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s", elf_errmsg(-1));
2606*2c23cb7cSEd Maste 			continue;
2607*2c23cb7cSEd Maste 		}
2608*2c23cb7cSEd Maste 		if (d->d_size <= 0)
2609*2c23cb7cSEd Maste 			continue;
2610*2c23cb7cSEd Maste 
2611*2c23cb7cSEd Maste 		is_dynamic = 1;
2612*2c23cb7cSEd Maste 
2613*2c23cb7cSEd Maste 		/* Determine the actual number of table entries. */
2614*2c23cb7cSEd Maste 		nentries = 0;
2615*2c23cb7cSEd Maste 		jmax = (int) (s->sz / s->entsize);
2616*2c23cb7cSEd Maste 
2617*2c23cb7cSEd Maste 		for (j = 0; j < jmax; j++) {
2618*2c23cb7cSEd Maste 			if (gelf_getdyn(d, j, &dyn) != &dyn) {
2619*2c23cb7cSEd Maste 				warnx("gelf_getdyn failed: %s",
2620*2c23cb7cSEd Maste 				    elf_errmsg(-1));
2621*2c23cb7cSEd Maste 				continue;
2622*2c23cb7cSEd Maste 			}
2623*2c23cb7cSEd Maste 			nentries ++;
2624*2c23cb7cSEd Maste 			if (dyn.d_tag == DT_NULL)
2625*2c23cb7cSEd Maste 				break;
2626*2c23cb7cSEd Maste                 }
2627*2c23cb7cSEd Maste 
2628*2c23cb7cSEd Maste 		printf("\nDynamic section at offset 0x%jx", (uintmax_t)s->off);
2629*2c23cb7cSEd Maste 		printf(" contains %u entries:\n", nentries);
2630*2c23cb7cSEd Maste 
2631*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32)
2632*2c23cb7cSEd Maste 			printf("%5s%12s%28s\n", "Tag", "Type", "Name/Value");
2633*2c23cb7cSEd Maste 		else
2634*2c23cb7cSEd Maste 			printf("%5s%20s%28s\n", "Tag", "Type", "Name/Value");
2635*2c23cb7cSEd Maste 
2636*2c23cb7cSEd Maste 		for (j = 0; j < nentries; j++) {
2637*2c23cb7cSEd Maste 			if (gelf_getdyn(d, j, &dyn) != &dyn)
2638*2c23cb7cSEd Maste 				continue;
2639*2c23cb7cSEd Maste 			/* Dump dynamic entry type. */
2640*2c23cb7cSEd Maste 			if (re->ec == ELFCLASS32)
2641*2c23cb7cSEd Maste 				printf(" 0x%8.8jx", (uintmax_t)dyn.d_tag);
2642*2c23cb7cSEd Maste 			else
2643*2c23cb7cSEd Maste 				printf(" 0x%16.16jx", (uintmax_t)dyn.d_tag);
2644*2c23cb7cSEd Maste 			printf(" %-20s", dt_type(re->ehdr.e_machine,
2645*2c23cb7cSEd Maste 			    dyn.d_tag));
2646*2c23cb7cSEd Maste 			/* Dump dynamic entry value. */
2647*2c23cb7cSEd Maste 			dump_dyn_val(re, &dyn, s->link);
2648*2c23cb7cSEd Maste 		}
2649*2c23cb7cSEd Maste 	}
2650*2c23cb7cSEd Maste 
2651*2c23cb7cSEd Maste 	if (!is_dynamic)
2652*2c23cb7cSEd Maste 		printf("\nThere is no dynamic section in this file.\n");
2653*2c23cb7cSEd Maste }
2654*2c23cb7cSEd Maste 
2655*2c23cb7cSEd Maste static char *
2656*2c23cb7cSEd Maste timestamp(time_t ti)
2657*2c23cb7cSEd Maste {
2658*2c23cb7cSEd Maste 	static char ts[32];
2659*2c23cb7cSEd Maste 	struct tm *t;
2660*2c23cb7cSEd Maste 
2661*2c23cb7cSEd Maste 	t = gmtime(&ti);
2662*2c23cb7cSEd Maste 	snprintf(ts, sizeof(ts), "%04d-%02d-%02dT%02d:%02d:%02d",
2663*2c23cb7cSEd Maste 	    t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour,
2664*2c23cb7cSEd Maste 	    t->tm_min, t->tm_sec);
2665*2c23cb7cSEd Maste 
2666*2c23cb7cSEd Maste 	return (ts);
2667*2c23cb7cSEd Maste }
2668*2c23cb7cSEd Maste 
2669*2c23cb7cSEd Maste static const char *
2670*2c23cb7cSEd Maste dyn_str(struct readelf *re, uint32_t stab, uint64_t d_val)
2671*2c23cb7cSEd Maste {
2672*2c23cb7cSEd Maste 	const char *name;
2673*2c23cb7cSEd Maste 
2674*2c23cb7cSEd Maste 	if (stab == SHN_UNDEF)
2675*2c23cb7cSEd Maste 		name = "ERROR";
2676*2c23cb7cSEd Maste 	else if ((name = elf_strptr(re->elf, stab, d_val)) == NULL) {
2677*2c23cb7cSEd Maste 		(void) elf_errno(); /* clear error */
2678*2c23cb7cSEd Maste 		name = "ERROR";
2679*2c23cb7cSEd Maste 	}
2680*2c23cb7cSEd Maste 
2681*2c23cb7cSEd Maste 	return (name);
2682*2c23cb7cSEd Maste }
2683*2c23cb7cSEd Maste 
2684*2c23cb7cSEd Maste static void
2685*2c23cb7cSEd Maste dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
2686*2c23cb7cSEd Maste {
2687*2c23cb7cSEd Maste 	const char *name;
2688*2c23cb7cSEd Maste 
2689*2c23cb7cSEd Maste 	switch (re->ehdr.e_machine) {
2690*2c23cb7cSEd Maste 	case EM_MIPS:
2691*2c23cb7cSEd Maste 	case EM_MIPS_RS3_LE:
2692*2c23cb7cSEd Maste 		switch (dyn->d_tag) {
2693*2c23cb7cSEd Maste 		case DT_MIPS_RLD_VERSION:
2694*2c23cb7cSEd Maste 		case DT_MIPS_LOCAL_GOTNO:
2695*2c23cb7cSEd Maste 		case DT_MIPS_CONFLICTNO:
2696*2c23cb7cSEd Maste 		case DT_MIPS_LIBLISTNO:
2697*2c23cb7cSEd Maste 		case DT_MIPS_SYMTABNO:
2698*2c23cb7cSEd Maste 		case DT_MIPS_UNREFEXTNO:
2699*2c23cb7cSEd Maste 		case DT_MIPS_GOTSYM:
2700*2c23cb7cSEd Maste 		case DT_MIPS_HIPAGENO:
2701*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_CLASS_NO:
2702*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_INSTANCE_NO:
2703*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_RELOC_NO:
2704*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_SYM_NO:
2705*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_CLASSSYM_NO:
2706*2c23cb7cSEd Maste 		case DT_MIPS_LOCALPAGE_GOTIDX:
2707*2c23cb7cSEd Maste 		case DT_MIPS_LOCAL_GOTIDX:
2708*2c23cb7cSEd Maste 		case DT_MIPS_HIDDEN_GOTIDX:
2709*2c23cb7cSEd Maste 		case DT_MIPS_PROTECTED_GOTIDX:
2710*2c23cb7cSEd Maste 			printf(" %ju\n", (uintmax_t) dyn->d_un.d_val);
2711*2c23cb7cSEd Maste 			break;
2712*2c23cb7cSEd Maste 		case DT_MIPS_ICHECKSUM:
2713*2c23cb7cSEd Maste 		case DT_MIPS_FLAGS:
2714*2c23cb7cSEd Maste 		case DT_MIPS_BASE_ADDRESS:
2715*2c23cb7cSEd Maste 		case DT_MIPS_CONFLICT:
2716*2c23cb7cSEd Maste 		case DT_MIPS_LIBLIST:
2717*2c23cb7cSEd Maste 		case DT_MIPS_RLD_MAP:
2718*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_CLASS:
2719*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_INSTANCE:
2720*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_RELOC:
2721*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_SYM:
2722*2c23cb7cSEd Maste 		case DT_MIPS_DELTA_CLASSSYM:
2723*2c23cb7cSEd Maste 		case DT_MIPS_CXX_FLAGS:
2724*2c23cb7cSEd Maste 		case DT_MIPS_PIXIE_INIT:
2725*2c23cb7cSEd Maste 		case DT_MIPS_SYMBOL_LIB:
2726*2c23cb7cSEd Maste 		case DT_MIPS_OPTIONS:
2727*2c23cb7cSEd Maste 		case DT_MIPS_INTERFACE:
2728*2c23cb7cSEd Maste 		case DT_MIPS_DYNSTR_ALIGN:
2729*2c23cb7cSEd Maste 		case DT_MIPS_INTERFACE_SIZE:
2730*2c23cb7cSEd Maste 		case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:
2731*2c23cb7cSEd Maste 		case DT_MIPS_COMPACT_SIZE:
2732*2c23cb7cSEd Maste 		case DT_MIPS_GP_VALUE:
2733*2c23cb7cSEd Maste 		case DT_MIPS_AUX_DYNAMIC:
2734*2c23cb7cSEd Maste 		case DT_MIPS_PLTGOT:
2735*2c23cb7cSEd Maste 		case DT_MIPS_RLD_OBJ_UPDATE:
2736*2c23cb7cSEd Maste 		case DT_MIPS_RWPLT:
2737*2c23cb7cSEd Maste 			printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val);
2738*2c23cb7cSEd Maste 			break;
2739*2c23cb7cSEd Maste 		case DT_MIPS_IVERSION:
2740*2c23cb7cSEd Maste 		case DT_MIPS_PERF_SUFFIX:
2741*2c23cb7cSEd Maste 		case DT_AUXILIARY:
2742*2c23cb7cSEd Maste 		case DT_FILTER:
2743*2c23cb7cSEd Maste 			name = dyn_str(re, stab, dyn->d_un.d_val);
2744*2c23cb7cSEd Maste 			printf(" %s\n", name);
2745*2c23cb7cSEd Maste 			break;
2746*2c23cb7cSEd Maste 		case DT_MIPS_TIME_STAMP:
2747*2c23cb7cSEd Maste 			printf(" %s\n", timestamp(dyn->d_un.d_val));
2748*2c23cb7cSEd Maste 			break;
2749*2c23cb7cSEd Maste 		}
2750*2c23cb7cSEd Maste 		break;
2751*2c23cb7cSEd Maste 	default:
2752*2c23cb7cSEd Maste 		printf("\n");
2753*2c23cb7cSEd Maste 		break;
2754*2c23cb7cSEd Maste 	}
2755*2c23cb7cSEd Maste }
2756*2c23cb7cSEd Maste 
2757*2c23cb7cSEd Maste static void
2758*2c23cb7cSEd Maste dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
2759*2c23cb7cSEd Maste {
2760*2c23cb7cSEd Maste 	const char *name;
2761*2c23cb7cSEd Maste 
2762*2c23cb7cSEd Maste 	if (dyn->d_tag >= DT_LOPROC && dyn->d_tag <= DT_HIPROC) {
2763*2c23cb7cSEd Maste 		dump_arch_dyn_val(re, dyn, stab);
2764*2c23cb7cSEd Maste 		return;
2765*2c23cb7cSEd Maste 	}
2766*2c23cb7cSEd Maste 
2767*2c23cb7cSEd Maste 	/* These entry values are index into the string table. */
2768*2c23cb7cSEd Maste 	name = NULL;
2769*2c23cb7cSEd Maste 	if (dyn->d_tag == DT_NEEDED || dyn->d_tag == DT_SONAME ||
2770*2c23cb7cSEd Maste 	    dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH)
2771*2c23cb7cSEd Maste 		name = dyn_str(re, stab, dyn->d_un.d_val);
2772*2c23cb7cSEd Maste 
2773*2c23cb7cSEd Maste 	switch(dyn->d_tag) {
2774*2c23cb7cSEd Maste 	case DT_NULL:
2775*2c23cb7cSEd Maste 	case DT_PLTGOT:
2776*2c23cb7cSEd Maste 	case DT_HASH:
2777*2c23cb7cSEd Maste 	case DT_STRTAB:
2778*2c23cb7cSEd Maste 	case DT_SYMTAB:
2779*2c23cb7cSEd Maste 	case DT_RELA:
2780*2c23cb7cSEd Maste 	case DT_INIT:
2781*2c23cb7cSEd Maste 	case DT_SYMBOLIC:
2782*2c23cb7cSEd Maste 	case DT_REL:
2783*2c23cb7cSEd Maste 	case DT_DEBUG:
2784*2c23cb7cSEd Maste 	case DT_TEXTREL:
2785*2c23cb7cSEd Maste 	case DT_JMPREL:
2786*2c23cb7cSEd Maste 	case DT_FINI:
2787*2c23cb7cSEd Maste 	case DT_VERDEF:
2788*2c23cb7cSEd Maste 	case DT_VERNEED:
2789*2c23cb7cSEd Maste 	case DT_VERSYM:
2790*2c23cb7cSEd Maste 	case DT_GNU_HASH:
2791*2c23cb7cSEd Maste 	case DT_GNU_LIBLIST:
2792*2c23cb7cSEd Maste 	case DT_GNU_CONFLICT:
2793*2c23cb7cSEd Maste 		printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val);
2794*2c23cb7cSEd Maste 		break;
2795*2c23cb7cSEd Maste 	case DT_PLTRELSZ:
2796*2c23cb7cSEd Maste 	case DT_RELASZ:
2797*2c23cb7cSEd Maste 	case DT_RELAENT:
2798*2c23cb7cSEd Maste 	case DT_STRSZ:
2799*2c23cb7cSEd Maste 	case DT_SYMENT:
2800*2c23cb7cSEd Maste 	case DT_RELSZ:
2801*2c23cb7cSEd Maste 	case DT_RELENT:
2802*2c23cb7cSEd Maste 	case DT_INIT_ARRAYSZ:
2803*2c23cb7cSEd Maste 	case DT_FINI_ARRAYSZ:
2804*2c23cb7cSEd Maste 	case DT_GNU_CONFLICTSZ:
2805*2c23cb7cSEd Maste 	case DT_GNU_LIBLISTSZ:
2806*2c23cb7cSEd Maste 		printf(" %ju (bytes)\n", (uintmax_t) dyn->d_un.d_val);
2807*2c23cb7cSEd Maste 		break;
2808*2c23cb7cSEd Maste  	case DT_RELACOUNT:
2809*2c23cb7cSEd Maste 	case DT_RELCOUNT:
2810*2c23cb7cSEd Maste 	case DT_VERDEFNUM:
2811*2c23cb7cSEd Maste 	case DT_VERNEEDNUM:
2812*2c23cb7cSEd Maste 		printf(" %ju\n", (uintmax_t) dyn->d_un.d_val);
2813*2c23cb7cSEd Maste 		break;
2814*2c23cb7cSEd Maste 	case DT_NEEDED:
2815*2c23cb7cSEd Maste 		printf(" Shared library: [%s]\n", name);
2816*2c23cb7cSEd Maste 		break;
2817*2c23cb7cSEd Maste 	case DT_SONAME:
2818*2c23cb7cSEd Maste 		printf(" Library soname: [%s]\n", name);
2819*2c23cb7cSEd Maste 		break;
2820*2c23cb7cSEd Maste 	case DT_RPATH:
2821*2c23cb7cSEd Maste 		printf(" Library rpath: [%s]\n", name);
2822*2c23cb7cSEd Maste 		break;
2823*2c23cb7cSEd Maste 	case DT_RUNPATH:
2824*2c23cb7cSEd Maste 		printf(" Library runpath: [%s]\n", name);
2825*2c23cb7cSEd Maste 		break;
2826*2c23cb7cSEd Maste 	case DT_PLTREL:
2827*2c23cb7cSEd Maste 		printf(" %s\n", dt_type(re->ehdr.e_machine, dyn->d_un.d_val));
2828*2c23cb7cSEd Maste 		break;
2829*2c23cb7cSEd Maste 	case DT_GNU_PRELINKED:
2830*2c23cb7cSEd Maste 		printf(" %s\n", timestamp(dyn->d_un.d_val));
2831*2c23cb7cSEd Maste 		break;
2832*2c23cb7cSEd Maste 	default:
2833*2c23cb7cSEd Maste 		printf("\n");
2834*2c23cb7cSEd Maste 	}
2835*2c23cb7cSEd Maste }
2836*2c23cb7cSEd Maste 
2837*2c23cb7cSEd Maste static void
2838*2c23cb7cSEd Maste dump_rel(struct readelf *re, struct section *s, Elf_Data *d)
2839*2c23cb7cSEd Maste {
2840*2c23cb7cSEd Maste 	GElf_Rel r;
2841*2c23cb7cSEd Maste 	const char *symname;
2842*2c23cb7cSEd Maste 	uint64_t symval;
2843*2c23cb7cSEd Maste 	int i, len;
2844*2c23cb7cSEd Maste 
2845*2c23cb7cSEd Maste #define	REL_HDR "r_offset", "r_info", "r_type", "st_value", "st_name"
2846*2c23cb7cSEd Maste #define	REL_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info,	    \
2847*2c23cb7cSEd Maste 		r_type(re->ehdr.e_machine, ELF32_R_TYPE(r.r_info)), \
2848*2c23cb7cSEd Maste 		(uintmax_t)symval, symname
2849*2c23cb7cSEd Maste #define	REL_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info,	    \
2850*2c23cb7cSEd Maste 		r_type(re->ehdr.e_machine, ELF64_R_TYPE(r.r_info)), \
2851*2c23cb7cSEd Maste 		(uintmax_t)symval, symname
2852*2c23cb7cSEd Maste 
2853*2c23cb7cSEd Maste 	printf("\nRelocation section (%s):\n", s->name);
2854*2c23cb7cSEd Maste 	if (re->ec == ELFCLASS32)
2855*2c23cb7cSEd Maste 		printf("%-8s %-8s %-19s %-8s %s\n", REL_HDR);
2856*2c23cb7cSEd Maste 	else {
2857*2c23cb7cSEd Maste 		if (re->options & RE_WW)
2858*2c23cb7cSEd Maste 			printf("%-16s %-16s %-24s %-16s %s\n", REL_HDR);
2859*2c23cb7cSEd Maste 		else
2860*2c23cb7cSEd Maste 			printf("%-12s %-12s %-19s %-16s %s\n", REL_HDR);
2861*2c23cb7cSEd Maste 	}
2862*2c23cb7cSEd Maste 	len = d->d_size / s->entsize;
2863*2c23cb7cSEd Maste 	for (i = 0; i < len; i++) {
2864*2c23cb7cSEd Maste 		if (gelf_getrel(d, i, &r) != &r) {
2865*2c23cb7cSEd Maste 			warnx("gelf_getrel failed: %s", elf_errmsg(-1));
2866*2c23cb7cSEd Maste 			continue;
2867*2c23cb7cSEd Maste 		}
2868*2c23cb7cSEd Maste 		symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info));
2869*2c23cb7cSEd Maste 		symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info));
2870*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32) {
2871*2c23cb7cSEd Maste 			r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info),
2872*2c23cb7cSEd Maste 			    ELF64_R_TYPE(r.r_info));
2873*2c23cb7cSEd Maste 			printf("%8.8jx %8.8jx %-19.19s %8.8jx %s\n", REL_CT32);
2874*2c23cb7cSEd Maste 		} else {
2875*2c23cb7cSEd Maste 			if (re->options & RE_WW)
2876*2c23cb7cSEd Maste 				printf("%16.16jx %16.16jx %-24.24s"
2877*2c23cb7cSEd Maste 				    " %16.16jx %s\n", REL_CT64);
2878*2c23cb7cSEd Maste 			else
2879*2c23cb7cSEd Maste 				printf("%12.12jx %12.12jx %-19.19s"
2880*2c23cb7cSEd Maste 				    " %16.16jx %s\n", REL_CT64);
2881*2c23cb7cSEd Maste 		}
2882*2c23cb7cSEd Maste 	}
2883*2c23cb7cSEd Maste 
2884*2c23cb7cSEd Maste #undef	REL_HDR
2885*2c23cb7cSEd Maste #undef	REL_CT
2886*2c23cb7cSEd Maste }
2887*2c23cb7cSEd Maste 
2888*2c23cb7cSEd Maste static void
2889*2c23cb7cSEd Maste dump_rela(struct readelf *re, struct section *s, Elf_Data *d)
2890*2c23cb7cSEd Maste {
2891*2c23cb7cSEd Maste 	GElf_Rela r;
2892*2c23cb7cSEd Maste 	const char *symname;
2893*2c23cb7cSEd Maste 	uint64_t symval;
2894*2c23cb7cSEd Maste 	int i, len;
2895*2c23cb7cSEd Maste 
2896*2c23cb7cSEd Maste #define	RELA_HDR "r_offset", "r_info", "r_type", "st_value", \
2897*2c23cb7cSEd Maste 		"st_name + r_addend"
2898*2c23cb7cSEd Maste #define	RELA_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info,	    \
2899*2c23cb7cSEd Maste 		r_type(re->ehdr.e_machine, ELF32_R_TYPE(r.r_info)), \
2900*2c23cb7cSEd Maste 		(uintmax_t)symval, symname
2901*2c23cb7cSEd Maste #define	RELA_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info,	    \
2902*2c23cb7cSEd Maste 		r_type(re->ehdr.e_machine, ELF64_R_TYPE(r.r_info)), \
2903*2c23cb7cSEd Maste 		(uintmax_t)symval, symname
2904*2c23cb7cSEd Maste 
2905*2c23cb7cSEd Maste 	printf("\nRelocation section with addend (%s):\n", s->name);
2906*2c23cb7cSEd Maste 	if (re->ec == ELFCLASS32)
2907*2c23cb7cSEd Maste 		printf("%-8s %-8s %-19s %-8s %s\n", RELA_HDR);
2908*2c23cb7cSEd Maste 	else {
2909*2c23cb7cSEd Maste 		if (re->options & RE_WW)
2910*2c23cb7cSEd Maste 			printf("%-16s %-16s %-24s %-16s %s\n", RELA_HDR);
2911*2c23cb7cSEd Maste 		else
2912*2c23cb7cSEd Maste 			printf("%-12s %-12s %-19s %-16s %s\n", RELA_HDR);
2913*2c23cb7cSEd Maste 	}
2914*2c23cb7cSEd Maste 	len = d->d_size / s->entsize;
2915*2c23cb7cSEd Maste 	for (i = 0; i < len; i++) {
2916*2c23cb7cSEd Maste 		if (gelf_getrela(d, i, &r) != &r) {
2917*2c23cb7cSEd Maste 			warnx("gelf_getrel failed: %s", elf_errmsg(-1));
2918*2c23cb7cSEd Maste 			continue;
2919*2c23cb7cSEd Maste 		}
2920*2c23cb7cSEd Maste 		symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info));
2921*2c23cb7cSEd Maste 		symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info));
2922*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32) {
2923*2c23cb7cSEd Maste 			r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info),
2924*2c23cb7cSEd Maste 			    ELF64_R_TYPE(r.r_info));
2925*2c23cb7cSEd Maste 			printf("%8.8jx %8.8jx %-19.19s %8.8jx %s", RELA_CT32);
2926*2c23cb7cSEd Maste 			printf(" + %x\n", (uint32_t) r.r_addend);
2927*2c23cb7cSEd Maste 		} else {
2928*2c23cb7cSEd Maste 			if (re->options & RE_WW)
2929*2c23cb7cSEd Maste 				printf("%16.16jx %16.16jx %-24.24s"
2930*2c23cb7cSEd Maste 				    " %16.16jx %s", RELA_CT64);
2931*2c23cb7cSEd Maste 			else
2932*2c23cb7cSEd Maste 				printf("%12.12jx %12.12jx %-19.19s"
2933*2c23cb7cSEd Maste 				    " %16.16jx %s", RELA_CT64);
2934*2c23cb7cSEd Maste 			printf(" + %jx\n", (uintmax_t) r.r_addend);
2935*2c23cb7cSEd Maste 		}
2936*2c23cb7cSEd Maste 	}
2937*2c23cb7cSEd Maste 
2938*2c23cb7cSEd Maste #undef	RELA_HDR
2939*2c23cb7cSEd Maste #undef	RELA_CT
2940*2c23cb7cSEd Maste }
2941*2c23cb7cSEd Maste 
2942*2c23cb7cSEd Maste static void
2943*2c23cb7cSEd Maste dump_reloc(struct readelf *re)
2944*2c23cb7cSEd Maste {
2945*2c23cb7cSEd Maste 	struct section *s;
2946*2c23cb7cSEd Maste 	Elf_Data *d;
2947*2c23cb7cSEd Maste 	int i, elferr;
2948*2c23cb7cSEd Maste 
2949*2c23cb7cSEd Maste 	for (i = 0; (size_t)i < re->shnum; i++) {
2950*2c23cb7cSEd Maste 		s = &re->sl[i];
2951*2c23cb7cSEd Maste 		if (s->type == SHT_REL || s->type == SHT_RELA) {
2952*2c23cb7cSEd Maste 			(void) elf_errno();
2953*2c23cb7cSEd Maste 			if ((d = elf_getdata(s->scn, NULL)) == NULL) {
2954*2c23cb7cSEd Maste 				elferr = elf_errno();
2955*2c23cb7cSEd Maste 				if (elferr != 0)
2956*2c23cb7cSEd Maste 					warnx("elf_getdata failed: %s",
2957*2c23cb7cSEd Maste 					    elf_errmsg(elferr));
2958*2c23cb7cSEd Maste 				continue;
2959*2c23cb7cSEd Maste 			}
2960*2c23cb7cSEd Maste 			if (s->type == SHT_REL)
2961*2c23cb7cSEd Maste 				dump_rel(re, s, d);
2962*2c23cb7cSEd Maste 			else
2963*2c23cb7cSEd Maste 				dump_rela(re, s, d);
2964*2c23cb7cSEd Maste 		}
2965*2c23cb7cSEd Maste 	}
2966*2c23cb7cSEd Maste }
2967*2c23cb7cSEd Maste 
2968*2c23cb7cSEd Maste static void
2969*2c23cb7cSEd Maste dump_symtab(struct readelf *re, int i)
2970*2c23cb7cSEd Maste {
2971*2c23cb7cSEd Maste 	struct section *s;
2972*2c23cb7cSEd Maste 	Elf_Data *d;
2973*2c23cb7cSEd Maste 	GElf_Sym sym;
2974*2c23cb7cSEd Maste 	const char *name;
2975*2c23cb7cSEd Maste 	int elferr, stab, j;
2976*2c23cb7cSEd Maste 
2977*2c23cb7cSEd Maste 	s = &re->sl[i];
2978*2c23cb7cSEd Maste 	stab = s->link;
2979*2c23cb7cSEd Maste 	(void) elf_errno();
2980*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
2981*2c23cb7cSEd Maste 		elferr = elf_errno();
2982*2c23cb7cSEd Maste 		if (elferr != 0)
2983*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
2984*2c23cb7cSEd Maste 		return;
2985*2c23cb7cSEd Maste 	}
2986*2c23cb7cSEd Maste 	if (d->d_size <= 0)
2987*2c23cb7cSEd Maste 		return;
2988*2c23cb7cSEd Maste 	printf("Symbol table (%s)", s->name);
2989*2c23cb7cSEd Maste 	printf(" contains %ju entries:\n", s->sz / s->entsize);
2990*2c23cb7cSEd Maste 	printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type",
2991*2c23cb7cSEd Maste 	    "Bind", "Vis", "Ndx", "Name");
2992*2c23cb7cSEd Maste 
2993*2c23cb7cSEd Maste 	for (j = 0; (uint64_t)j < s->sz / s->entsize; j++) {
2994*2c23cb7cSEd Maste 		if (gelf_getsym(d, j, &sym) != &sym) {
2995*2c23cb7cSEd Maste 			warnx("gelf_getsym failed: %s", elf_errmsg(-1));
2996*2c23cb7cSEd Maste 			continue;
2997*2c23cb7cSEd Maste 		}
2998*2c23cb7cSEd Maste 		printf("%6d:", j);
2999*2c23cb7cSEd Maste 		printf(" %16.16jx", (uintmax_t)sym.st_value);
3000*2c23cb7cSEd Maste 		printf(" %5ju", sym.st_size);
3001*2c23cb7cSEd Maste 		printf(" %-7s", st_type(GELF_ST_TYPE(sym.st_info)));
3002*2c23cb7cSEd Maste 		printf(" %-6s", st_bind(GELF_ST_BIND(sym.st_info)));
3003*2c23cb7cSEd Maste 		printf(" %-8s", st_vis(GELF_ST_VISIBILITY(sym.st_other)));
3004*2c23cb7cSEd Maste 		printf(" %3s", st_shndx(sym.st_shndx));
3005*2c23cb7cSEd Maste 		if ((name = elf_strptr(re->elf, stab, sym.st_name)) != NULL)
3006*2c23cb7cSEd Maste 			printf(" %s", name);
3007*2c23cb7cSEd Maste 		/* Append symbol version string for SHT_DYNSYM symbol table. */
3008*2c23cb7cSEd Maste 		if (s->type == SHT_DYNSYM && re->ver != NULL &&
3009*2c23cb7cSEd Maste 		    re->vs != NULL && re->vs[j] > 1) {
3010*2c23cb7cSEd Maste 			if (re->vs[j] & 0x8000 ||
3011*2c23cb7cSEd Maste 			    re->ver[re->vs[j] & 0x7fff].type == 0)
3012*2c23cb7cSEd Maste 				printf("@%s (%d)",
3013*2c23cb7cSEd Maste 				    re->ver[re->vs[j] & 0x7fff].name,
3014*2c23cb7cSEd Maste 				    re->vs[j] & 0x7fff);
3015*2c23cb7cSEd Maste 			else
3016*2c23cb7cSEd Maste 				printf("@@%s (%d)", re->ver[re->vs[j]].name,
3017*2c23cb7cSEd Maste 				    re->vs[j]);
3018*2c23cb7cSEd Maste 		}
3019*2c23cb7cSEd Maste 		putchar('\n');
3020*2c23cb7cSEd Maste 	}
3021*2c23cb7cSEd Maste 
3022*2c23cb7cSEd Maste }
3023*2c23cb7cSEd Maste 
3024*2c23cb7cSEd Maste static void
3025*2c23cb7cSEd Maste dump_symtabs(struct readelf *re)
3026*2c23cb7cSEd Maste {
3027*2c23cb7cSEd Maste 	GElf_Dyn dyn;
3028*2c23cb7cSEd Maste 	Elf_Data *d;
3029*2c23cb7cSEd Maste 	struct section *s;
3030*2c23cb7cSEd Maste 	uint64_t dyn_off;
3031*2c23cb7cSEd Maste 	int elferr, i;
3032*2c23cb7cSEd Maste 
3033*2c23cb7cSEd Maste 	/*
3034*2c23cb7cSEd Maste 	 * If -D is specified, only dump the symbol table specified by
3035*2c23cb7cSEd Maste 	 * the DT_SYMTAB entry in the .dynamic section.
3036*2c23cb7cSEd Maste 	 */
3037*2c23cb7cSEd Maste 	dyn_off = 0;
3038*2c23cb7cSEd Maste 	if (re->options & RE_DD) {
3039*2c23cb7cSEd Maste 		s = NULL;
3040*2c23cb7cSEd Maste 		for (i = 0; (size_t)i < re->shnum; i++)
3041*2c23cb7cSEd Maste 			if (re->sl[i].type == SHT_DYNAMIC) {
3042*2c23cb7cSEd Maste 				s = &re->sl[i];
3043*2c23cb7cSEd Maste 				break;
3044*2c23cb7cSEd Maste 			}
3045*2c23cb7cSEd Maste 		if (s == NULL)
3046*2c23cb7cSEd Maste 			return;
3047*2c23cb7cSEd Maste 		(void) elf_errno();
3048*2c23cb7cSEd Maste 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3049*2c23cb7cSEd Maste 			elferr = elf_errno();
3050*2c23cb7cSEd Maste 			if (elferr != 0)
3051*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s", elf_errmsg(-1));
3052*2c23cb7cSEd Maste 			return;
3053*2c23cb7cSEd Maste 		}
3054*2c23cb7cSEd Maste 		if (d->d_size <= 0)
3055*2c23cb7cSEd Maste 			return;
3056*2c23cb7cSEd Maste 
3057*2c23cb7cSEd Maste 		for (i = 0; (uint64_t)i < s->sz / s->entsize; i++) {
3058*2c23cb7cSEd Maste 			if (gelf_getdyn(d, i, &dyn) != &dyn) {
3059*2c23cb7cSEd Maste 				warnx("gelf_getdyn failed: %s", elf_errmsg(-1));
3060*2c23cb7cSEd Maste 				continue;
3061*2c23cb7cSEd Maste 			}
3062*2c23cb7cSEd Maste 			if (dyn.d_tag == DT_SYMTAB) {
3063*2c23cb7cSEd Maste 				dyn_off = dyn.d_un.d_val;
3064*2c23cb7cSEd Maste 				break;
3065*2c23cb7cSEd Maste 			}
3066*2c23cb7cSEd Maste 		}
3067*2c23cb7cSEd Maste 	}
3068*2c23cb7cSEd Maste 
3069*2c23cb7cSEd Maste 	/* Find and dump symbol tables. */
3070*2c23cb7cSEd Maste 	for (i = 0; (size_t)i < re->shnum; i++) {
3071*2c23cb7cSEd Maste 		s = &re->sl[i];
3072*2c23cb7cSEd Maste 		if (s->type == SHT_SYMTAB || s->type == SHT_DYNSYM) {
3073*2c23cb7cSEd Maste 			if (re->options & RE_DD) {
3074*2c23cb7cSEd Maste 				if (dyn_off == s->addr) {
3075*2c23cb7cSEd Maste 					dump_symtab(re, i);
3076*2c23cb7cSEd Maste 					break;
3077*2c23cb7cSEd Maste 				}
3078*2c23cb7cSEd Maste 			} else
3079*2c23cb7cSEd Maste 				dump_symtab(re, i);
3080*2c23cb7cSEd Maste 		}
3081*2c23cb7cSEd Maste 	}
3082*2c23cb7cSEd Maste }
3083*2c23cb7cSEd Maste 
3084*2c23cb7cSEd Maste static void
3085*2c23cb7cSEd Maste dump_svr4_hash(struct section *s)
3086*2c23cb7cSEd Maste {
3087*2c23cb7cSEd Maste 	Elf_Data	*d;
3088*2c23cb7cSEd Maste 	uint32_t	*buf;
3089*2c23cb7cSEd Maste 	uint32_t	 nbucket, nchain;
3090*2c23cb7cSEd Maste 	uint32_t	*bucket, *chain;
3091*2c23cb7cSEd Maste 	uint32_t	*bl, *c, maxl, total;
3092*2c23cb7cSEd Maste 	int		 elferr, i, j;
3093*2c23cb7cSEd Maste 
3094*2c23cb7cSEd Maste 	/* Read and parse the content of .hash section. */
3095*2c23cb7cSEd Maste 	(void) elf_errno();
3096*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3097*2c23cb7cSEd Maste 		elferr = elf_errno();
3098*2c23cb7cSEd Maste 		if (elferr != 0)
3099*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
3100*2c23cb7cSEd Maste 		return;
3101*2c23cb7cSEd Maste 	}
3102*2c23cb7cSEd Maste 	if (d->d_size < 2 * sizeof(uint32_t)) {
3103*2c23cb7cSEd Maste 		warnx(".hash section too small");
3104*2c23cb7cSEd Maste 		return;
3105*2c23cb7cSEd Maste 	}
3106*2c23cb7cSEd Maste 	buf = d->d_buf;
3107*2c23cb7cSEd Maste 	nbucket = buf[0];
3108*2c23cb7cSEd Maste 	nchain = buf[1];
3109*2c23cb7cSEd Maste 	if (nbucket <= 0 || nchain <= 0) {
3110*2c23cb7cSEd Maste 		warnx("Malformed .hash section");
3111*2c23cb7cSEd Maste 		return;
3112*2c23cb7cSEd Maste 	}
3113*2c23cb7cSEd Maste 	if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) {
3114*2c23cb7cSEd Maste 		warnx("Malformed .hash section");
3115*2c23cb7cSEd Maste 		return;
3116*2c23cb7cSEd Maste 	}
3117*2c23cb7cSEd Maste 	bucket = &buf[2];
3118*2c23cb7cSEd Maste 	chain = &buf[2 + nbucket];
3119*2c23cb7cSEd Maste 
3120*2c23cb7cSEd Maste 	maxl = 0;
3121*2c23cb7cSEd Maste 	if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
3122*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3123*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i < nbucket; i++)
3124*2c23cb7cSEd Maste 		for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j])
3125*2c23cb7cSEd Maste 			if (++bl[i] > maxl)
3126*2c23cb7cSEd Maste 				maxl = bl[i];
3127*2c23cb7cSEd Maste 	if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
3128*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3129*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i < nbucket; i++)
3130*2c23cb7cSEd Maste 		c[bl[i]]++;
3131*2c23cb7cSEd Maste 	printf("\nHistogram for bucket list length (total of %u buckets):\n",
3132*2c23cb7cSEd Maste 	    nbucket);
3133*2c23cb7cSEd Maste 	printf(" Length\tNumber\t\t%% of total\tCoverage\n");
3134*2c23cb7cSEd Maste 	total = 0;
3135*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i <= maxl; i++) {
3136*2c23cb7cSEd Maste 		total += c[i] * i;
3137*2c23cb7cSEd Maste 		printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i],
3138*2c23cb7cSEd Maste 		    c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));
3139*2c23cb7cSEd Maste 	}
3140*2c23cb7cSEd Maste 	free(c);
3141*2c23cb7cSEd Maste 	free(bl);
3142*2c23cb7cSEd Maste }
3143*2c23cb7cSEd Maste 
3144*2c23cb7cSEd Maste static void
3145*2c23cb7cSEd Maste dump_svr4_hash64(struct readelf *re, struct section *s)
3146*2c23cb7cSEd Maste {
3147*2c23cb7cSEd Maste 	Elf_Data	*d, dst;
3148*2c23cb7cSEd Maste 	uint64_t	*buf;
3149*2c23cb7cSEd Maste 	uint64_t	 nbucket, nchain;
3150*2c23cb7cSEd Maste 	uint64_t	*bucket, *chain;
3151*2c23cb7cSEd Maste 	uint64_t	*bl, *c, maxl, total;
3152*2c23cb7cSEd Maste 	int		 elferr, i, j;
3153*2c23cb7cSEd Maste 
3154*2c23cb7cSEd Maste 	/*
3155*2c23cb7cSEd Maste 	 * ALPHA uses 64-bit hash entries. Since libelf assumes that
3156*2c23cb7cSEd Maste 	 * .hash section contains only 32-bit entry, an explicit
3157*2c23cb7cSEd Maste 	 * gelf_xlatetom is needed here.
3158*2c23cb7cSEd Maste 	 */
3159*2c23cb7cSEd Maste 	(void) elf_errno();
3160*2c23cb7cSEd Maste 	if ((d = elf_rawdata(s->scn, NULL)) == NULL) {
3161*2c23cb7cSEd Maste 		elferr = elf_errno();
3162*2c23cb7cSEd Maste 		if (elferr != 0)
3163*2c23cb7cSEd Maste 			warnx("elf_rawdata failed: %s",
3164*2c23cb7cSEd Maste 			    elf_errmsg(elferr));
3165*2c23cb7cSEd Maste 		return;
3166*2c23cb7cSEd Maste 	}
3167*2c23cb7cSEd Maste 	d->d_type = ELF_T_XWORD;
3168*2c23cb7cSEd Maste 	memcpy(&dst, d, sizeof(Elf_Data));
3169*2c23cb7cSEd Maste 	if (gelf_xlatetom(re->elf, &dst, d,
3170*2c23cb7cSEd Maste 		re->ehdr.e_ident[EI_DATA]) != &dst) {
3171*2c23cb7cSEd Maste 		warnx("gelf_xlatetom failed: %s", elf_errmsg(-1));
3172*2c23cb7cSEd Maste 		return;
3173*2c23cb7cSEd Maste 	}
3174*2c23cb7cSEd Maste 	if (dst.d_size < 2 * sizeof(uint64_t)) {
3175*2c23cb7cSEd Maste 		warnx(".hash section too small");
3176*2c23cb7cSEd Maste 		return;
3177*2c23cb7cSEd Maste 	}
3178*2c23cb7cSEd Maste 	buf = dst.d_buf;
3179*2c23cb7cSEd Maste 	nbucket = buf[0];
3180*2c23cb7cSEd Maste 	nchain = buf[1];
3181*2c23cb7cSEd Maste 	if (nbucket <= 0 || nchain <= 0) {
3182*2c23cb7cSEd Maste 		warnx("Malformed .hash section");
3183*2c23cb7cSEd Maste 		return;
3184*2c23cb7cSEd Maste 	}
3185*2c23cb7cSEd Maste 	if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) {
3186*2c23cb7cSEd Maste 		warnx("Malformed .hash section");
3187*2c23cb7cSEd Maste 		return;
3188*2c23cb7cSEd Maste 	}
3189*2c23cb7cSEd Maste 	bucket = &buf[2];
3190*2c23cb7cSEd Maste 	chain = &buf[2 + nbucket];
3191*2c23cb7cSEd Maste 
3192*2c23cb7cSEd Maste 	maxl = 0;
3193*2c23cb7cSEd Maste 	if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
3194*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3195*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i < nbucket; i++)
3196*2c23cb7cSEd Maste 		for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j])
3197*2c23cb7cSEd Maste 			if (++bl[i] > maxl)
3198*2c23cb7cSEd Maste 				maxl = bl[i];
3199*2c23cb7cSEd Maste 	if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
3200*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3201*2c23cb7cSEd Maste 	for (i = 0; (uint64_t)i < nbucket; i++)
3202*2c23cb7cSEd Maste 		c[bl[i]]++;
3203*2c23cb7cSEd Maste 	printf("Histogram for bucket list length (total of %ju buckets):\n",
3204*2c23cb7cSEd Maste 	    (uintmax_t)nbucket);
3205*2c23cb7cSEd Maste 	printf(" Length\tNumber\t\t%% of total\tCoverage\n");
3206*2c23cb7cSEd Maste 	total = 0;
3207*2c23cb7cSEd Maste 	for (i = 0; (uint64_t)i <= maxl; i++) {
3208*2c23cb7cSEd Maste 		total += c[i] * i;
3209*2c23cb7cSEd Maste 		printf("%7u\t%-10ju\t(%5.1f%%)\t%5.1f%%\n", i, (uintmax_t)c[i],
3210*2c23cb7cSEd Maste 		    c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));
3211*2c23cb7cSEd Maste 	}
3212*2c23cb7cSEd Maste 	free(c);
3213*2c23cb7cSEd Maste 	free(bl);
3214*2c23cb7cSEd Maste }
3215*2c23cb7cSEd Maste 
3216*2c23cb7cSEd Maste static void
3217*2c23cb7cSEd Maste dump_gnu_hash(struct readelf *re, struct section *s)
3218*2c23cb7cSEd Maste {
3219*2c23cb7cSEd Maste 	struct section	*ds;
3220*2c23cb7cSEd Maste 	Elf_Data	*d;
3221*2c23cb7cSEd Maste 	uint32_t	*buf;
3222*2c23cb7cSEd Maste 	uint32_t	*bucket, *chain;
3223*2c23cb7cSEd Maste 	uint32_t	 nbucket, nchain, symndx, maskwords, shift2;
3224*2c23cb7cSEd Maste 	uint32_t	*bl, *c, maxl, total;
3225*2c23cb7cSEd Maste 	int		 elferr, dynsymcount, i, j;
3226*2c23cb7cSEd Maste 
3227*2c23cb7cSEd Maste 	(void) elf_errno();
3228*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3229*2c23cb7cSEd Maste 		elferr = elf_errno();
3230*2c23cb7cSEd Maste 		if (elferr != 0)
3231*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s",
3232*2c23cb7cSEd Maste 			    elf_errmsg(elferr));
3233*2c23cb7cSEd Maste 		return;
3234*2c23cb7cSEd Maste 	}
3235*2c23cb7cSEd Maste 	if (d->d_size < 4 * sizeof(uint32_t)) {
3236*2c23cb7cSEd Maste 		warnx(".gnu.hash section too small");
3237*2c23cb7cSEd Maste 		return;
3238*2c23cb7cSEd Maste 	}
3239*2c23cb7cSEd Maste 	buf = d->d_buf;
3240*2c23cb7cSEd Maste 	nbucket = buf[0];
3241*2c23cb7cSEd Maste 	symndx = buf[1];
3242*2c23cb7cSEd Maste 	maskwords = buf[2];
3243*2c23cb7cSEd Maste 	shift2 = buf[3];
3244*2c23cb7cSEd Maste 	buf += 4;
3245*2c23cb7cSEd Maste 	ds = &re->sl[s->link];
3246*2c23cb7cSEd Maste 	dynsymcount = ds->sz / ds->entsize;
3247*2c23cb7cSEd Maste 	nchain = dynsymcount - symndx;
3248*2c23cb7cSEd Maste 	if (d->d_size != 4 * sizeof(uint32_t) + maskwords *
3249*2c23cb7cSEd Maste 	    (re->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) +
3250*2c23cb7cSEd Maste 	    (nbucket + nchain) * sizeof(uint32_t)) {
3251*2c23cb7cSEd Maste 		warnx("Malformed .gnu.hash section");
3252*2c23cb7cSEd Maste 		return;
3253*2c23cb7cSEd Maste 	}
3254*2c23cb7cSEd Maste 	bucket = buf + (re->ec == ELFCLASS32 ? maskwords : maskwords * 2);
3255*2c23cb7cSEd Maste 	chain = bucket + nbucket;
3256*2c23cb7cSEd Maste 
3257*2c23cb7cSEd Maste 	maxl = 0;
3258*2c23cb7cSEd Maste 	if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)
3259*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3260*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i < nbucket; i++)
3261*2c23cb7cSEd Maste 		for (j = bucket[i]; j > 0 && (uint32_t)j - symndx < nchain;
3262*2c23cb7cSEd Maste 		     j++) {
3263*2c23cb7cSEd Maste 			if (++bl[i] > maxl)
3264*2c23cb7cSEd Maste 				maxl = bl[i];
3265*2c23cb7cSEd Maste 			if (chain[j - symndx] & 1)
3266*2c23cb7cSEd Maste 				break;
3267*2c23cb7cSEd Maste 		}
3268*2c23cb7cSEd Maste 	if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)
3269*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
3270*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i < nbucket; i++)
3271*2c23cb7cSEd Maste 		c[bl[i]]++;
3272*2c23cb7cSEd Maste 	printf("Histogram for bucket list length (total of %u buckets):\n",
3273*2c23cb7cSEd Maste 	    nbucket);
3274*2c23cb7cSEd Maste 	printf(" Length\tNumber\t\t%% of total\tCoverage\n");
3275*2c23cb7cSEd Maste 	total = 0;
3276*2c23cb7cSEd Maste 	for (i = 0; (uint32_t)i <= maxl; i++) {
3277*2c23cb7cSEd Maste 		total += c[i] * i;
3278*2c23cb7cSEd Maste 		printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i],
3279*2c23cb7cSEd Maste 		    c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));
3280*2c23cb7cSEd Maste 	}
3281*2c23cb7cSEd Maste 	free(c);
3282*2c23cb7cSEd Maste 	free(bl);
3283*2c23cb7cSEd Maste }
3284*2c23cb7cSEd Maste 
3285*2c23cb7cSEd Maste static void
3286*2c23cb7cSEd Maste dump_hash(struct readelf *re)
3287*2c23cb7cSEd Maste {
3288*2c23cb7cSEd Maste 	struct section	*s;
3289*2c23cb7cSEd Maste 	int		 i;
3290*2c23cb7cSEd Maste 
3291*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
3292*2c23cb7cSEd Maste 		s = &re->sl[i];
3293*2c23cb7cSEd Maste 		if (s->type == SHT_HASH || s->type == SHT_GNU_HASH) {
3294*2c23cb7cSEd Maste 			if (s->type == SHT_GNU_HASH)
3295*2c23cb7cSEd Maste 				dump_gnu_hash(re, s);
3296*2c23cb7cSEd Maste 			else if (re->ehdr.e_machine == EM_ALPHA &&
3297*2c23cb7cSEd Maste 			    s->entsize == 8)
3298*2c23cb7cSEd Maste 				dump_svr4_hash64(re, s);
3299*2c23cb7cSEd Maste 			else
3300*2c23cb7cSEd Maste 				dump_svr4_hash(s);
3301*2c23cb7cSEd Maste 		}
3302*2c23cb7cSEd Maste 	}
3303*2c23cb7cSEd Maste }
3304*2c23cb7cSEd Maste 
3305*2c23cb7cSEd Maste static void
3306*2c23cb7cSEd Maste dump_notes(struct readelf *re)
3307*2c23cb7cSEd Maste {
3308*2c23cb7cSEd Maste 	struct section *s;
3309*2c23cb7cSEd Maste 	const char *rawfile;
3310*2c23cb7cSEd Maste 	GElf_Phdr phdr;
3311*2c23cb7cSEd Maste 	Elf_Data *d;
3312*2c23cb7cSEd Maste 	size_t phnum;
3313*2c23cb7cSEd Maste 	int i, elferr;
3314*2c23cb7cSEd Maste 
3315*2c23cb7cSEd Maste 	if (re->ehdr.e_type == ET_CORE) {
3316*2c23cb7cSEd Maste 		/*
3317*2c23cb7cSEd Maste 		 * Search program headers in the core file for
3318*2c23cb7cSEd Maste 		 * PT_NOTE entry.
3319*2c23cb7cSEd Maste 		 */
3320*2c23cb7cSEd Maste 		if (elf_getphnum(re->elf, &phnum) == 0) {
3321*2c23cb7cSEd Maste 			warnx("elf_getphnum failed: %s", elf_errmsg(-1));
3322*2c23cb7cSEd Maste 			return;
3323*2c23cb7cSEd Maste 		}
3324*2c23cb7cSEd Maste 		if (phnum == 0)
3325*2c23cb7cSEd Maste 			return;
3326*2c23cb7cSEd Maste 		if ((rawfile = elf_rawfile(re->elf, NULL)) == NULL) {
3327*2c23cb7cSEd Maste 			warnx("elf_rawfile failed: %s", elf_errmsg(-1));
3328*2c23cb7cSEd Maste 			return;
3329*2c23cb7cSEd Maste 		}
3330*2c23cb7cSEd Maste 		for (i = 0; (size_t) i < phnum; i++) {
3331*2c23cb7cSEd Maste 			if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {
3332*2c23cb7cSEd Maste 				warnx("gelf_getphdr failed: %s",
3333*2c23cb7cSEd Maste 				    elf_errmsg(-1));
3334*2c23cb7cSEd Maste 				continue;
3335*2c23cb7cSEd Maste 			}
3336*2c23cb7cSEd Maste 			if (phdr.p_type == PT_NOTE)
3337*2c23cb7cSEd Maste 				dump_notes_content(re, rawfile + phdr.p_offset,
3338*2c23cb7cSEd Maste 				    phdr.p_filesz, phdr.p_offset);
3339*2c23cb7cSEd Maste 		}
3340*2c23cb7cSEd Maste 
3341*2c23cb7cSEd Maste 	} else {
3342*2c23cb7cSEd Maste 		/*
3343*2c23cb7cSEd Maste 		 * For objects other than core files, Search for
3344*2c23cb7cSEd Maste 		 * SHT_NOTE sections.
3345*2c23cb7cSEd Maste 		 */
3346*2c23cb7cSEd Maste 		for (i = 0; (size_t) i < re->shnum; i++) {
3347*2c23cb7cSEd Maste 			s = &re->sl[i];
3348*2c23cb7cSEd Maste 			if (s->type == SHT_NOTE) {
3349*2c23cb7cSEd Maste 				(void) elf_errno();
3350*2c23cb7cSEd Maste 				if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3351*2c23cb7cSEd Maste 					elferr = elf_errno();
3352*2c23cb7cSEd Maste 					if (elferr != 0)
3353*2c23cb7cSEd Maste 						warnx("elf_getdata failed: %s",
3354*2c23cb7cSEd Maste 						    elf_errmsg(elferr));
3355*2c23cb7cSEd Maste 					continue;
3356*2c23cb7cSEd Maste 				}
3357*2c23cb7cSEd Maste 				dump_notes_content(re, d->d_buf, d->d_size,
3358*2c23cb7cSEd Maste 				    s->off);
3359*2c23cb7cSEd Maste 			}
3360*2c23cb7cSEd Maste 		}
3361*2c23cb7cSEd Maste 	}
3362*2c23cb7cSEd Maste }
3363*2c23cb7cSEd Maste 
3364*2c23cb7cSEd Maste static void
3365*2c23cb7cSEd Maste dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
3366*2c23cb7cSEd Maste {
3367*2c23cb7cSEd Maste 	Elf_Note *note;
3368*2c23cb7cSEd Maste 	const char *end;
3369*2c23cb7cSEd Maste 
3370*2c23cb7cSEd Maste 	printf("\nNotes at offset %#010jx with length %#010jx:\n",
3371*2c23cb7cSEd Maste 	    (uintmax_t) off, (uintmax_t) sz);
3372*2c23cb7cSEd Maste 	printf("  %-13s %-15s %s\n", "Owner", "Data size", "Description");
3373*2c23cb7cSEd Maste 	end = buf + sz;
3374*2c23cb7cSEd Maste 	while (buf < end) {
3375*2c23cb7cSEd Maste 		note = (Elf_Note *)(uintptr_t) buf;
3376*2c23cb7cSEd Maste 		printf("  %-13s %#010jx", (char *)(uintptr_t) (note + 1),
3377*2c23cb7cSEd Maste 		    (uintmax_t) note->n_descsz);
3378*2c23cb7cSEd Maste 		printf("      %s\n", note_type(re->ehdr.e_ident[EI_OSABI],
3379*2c23cb7cSEd Maste 		    re->ehdr.e_type, note->n_type));
3380*2c23cb7cSEd Maste 		buf += sizeof(Elf_Note);
3381*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32)
3382*2c23cb7cSEd Maste 			buf += roundup2(note->n_namesz, 4) +
3383*2c23cb7cSEd Maste 			    roundup2(note->n_descsz, 4);
3384*2c23cb7cSEd Maste 		else
3385*2c23cb7cSEd Maste 			buf += roundup2(note->n_namesz, 8) +
3386*2c23cb7cSEd Maste 			    roundup2(note->n_descsz, 8);
3387*2c23cb7cSEd Maste 	}
3388*2c23cb7cSEd Maste }
3389*2c23cb7cSEd Maste 
3390*2c23cb7cSEd Maste /*
3391*2c23cb7cSEd Maste  * Symbol versioning sections are the same for 32bit and 64bit
3392*2c23cb7cSEd Maste  * ELF objects.
3393*2c23cb7cSEd Maste  */
3394*2c23cb7cSEd Maste #define Elf_Verdef	Elf32_Verdef
3395*2c23cb7cSEd Maste #define	Elf_Verdaux	Elf32_Verdaux
3396*2c23cb7cSEd Maste #define	Elf_Verneed	Elf32_Verneed
3397*2c23cb7cSEd Maste #define	Elf_Vernaux	Elf32_Vernaux
3398*2c23cb7cSEd Maste 
3399*2c23cb7cSEd Maste #define	SAVE_VERSION_NAME(x, n, t)					\
3400*2c23cb7cSEd Maste 	do {								\
3401*2c23cb7cSEd Maste 		while (x >= re->ver_sz) {				\
3402*2c23cb7cSEd Maste 			nv = realloc(re->ver,				\
3403*2c23cb7cSEd Maste 			    sizeof(*re->ver) * re->ver_sz * 2);		\
3404*2c23cb7cSEd Maste 			if (nv == NULL) {				\
3405*2c23cb7cSEd Maste 				warn("realloc failed");			\
3406*2c23cb7cSEd Maste 				free(re->ver);				\
3407*2c23cb7cSEd Maste 				return;					\
3408*2c23cb7cSEd Maste 			}						\
3409*2c23cb7cSEd Maste 			re->ver = nv;					\
3410*2c23cb7cSEd Maste 			for (i = re->ver_sz; i < re->ver_sz * 2; i++) {	\
3411*2c23cb7cSEd Maste 				re->ver[i].name = NULL;			\
3412*2c23cb7cSEd Maste 				re->ver[i].type = 0;			\
3413*2c23cb7cSEd Maste 			}						\
3414*2c23cb7cSEd Maste 			re->ver_sz *= 2;				\
3415*2c23cb7cSEd Maste 		}							\
3416*2c23cb7cSEd Maste 		if (x > 1) {						\
3417*2c23cb7cSEd Maste 			re->ver[x].name = n;				\
3418*2c23cb7cSEd Maste 			re->ver[x].type = t;				\
3419*2c23cb7cSEd Maste 		}							\
3420*2c23cb7cSEd Maste 	} while (0)
3421*2c23cb7cSEd Maste 
3422*2c23cb7cSEd Maste 
3423*2c23cb7cSEd Maste static void
3424*2c23cb7cSEd Maste dump_verdef(struct readelf *re, int dump)
3425*2c23cb7cSEd Maste {
3426*2c23cb7cSEd Maste 	struct section *s;
3427*2c23cb7cSEd Maste 	struct symver *nv;
3428*2c23cb7cSEd Maste 	Elf_Data *d;
3429*2c23cb7cSEd Maste 	Elf_Verdef *vd;
3430*2c23cb7cSEd Maste 	Elf_Verdaux *vda;
3431*2c23cb7cSEd Maste 	uint8_t *buf, *end, *buf2;
3432*2c23cb7cSEd Maste 	const char *name;
3433*2c23cb7cSEd Maste 	int elferr, i, j;
3434*2c23cb7cSEd Maste 
3435*2c23cb7cSEd Maste 	if ((s = re->vd_s) == NULL)
3436*2c23cb7cSEd Maste 		return;
3437*2c23cb7cSEd Maste 
3438*2c23cb7cSEd Maste 	if (re->ver == NULL) {
3439*2c23cb7cSEd Maste 		re->ver_sz = 16;
3440*2c23cb7cSEd Maste 		if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) ==
3441*2c23cb7cSEd Maste 		    NULL) {
3442*2c23cb7cSEd Maste 			warn("calloc failed");
3443*2c23cb7cSEd Maste 			return;
3444*2c23cb7cSEd Maste 		}
3445*2c23cb7cSEd Maste 		re->ver[0].name = "*local*";
3446*2c23cb7cSEd Maste 		re->ver[1].name = "*global*";
3447*2c23cb7cSEd Maste 	}
3448*2c23cb7cSEd Maste 
3449*2c23cb7cSEd Maste 	if (dump)
3450*2c23cb7cSEd Maste 		printf("\nVersion definition section (%s):\n", s->name);
3451*2c23cb7cSEd Maste 	(void) elf_errno();
3452*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3453*2c23cb7cSEd Maste 		elferr = elf_errno();
3454*2c23cb7cSEd Maste 		if (elferr != 0)
3455*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
3456*2c23cb7cSEd Maste 		return;
3457*2c23cb7cSEd Maste 	}
3458*2c23cb7cSEd Maste 	if (d->d_size == 0)
3459*2c23cb7cSEd Maste 		return;
3460*2c23cb7cSEd Maste 
3461*2c23cb7cSEd Maste 	buf = d->d_buf;
3462*2c23cb7cSEd Maste 	end = buf + d->d_size;
3463*2c23cb7cSEd Maste 	while (buf + sizeof(Elf_Verdef) <= end) {
3464*2c23cb7cSEd Maste 		vd = (Elf_Verdef *) (uintptr_t) buf;
3465*2c23cb7cSEd Maste 		if (dump) {
3466*2c23cb7cSEd Maste 			printf("  0x%4.4lx", (unsigned long)
3467*2c23cb7cSEd Maste 			    (buf - (uint8_t *)d->d_buf));
3468*2c23cb7cSEd Maste 			printf(" vd_version: %u vd_flags: %d"
3469*2c23cb7cSEd Maste 			    " vd_ndx: %u vd_cnt: %u", vd->vd_version,
3470*2c23cb7cSEd Maste 			    vd->vd_flags, vd->vd_ndx, vd->vd_cnt);
3471*2c23cb7cSEd Maste 		}
3472*2c23cb7cSEd Maste 		buf2 = buf + vd->vd_aux;
3473*2c23cb7cSEd Maste 		j = 0;
3474*2c23cb7cSEd Maste 		while (buf2 + sizeof(Elf_Verdaux) <= end && j < vd->vd_cnt) {
3475*2c23cb7cSEd Maste 			vda = (Elf_Verdaux *) (uintptr_t) buf2;
3476*2c23cb7cSEd Maste 			name = get_string(re, s->link, vda->vda_name);
3477*2c23cb7cSEd Maste 			if (j == 0) {
3478*2c23cb7cSEd Maste 				if (dump)
3479*2c23cb7cSEd Maste 					printf(" vda_name: %s\n", name);
3480*2c23cb7cSEd Maste 				SAVE_VERSION_NAME((int)vd->vd_ndx, name, 1);
3481*2c23cb7cSEd Maste 			} else if (dump)
3482*2c23cb7cSEd Maste 				printf("  0x%4.4lx parent: %s\n",
3483*2c23cb7cSEd Maste 				    (unsigned long) (buf2 -
3484*2c23cb7cSEd Maste 				    (uint8_t *)d->d_buf), name);
3485*2c23cb7cSEd Maste 			if (vda->vda_next == 0)
3486*2c23cb7cSEd Maste 				break;
3487*2c23cb7cSEd Maste 			buf2 += vda->vda_next;
3488*2c23cb7cSEd Maste 			j++;
3489*2c23cb7cSEd Maste 		}
3490*2c23cb7cSEd Maste 		if (vd->vd_next == 0)
3491*2c23cb7cSEd Maste 			break;
3492*2c23cb7cSEd Maste 		buf += vd->vd_next;
3493*2c23cb7cSEd Maste 	}
3494*2c23cb7cSEd Maste }
3495*2c23cb7cSEd Maste 
3496*2c23cb7cSEd Maste static void
3497*2c23cb7cSEd Maste dump_verneed(struct readelf *re, int dump)
3498*2c23cb7cSEd Maste {
3499*2c23cb7cSEd Maste 	struct section *s;
3500*2c23cb7cSEd Maste 	struct symver *nv;
3501*2c23cb7cSEd Maste 	Elf_Data *d;
3502*2c23cb7cSEd Maste 	Elf_Verneed *vn;
3503*2c23cb7cSEd Maste 	Elf_Vernaux *vna;
3504*2c23cb7cSEd Maste 	uint8_t *buf, *end, *buf2;
3505*2c23cb7cSEd Maste 	const char *name;
3506*2c23cb7cSEd Maste 	int elferr, i, j;
3507*2c23cb7cSEd Maste 
3508*2c23cb7cSEd Maste 	if ((s = re->vn_s) == NULL)
3509*2c23cb7cSEd Maste 		return;
3510*2c23cb7cSEd Maste 
3511*2c23cb7cSEd Maste 	if (re->ver == NULL) {
3512*2c23cb7cSEd Maste 		re->ver_sz = 16;
3513*2c23cb7cSEd Maste 		if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) ==
3514*2c23cb7cSEd Maste 		    NULL) {
3515*2c23cb7cSEd Maste 			warn("calloc failed");
3516*2c23cb7cSEd Maste 			return;
3517*2c23cb7cSEd Maste 		}
3518*2c23cb7cSEd Maste 		re->ver[0].name = "*local*";
3519*2c23cb7cSEd Maste 		re->ver[1].name = "*global*";
3520*2c23cb7cSEd Maste 	}
3521*2c23cb7cSEd Maste 
3522*2c23cb7cSEd Maste 	if (dump)
3523*2c23cb7cSEd Maste 		printf("\nVersion needed section (%s):\n", s->name);
3524*2c23cb7cSEd Maste 	(void) elf_errno();
3525*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3526*2c23cb7cSEd Maste 		elferr = elf_errno();
3527*2c23cb7cSEd Maste 		if (elferr != 0)
3528*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
3529*2c23cb7cSEd Maste 		return;
3530*2c23cb7cSEd Maste 	}
3531*2c23cb7cSEd Maste 	if (d->d_size == 0)
3532*2c23cb7cSEd Maste 		return;
3533*2c23cb7cSEd Maste 
3534*2c23cb7cSEd Maste 	buf = d->d_buf;
3535*2c23cb7cSEd Maste 	end = buf + d->d_size;
3536*2c23cb7cSEd Maste 	while (buf + sizeof(Elf_Verneed) <= end) {
3537*2c23cb7cSEd Maste 		vn = (Elf_Verneed *) (uintptr_t) buf;
3538*2c23cb7cSEd Maste 		if (dump) {
3539*2c23cb7cSEd Maste 			printf("  0x%4.4lx", (unsigned long)
3540*2c23cb7cSEd Maste 			    (buf - (uint8_t *)d->d_buf));
3541*2c23cb7cSEd Maste 			printf(" vn_version: %u vn_file: %s vn_cnt: %u\n",
3542*2c23cb7cSEd Maste 			    vn->vn_version,
3543*2c23cb7cSEd Maste 			    get_string(re, s->link, vn->vn_file),
3544*2c23cb7cSEd Maste 			    vn->vn_cnt);
3545*2c23cb7cSEd Maste 		}
3546*2c23cb7cSEd Maste 		buf2 = buf + vn->vn_aux;
3547*2c23cb7cSEd Maste 		j = 0;
3548*2c23cb7cSEd Maste 		while (buf2 + sizeof(Elf_Vernaux) <= end && j < vn->vn_cnt) {
3549*2c23cb7cSEd Maste 			vna = (Elf32_Vernaux *) (uintptr_t) buf2;
3550*2c23cb7cSEd Maste 			if (dump)
3551*2c23cb7cSEd Maste 				printf("  0x%4.4lx", (unsigned long)
3552*2c23cb7cSEd Maste 				    (buf2 - (uint8_t *)d->d_buf));
3553*2c23cb7cSEd Maste 			name = get_string(re, s->link, vna->vna_name);
3554*2c23cb7cSEd Maste 			if (dump)
3555*2c23cb7cSEd Maste 				printf("   vna_name: %s vna_flags: %u"
3556*2c23cb7cSEd Maste 				    " vna_other: %u\n", name,
3557*2c23cb7cSEd Maste 				    vna->vna_flags, vna->vna_other);
3558*2c23cb7cSEd Maste 			SAVE_VERSION_NAME((int)vna->vna_other, name, 0);
3559*2c23cb7cSEd Maste 			if (vna->vna_next == 0)
3560*2c23cb7cSEd Maste 				break;
3561*2c23cb7cSEd Maste 			buf2 += vna->vna_next;
3562*2c23cb7cSEd Maste 			j++;
3563*2c23cb7cSEd Maste 		}
3564*2c23cb7cSEd Maste 		if (vn->vn_next == 0)
3565*2c23cb7cSEd Maste 			break;
3566*2c23cb7cSEd Maste 		buf += vn->vn_next;
3567*2c23cb7cSEd Maste 	}
3568*2c23cb7cSEd Maste }
3569*2c23cb7cSEd Maste 
3570*2c23cb7cSEd Maste static void
3571*2c23cb7cSEd Maste dump_versym(struct readelf *re)
3572*2c23cb7cSEd Maste {
3573*2c23cb7cSEd Maste 	int i;
3574*2c23cb7cSEd Maste 
3575*2c23cb7cSEd Maste 	if (re->vs_s == NULL || re->ver == NULL || re->vs == NULL)
3576*2c23cb7cSEd Maste 		return;
3577*2c23cb7cSEd Maste 	printf("\nVersion symbol section (%s):\n", re->vs_s->name);
3578*2c23cb7cSEd Maste 	for (i = 0; i < re->vs_sz; i++) {
3579*2c23cb7cSEd Maste 		if ((i & 3) == 0) {
3580*2c23cb7cSEd Maste 			if (i > 0)
3581*2c23cb7cSEd Maste 				putchar('\n');
3582*2c23cb7cSEd Maste 			printf("  %03x:", i);
3583*2c23cb7cSEd Maste 		}
3584*2c23cb7cSEd Maste 		if (re->vs[i] & 0x8000)
3585*2c23cb7cSEd Maste 			printf(" %3xh %-12s ", re->vs[i] & 0x7fff,
3586*2c23cb7cSEd Maste 			    re->ver[re->vs[i] & 0x7fff].name);
3587*2c23cb7cSEd Maste 		else
3588*2c23cb7cSEd Maste 			printf(" %3x %-12s ", re->vs[i],
3589*2c23cb7cSEd Maste 			    re->ver[re->vs[i]].name);
3590*2c23cb7cSEd Maste 	}
3591*2c23cb7cSEd Maste 	putchar('\n');
3592*2c23cb7cSEd Maste }
3593*2c23cb7cSEd Maste 
3594*2c23cb7cSEd Maste static void
3595*2c23cb7cSEd Maste dump_ver(struct readelf *re)
3596*2c23cb7cSEd Maste {
3597*2c23cb7cSEd Maste 
3598*2c23cb7cSEd Maste 	if (re->vs_s && re->ver && re->vs)
3599*2c23cb7cSEd Maste 		dump_versym(re);
3600*2c23cb7cSEd Maste 	if (re->vd_s)
3601*2c23cb7cSEd Maste 		dump_verdef(re, 1);
3602*2c23cb7cSEd Maste 	if (re->vn_s)
3603*2c23cb7cSEd Maste 		dump_verneed(re, 1);
3604*2c23cb7cSEd Maste }
3605*2c23cb7cSEd Maste 
3606*2c23cb7cSEd Maste static void
3607*2c23cb7cSEd Maste search_ver(struct readelf *re)
3608*2c23cb7cSEd Maste {
3609*2c23cb7cSEd Maste 	struct section *s;
3610*2c23cb7cSEd Maste 	Elf_Data *d;
3611*2c23cb7cSEd Maste 	int elferr, i;
3612*2c23cb7cSEd Maste 
3613*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
3614*2c23cb7cSEd Maste 		s = &re->sl[i];
3615*2c23cb7cSEd Maste 		if (s->type == SHT_SUNW_versym)
3616*2c23cb7cSEd Maste 			re->vs_s = s;
3617*2c23cb7cSEd Maste 		if (s->type == SHT_SUNW_verneed)
3618*2c23cb7cSEd Maste 			re->vn_s = s;
3619*2c23cb7cSEd Maste 		if (s->type == SHT_SUNW_verdef)
3620*2c23cb7cSEd Maste 			re->vd_s = s;
3621*2c23cb7cSEd Maste 	}
3622*2c23cb7cSEd Maste 	if (re->vd_s)
3623*2c23cb7cSEd Maste 		dump_verdef(re, 0);
3624*2c23cb7cSEd Maste 	if (re->vn_s)
3625*2c23cb7cSEd Maste 		dump_verneed(re, 0);
3626*2c23cb7cSEd Maste 	if (re->vs_s && re->ver != NULL) {
3627*2c23cb7cSEd Maste 		(void) elf_errno();
3628*2c23cb7cSEd Maste 		if ((d = elf_getdata(re->vs_s->scn, NULL)) == NULL) {
3629*2c23cb7cSEd Maste 			elferr = elf_errno();
3630*2c23cb7cSEd Maste 			if (elferr != 0)
3631*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s",
3632*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
3633*2c23cb7cSEd Maste 			return;
3634*2c23cb7cSEd Maste 		}
3635*2c23cb7cSEd Maste 		if (d->d_size == 0)
3636*2c23cb7cSEd Maste 			return;
3637*2c23cb7cSEd Maste 		re->vs = d->d_buf;
3638*2c23cb7cSEd Maste 		re->vs_sz = d->d_size / sizeof(Elf32_Half);
3639*2c23cb7cSEd Maste 	}
3640*2c23cb7cSEd Maste }
3641*2c23cb7cSEd Maste 
3642*2c23cb7cSEd Maste #undef	Elf_Verdef
3643*2c23cb7cSEd Maste #undef	Elf_Verdaux
3644*2c23cb7cSEd Maste #undef	Elf_Verneed
3645*2c23cb7cSEd Maste #undef	Elf_Vernaux
3646*2c23cb7cSEd Maste #undef	SAVE_VERSION_NAME
3647*2c23cb7cSEd Maste 
3648*2c23cb7cSEd Maste /*
3649*2c23cb7cSEd Maste  * Elf32_Lib and Elf64_Lib are identical.
3650*2c23cb7cSEd Maste  */
3651*2c23cb7cSEd Maste #define	Elf_Lib		Elf32_Lib
3652*2c23cb7cSEd Maste 
3653*2c23cb7cSEd Maste static void
3654*2c23cb7cSEd Maste dump_liblist(struct readelf *re)
3655*2c23cb7cSEd Maste {
3656*2c23cb7cSEd Maste 	struct section *s;
3657*2c23cb7cSEd Maste 	struct tm *t;
3658*2c23cb7cSEd Maste 	time_t ti;
3659*2c23cb7cSEd Maste 	char tbuf[20];
3660*2c23cb7cSEd Maste 	Elf_Data *d;
3661*2c23cb7cSEd Maste 	Elf_Lib *lib;
3662*2c23cb7cSEd Maste 	int i, j, k, elferr, first;
3663*2c23cb7cSEd Maste 
3664*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
3665*2c23cb7cSEd Maste 		s = &re->sl[i];
3666*2c23cb7cSEd Maste 		if (s->type != SHT_GNU_LIBLIST)
3667*2c23cb7cSEd Maste 			continue;
3668*2c23cb7cSEd Maste 		(void) elf_errno();
3669*2c23cb7cSEd Maste 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
3670*2c23cb7cSEd Maste 			elferr = elf_errno();
3671*2c23cb7cSEd Maste 			if (elferr != 0)
3672*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s",
3673*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
3674*2c23cb7cSEd Maste 			continue;
3675*2c23cb7cSEd Maste 		}
3676*2c23cb7cSEd Maste 		if (d->d_size <= 0)
3677*2c23cb7cSEd Maste 			continue;
3678*2c23cb7cSEd Maste 		lib = d->d_buf;
3679*2c23cb7cSEd Maste 		printf("\nLibrary list section '%s' ", s->name);
3680*2c23cb7cSEd Maste 		printf("contains %ju entries:\n", s->sz / s->entsize);
3681*2c23cb7cSEd Maste 		printf("%12s%24s%18s%10s%6s\n", "Library", "Time Stamp",
3682*2c23cb7cSEd Maste 		    "Checksum", "Version", "Flags");
3683*2c23cb7cSEd Maste 		for (j = 0; (uint64_t) j < s->sz / s->entsize; j++) {
3684*2c23cb7cSEd Maste 			printf("%3d: ", j);
3685*2c23cb7cSEd Maste 			printf("%-20.20s ",
3686*2c23cb7cSEd Maste 			    get_string(re, s->link, lib->l_name));
3687*2c23cb7cSEd Maste 			ti = lib->l_time_stamp;
3688*2c23cb7cSEd Maste 			t = gmtime(&ti);
3689*2c23cb7cSEd Maste 			snprintf(tbuf, sizeof(tbuf), "%04d-%02d-%02dT%02d:%02d"
3690*2c23cb7cSEd Maste 			    ":%2d", t->tm_year + 1900, t->tm_mon + 1,
3691*2c23cb7cSEd Maste 			    t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
3692*2c23cb7cSEd Maste 			printf("%-19.19s ", tbuf);
3693*2c23cb7cSEd Maste 			printf("0x%08x ", lib->l_checksum);
3694*2c23cb7cSEd Maste 			printf("%-7d %#x", lib->l_version, lib->l_flags);
3695*2c23cb7cSEd Maste 			if (lib->l_flags != 0) {
3696*2c23cb7cSEd Maste 				first = 1;
3697*2c23cb7cSEd Maste 				putchar('(');
3698*2c23cb7cSEd Maste 				for (k = 0; l_flag[k].name != NULL; k++) {
3699*2c23cb7cSEd Maste 					if ((l_flag[k].value & lib->l_flags) ==
3700*2c23cb7cSEd Maste 					    0)
3701*2c23cb7cSEd Maste 						continue;
3702*2c23cb7cSEd Maste 					if (!first)
3703*2c23cb7cSEd Maste 						putchar(',');
3704*2c23cb7cSEd Maste 					else
3705*2c23cb7cSEd Maste 						first = 0;
3706*2c23cb7cSEd Maste 					printf("%s", l_flag[k].name);
3707*2c23cb7cSEd Maste 				}
3708*2c23cb7cSEd Maste 				putchar(')');
3709*2c23cb7cSEd Maste 			}
3710*2c23cb7cSEd Maste 			putchar('\n');
3711*2c23cb7cSEd Maste 			lib++;
3712*2c23cb7cSEd Maste 		}
3713*2c23cb7cSEd Maste 	}
3714*2c23cb7cSEd Maste }
3715*2c23cb7cSEd Maste 
3716*2c23cb7cSEd Maste #undef Elf_Lib
3717*2c23cb7cSEd Maste 
3718*2c23cb7cSEd Maste static uint8_t *
3719*2c23cb7cSEd Maste dump_unknown_tag(uint64_t tag, uint8_t *p)
3720*2c23cb7cSEd Maste {
3721*2c23cb7cSEd Maste 	uint64_t val;
3722*2c23cb7cSEd Maste 
3723*2c23cb7cSEd Maste 	/*
3724*2c23cb7cSEd Maste 	 * According to ARM EABI: For tags > 32, even numbered tags have
3725*2c23cb7cSEd Maste 	 * a ULEB128 param and odd numbered ones have NUL-terminated
3726*2c23cb7cSEd Maste 	 * string param. This rule probably also applies for tags <= 32
3727*2c23cb7cSEd Maste 	 * if the object arch is not ARM.
3728*2c23cb7cSEd Maste 	 */
3729*2c23cb7cSEd Maste 
3730*2c23cb7cSEd Maste 	printf("  Tag_unknown_%ju: ", (uintmax_t) tag);
3731*2c23cb7cSEd Maste 
3732*2c23cb7cSEd Maste 	if (tag & 1) {
3733*2c23cb7cSEd Maste 		printf("%s\n", (char *) p);
3734*2c23cb7cSEd Maste 		p += strlen((char *) p) + 1;
3735*2c23cb7cSEd Maste 	} else {
3736*2c23cb7cSEd Maste 		val = _decode_uleb128(&p);
3737*2c23cb7cSEd Maste 		printf("%ju\n", (uintmax_t) val);
3738*2c23cb7cSEd Maste 	}
3739*2c23cb7cSEd Maste 
3740*2c23cb7cSEd Maste 	return (p);
3741*2c23cb7cSEd Maste }
3742*2c23cb7cSEd Maste 
3743*2c23cb7cSEd Maste static uint8_t *
3744*2c23cb7cSEd Maste dump_compatibility_tag(uint8_t *p)
3745*2c23cb7cSEd Maste {
3746*2c23cb7cSEd Maste 	uint64_t val;
3747*2c23cb7cSEd Maste 
3748*2c23cb7cSEd Maste 	val = _decode_uleb128(&p);
3749*2c23cb7cSEd Maste 	printf("flag = %ju, vendor = %s\n", val, p);
3750*2c23cb7cSEd Maste 	p += strlen((char *) p) + 1;
3751*2c23cb7cSEd Maste 
3752*2c23cb7cSEd Maste 	return (p);
3753*2c23cb7cSEd Maste }
3754*2c23cb7cSEd Maste 
3755*2c23cb7cSEd Maste static void
3756*2c23cb7cSEd Maste dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe)
3757*2c23cb7cSEd Maste {
3758*2c23cb7cSEd Maste 	uint64_t tag, val;
3759*2c23cb7cSEd Maste 	size_t i;
3760*2c23cb7cSEd Maste 	int found, desc;
3761*2c23cb7cSEd Maste 
3762*2c23cb7cSEd Maste 	(void) re;
3763*2c23cb7cSEd Maste 
3764*2c23cb7cSEd Maste 	while (p < pe) {
3765*2c23cb7cSEd Maste 		tag = _decode_uleb128(&p);
3766*2c23cb7cSEd Maste 		found = desc = 0;
3767*2c23cb7cSEd Maste 		for (i = 0; i < sizeof(aeabi_tags) / sizeof(aeabi_tags[0]);
3768*2c23cb7cSEd Maste 		     i++) {
3769*2c23cb7cSEd Maste 			if (tag == aeabi_tags[i].tag) {
3770*2c23cb7cSEd Maste 				found = 1;
3771*2c23cb7cSEd Maste 				printf("  %s: ", aeabi_tags[i].s_tag);
3772*2c23cb7cSEd Maste 				if (aeabi_tags[i].get_desc) {
3773*2c23cb7cSEd Maste 					desc = 1;
3774*2c23cb7cSEd Maste 					val = _decode_uleb128(&p);
3775*2c23cb7cSEd Maste 					printf("%s\n",
3776*2c23cb7cSEd Maste 					    aeabi_tags[i].get_desc(val));
3777*2c23cb7cSEd Maste 				}
3778*2c23cb7cSEd Maste 				break;
3779*2c23cb7cSEd Maste 			}
3780*2c23cb7cSEd Maste 			if (tag < aeabi_tags[i].tag)
3781*2c23cb7cSEd Maste 				break;
3782*2c23cb7cSEd Maste 		}
3783*2c23cb7cSEd Maste 		if (!found) {
3784*2c23cb7cSEd Maste 			p = dump_unknown_tag(tag, p);
3785*2c23cb7cSEd Maste 			continue;
3786*2c23cb7cSEd Maste 		}
3787*2c23cb7cSEd Maste 		if (desc)
3788*2c23cb7cSEd Maste 			continue;
3789*2c23cb7cSEd Maste 
3790*2c23cb7cSEd Maste 		switch (tag) {
3791*2c23cb7cSEd Maste 		case 4:		/* Tag_CPU_raw_name */
3792*2c23cb7cSEd Maste 		case 5:		/* Tag_CPU_name */
3793*2c23cb7cSEd Maste 		case 67:	/* Tag_conformance */
3794*2c23cb7cSEd Maste 			printf("%s\n", (char *) p);
3795*2c23cb7cSEd Maste 			p += strlen((char *) p) + 1;
3796*2c23cb7cSEd Maste 			break;
3797*2c23cb7cSEd Maste 		case 32:	/* Tag_compatibility */
3798*2c23cb7cSEd Maste 			p = dump_compatibility_tag(p);
3799*2c23cb7cSEd Maste 			break;
3800*2c23cb7cSEd Maste 		case 64:	/* Tag_nodefaults */
3801*2c23cb7cSEd Maste 			/* ignored, written as 0. */
3802*2c23cb7cSEd Maste 			(void) _decode_uleb128(&p);
3803*2c23cb7cSEd Maste 			printf("True\n");
3804*2c23cb7cSEd Maste 			break;
3805*2c23cb7cSEd Maste 		case 65:	/* Tag_also_compatible_with */
3806*2c23cb7cSEd Maste 			val = _decode_uleb128(&p);
3807*2c23cb7cSEd Maste 			/* Must be Tag_CPU_arch */
3808*2c23cb7cSEd Maste 			if (val != 6) {
3809*2c23cb7cSEd Maste 				printf("unknown\n");
3810*2c23cb7cSEd Maste 				break;
3811*2c23cb7cSEd Maste 			}
3812*2c23cb7cSEd Maste 			val = _decode_uleb128(&p);
3813*2c23cb7cSEd Maste 			printf("%s\n", aeabi_cpu_arch(val));
3814*2c23cb7cSEd Maste 			/* Skip NUL terminator. */
3815*2c23cb7cSEd Maste 			p++;
3816*2c23cb7cSEd Maste 			break;
3817*2c23cb7cSEd Maste 		default:
3818*2c23cb7cSEd Maste 			putchar('\n');
3819*2c23cb7cSEd Maste 			break;
3820*2c23cb7cSEd Maste 		}
3821*2c23cb7cSEd Maste 	}
3822*2c23cb7cSEd Maste }
3823*2c23cb7cSEd Maste 
3824*2c23cb7cSEd Maste #ifndef	Tag_GNU_MIPS_ABI_FP
3825*2c23cb7cSEd Maste #define	Tag_GNU_MIPS_ABI_FP	4
3826*2c23cb7cSEd Maste #endif
3827*2c23cb7cSEd Maste 
3828*2c23cb7cSEd Maste static void
3829*2c23cb7cSEd Maste dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe)
3830*2c23cb7cSEd Maste {
3831*2c23cb7cSEd Maste 	uint64_t tag, val;
3832*2c23cb7cSEd Maste 
3833*2c23cb7cSEd Maste 	(void) re;
3834*2c23cb7cSEd Maste 
3835*2c23cb7cSEd Maste 	while (p < pe) {
3836*2c23cb7cSEd Maste 		tag = _decode_uleb128(&p);
3837*2c23cb7cSEd Maste 		switch (tag) {
3838*2c23cb7cSEd Maste 		case Tag_GNU_MIPS_ABI_FP:
3839*2c23cb7cSEd Maste 			val = _decode_uleb128(&p);
3840*2c23cb7cSEd Maste 			printf("  Tag_GNU_MIPS_ABI_FP: %s\n", mips_abi_fp(val));
3841*2c23cb7cSEd Maste 			break;
3842*2c23cb7cSEd Maste 		case 32:	/* Tag_compatibility */
3843*2c23cb7cSEd Maste 			p = dump_compatibility_tag(p);
3844*2c23cb7cSEd Maste 			break;
3845*2c23cb7cSEd Maste 		default:
3846*2c23cb7cSEd Maste 			p = dump_unknown_tag(tag, p);
3847*2c23cb7cSEd Maste 			break;
3848*2c23cb7cSEd Maste 		}
3849*2c23cb7cSEd Maste 	}
3850*2c23cb7cSEd Maste }
3851*2c23cb7cSEd Maste 
3852*2c23cb7cSEd Maste #ifndef Tag_GNU_Power_ABI_FP
3853*2c23cb7cSEd Maste #define	Tag_GNU_Power_ABI_FP	4
3854*2c23cb7cSEd Maste #endif
3855*2c23cb7cSEd Maste 
3856*2c23cb7cSEd Maste #ifndef Tag_GNU_Power_ABI_Vector
3857*2c23cb7cSEd Maste #define	Tag_GNU_Power_ABI_Vector	8
3858*2c23cb7cSEd Maste #endif
3859*2c23cb7cSEd Maste 
3860*2c23cb7cSEd Maste static void
3861*2c23cb7cSEd Maste dump_ppc_attributes(uint8_t *p, uint8_t *pe)
3862*2c23cb7cSEd Maste {
3863*2c23cb7cSEd Maste 	uint64_t tag, val;
3864*2c23cb7cSEd Maste 
3865*2c23cb7cSEd Maste 	while (p < pe) {
3866*2c23cb7cSEd Maste 		tag = _decode_uleb128(&p);
3867*2c23cb7cSEd Maste 		switch (tag) {
3868*2c23cb7cSEd Maste 		case Tag_GNU_Power_ABI_FP:
3869*2c23cb7cSEd Maste 			val = _decode_uleb128(&p);
3870*2c23cb7cSEd Maste 			printf("  Tag_GNU_Power_ABI_FP: %s\n", ppc_abi_fp(val));
3871*2c23cb7cSEd Maste 			break;
3872*2c23cb7cSEd Maste 		case Tag_GNU_Power_ABI_Vector:
3873*2c23cb7cSEd Maste 			val = _decode_uleb128(&p);
3874*2c23cb7cSEd Maste 			printf("  Tag_GNU_Power_ABI_Vector: %s\n",
3875*2c23cb7cSEd Maste 			    ppc_abi_vector(val));
3876*2c23cb7cSEd Maste 			break;
3877*2c23cb7cSEd Maste 		case 32:	/* Tag_compatibility */
3878*2c23cb7cSEd Maste 			p = dump_compatibility_tag(p);
3879*2c23cb7cSEd Maste 			break;
3880*2c23cb7cSEd Maste 		default:
3881*2c23cb7cSEd Maste 			p = dump_unknown_tag(tag, p);
3882*2c23cb7cSEd Maste 			break;
3883*2c23cb7cSEd Maste 		}
3884*2c23cb7cSEd Maste 	}
3885*2c23cb7cSEd Maste }
3886*2c23cb7cSEd Maste 
3887*2c23cb7cSEd Maste static void
3888*2c23cb7cSEd Maste dump_attributes(struct readelf *re)
3889*2c23cb7cSEd Maste {
3890*2c23cb7cSEd Maste 	struct section *s;
3891*2c23cb7cSEd Maste 	Elf_Data *d;
3892*2c23cb7cSEd Maste 	uint8_t *p, *sp;
3893*2c23cb7cSEd Maste 	size_t len, seclen, nlen, sublen;
3894*2c23cb7cSEd Maste 	uint64_t val;
3895*2c23cb7cSEd Maste 	int tag, i, elferr;
3896*2c23cb7cSEd Maste 
3897*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
3898*2c23cb7cSEd Maste 		s = &re->sl[i];
3899*2c23cb7cSEd Maste 		if (s->type != SHT_GNU_ATTRIBUTES &&
3900*2c23cb7cSEd Maste 		    (re->ehdr.e_machine != EM_ARM || s->type != SHT_LOPROC + 3))
3901*2c23cb7cSEd Maste 			continue;
3902*2c23cb7cSEd Maste 		(void) elf_errno();
3903*2c23cb7cSEd Maste 		if ((d = elf_rawdata(s->scn, NULL)) == NULL) {
3904*2c23cb7cSEd Maste 			elferr = elf_errno();
3905*2c23cb7cSEd Maste 			if (elferr != 0)
3906*2c23cb7cSEd Maste 				warnx("elf_rawdata failed: %s",
3907*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
3908*2c23cb7cSEd Maste 			continue;
3909*2c23cb7cSEd Maste 		}
3910*2c23cb7cSEd Maste 		if (d->d_size <= 0)
3911*2c23cb7cSEd Maste 			continue;
3912*2c23cb7cSEd Maste 		p = d->d_buf;
3913*2c23cb7cSEd Maste 		if (*p != 'A') {
3914*2c23cb7cSEd Maste 			printf("Unknown Attribute Section Format: %c\n",
3915*2c23cb7cSEd Maste 			    (char) *p);
3916*2c23cb7cSEd Maste 			continue;
3917*2c23cb7cSEd Maste 		}
3918*2c23cb7cSEd Maste 		len = d->d_size - 1;
3919*2c23cb7cSEd Maste 		p++;
3920*2c23cb7cSEd Maste 		while (len > 0) {
3921*2c23cb7cSEd Maste 			seclen = re->dw_decode(&p, 4);
3922*2c23cb7cSEd Maste 			if (seclen > len) {
3923*2c23cb7cSEd Maste 				warnx("invalid attribute section length");
3924*2c23cb7cSEd Maste 				break;
3925*2c23cb7cSEd Maste 			}
3926*2c23cb7cSEd Maste 			len -= seclen;
3927*2c23cb7cSEd Maste 			printf("Attribute Section: %s\n", (char *) p);
3928*2c23cb7cSEd Maste 			nlen = strlen((char *) p) + 1;
3929*2c23cb7cSEd Maste 			p += nlen;
3930*2c23cb7cSEd Maste 			seclen -= nlen + 4;
3931*2c23cb7cSEd Maste 			while (seclen > 0) {
3932*2c23cb7cSEd Maste 				sp = p;
3933*2c23cb7cSEd Maste 				tag = *p++;
3934*2c23cb7cSEd Maste 				sublen = re->dw_decode(&p, 4);
3935*2c23cb7cSEd Maste 				if (sublen > seclen) {
3936*2c23cb7cSEd Maste 					warnx("invalid attribute sub-section"
3937*2c23cb7cSEd Maste 					    " length");
3938*2c23cb7cSEd Maste 					break;
3939*2c23cb7cSEd Maste 				}
3940*2c23cb7cSEd Maste 				seclen -= sublen;
3941*2c23cb7cSEd Maste 				printf("%s", top_tag(tag));
3942*2c23cb7cSEd Maste 				if (tag == 2 || tag == 3) {
3943*2c23cb7cSEd Maste 					putchar(':');
3944*2c23cb7cSEd Maste 					for (;;) {
3945*2c23cb7cSEd Maste 						val = _decode_uleb128(&p);
3946*2c23cb7cSEd Maste 						if (val == 0)
3947*2c23cb7cSEd Maste 							break;
3948*2c23cb7cSEd Maste 						printf(" %ju", (uintmax_t) val);
3949*2c23cb7cSEd Maste 					}
3950*2c23cb7cSEd Maste 				}
3951*2c23cb7cSEd Maste 				putchar('\n');
3952*2c23cb7cSEd Maste 				if (re->ehdr.e_machine == EM_ARM &&
3953*2c23cb7cSEd Maste 				    s->type == SHT_LOPROC + 3)
3954*2c23cb7cSEd Maste 					dump_arm_attributes(re, p, sp + sublen);
3955*2c23cb7cSEd Maste 				else if (re->ehdr.e_machine == EM_MIPS ||
3956*2c23cb7cSEd Maste 				    re->ehdr.e_machine == EM_MIPS_RS3_LE)
3957*2c23cb7cSEd Maste 					dump_mips_attributes(re, p,
3958*2c23cb7cSEd Maste 					    sp + sublen);
3959*2c23cb7cSEd Maste 				else if (re->ehdr.e_machine == EM_PPC)
3960*2c23cb7cSEd Maste 					dump_ppc_attributes(p, sp + sublen);
3961*2c23cb7cSEd Maste 				p = sp + sublen;
3962*2c23cb7cSEd Maste 			}
3963*2c23cb7cSEd Maste 		}
3964*2c23cb7cSEd Maste 	}
3965*2c23cb7cSEd Maste }
3966*2c23cb7cSEd Maste 
3967*2c23cb7cSEd Maste static void
3968*2c23cb7cSEd Maste dump_mips_specific_info(struct readelf *re)
3969*2c23cb7cSEd Maste {
3970*2c23cb7cSEd Maste 	struct section *s;
3971*2c23cb7cSEd Maste 	int i, options_found;
3972*2c23cb7cSEd Maste 
3973*2c23cb7cSEd Maste 	options_found = 0;
3974*2c23cb7cSEd Maste 	s = NULL;
3975*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
3976*2c23cb7cSEd Maste 		s = &re->sl[i];
3977*2c23cb7cSEd Maste 		if (s->name != NULL && (!strcmp(s->name, ".MIPS.options") ||
3978*2c23cb7cSEd Maste 		    (s->type == SHT_MIPS_OPTIONS))) {
3979*2c23cb7cSEd Maste 			dump_mips_options(re, s);
3980*2c23cb7cSEd Maste 			options_found = 1;
3981*2c23cb7cSEd Maste 		}
3982*2c23cb7cSEd Maste 	}
3983*2c23cb7cSEd Maste 
3984*2c23cb7cSEd Maste 	/*
3985*2c23cb7cSEd Maste 	 * According to SGI mips64 spec, .reginfo should be ignored if
3986*2c23cb7cSEd Maste 	 * .MIPS.options section is present.
3987*2c23cb7cSEd Maste 	 */
3988*2c23cb7cSEd Maste 	if (!options_found) {
3989*2c23cb7cSEd Maste 		for (i = 0; (size_t) i < re->shnum; i++) {
3990*2c23cb7cSEd Maste 			s = &re->sl[i];
3991*2c23cb7cSEd Maste 			if (s->name != NULL && (!strcmp(s->name, ".reginfo") ||
3992*2c23cb7cSEd Maste 			    (s->type == SHT_MIPS_REGINFO)))
3993*2c23cb7cSEd Maste 				dump_mips_reginfo(re, s);
3994*2c23cb7cSEd Maste 		}
3995*2c23cb7cSEd Maste 	}
3996*2c23cb7cSEd Maste }
3997*2c23cb7cSEd Maste 
3998*2c23cb7cSEd Maste static void
3999*2c23cb7cSEd Maste dump_mips_reginfo(struct readelf *re, struct section *s)
4000*2c23cb7cSEd Maste {
4001*2c23cb7cSEd Maste 	Elf_Data *d;
4002*2c23cb7cSEd Maste 	int elferr;
4003*2c23cb7cSEd Maste 
4004*2c23cb7cSEd Maste 	(void) elf_errno();
4005*2c23cb7cSEd Maste 	if ((d = elf_rawdata(s->scn, NULL)) == NULL) {
4006*2c23cb7cSEd Maste 		elferr = elf_errno();
4007*2c23cb7cSEd Maste 		if (elferr != 0)
4008*2c23cb7cSEd Maste 			warnx("elf_rawdata failed: %s",
4009*2c23cb7cSEd Maste 			    elf_errmsg(elferr));
4010*2c23cb7cSEd Maste 		return;
4011*2c23cb7cSEd Maste 	}
4012*2c23cb7cSEd Maste 	if (d->d_size <= 0)
4013*2c23cb7cSEd Maste 		return;
4014*2c23cb7cSEd Maste 
4015*2c23cb7cSEd Maste 	printf("\nSection '%s' contains %ju entries:\n", s->name,
4016*2c23cb7cSEd Maste 	    s->sz / s->entsize);
4017*2c23cb7cSEd Maste 	dump_mips_odk_reginfo(re, d->d_buf, d->d_size);
4018*2c23cb7cSEd Maste }
4019*2c23cb7cSEd Maste 
4020*2c23cb7cSEd Maste static void
4021*2c23cb7cSEd Maste dump_mips_options(struct readelf *re, struct section *s)
4022*2c23cb7cSEd Maste {
4023*2c23cb7cSEd Maste 	Elf_Data *d;
4024*2c23cb7cSEd Maste 	uint32_t info;
4025*2c23cb7cSEd Maste 	uint16_t sndx;
4026*2c23cb7cSEd Maste 	uint8_t *p, *pe;
4027*2c23cb7cSEd Maste 	uint8_t kind, size;
4028*2c23cb7cSEd Maste 	int elferr;
4029*2c23cb7cSEd Maste 
4030*2c23cb7cSEd Maste 	(void) elf_errno();
4031*2c23cb7cSEd Maste 	if ((d = elf_rawdata(s->scn, NULL)) == NULL) {
4032*2c23cb7cSEd Maste 		elferr = elf_errno();
4033*2c23cb7cSEd Maste 		if (elferr != 0)
4034*2c23cb7cSEd Maste 			warnx("elf_rawdata failed: %s",
4035*2c23cb7cSEd Maste 			    elf_errmsg(elferr));
4036*2c23cb7cSEd Maste 		return;
4037*2c23cb7cSEd Maste 	}
4038*2c23cb7cSEd Maste 	if (d->d_size == 0)
4039*2c23cb7cSEd Maste 		return;
4040*2c23cb7cSEd Maste 
4041*2c23cb7cSEd Maste 	printf("\nSection %s contains:\n", s->name);
4042*2c23cb7cSEd Maste 	p = d->d_buf;
4043*2c23cb7cSEd Maste 	pe = p + d->d_size;
4044*2c23cb7cSEd Maste 	while (p < pe) {
4045*2c23cb7cSEd Maste 		kind = re->dw_decode(&p, 1);
4046*2c23cb7cSEd Maste 		size = re->dw_decode(&p, 1);
4047*2c23cb7cSEd Maste 		sndx = re->dw_decode(&p, 2);
4048*2c23cb7cSEd Maste 		info = re->dw_decode(&p, 4);
4049*2c23cb7cSEd Maste 		switch (kind) {
4050*2c23cb7cSEd Maste 		case ODK_REGINFO:
4051*2c23cb7cSEd Maste 			dump_mips_odk_reginfo(re, p, size - 8);
4052*2c23cb7cSEd Maste 			break;
4053*2c23cb7cSEd Maste 		case ODK_EXCEPTIONS:
4054*2c23cb7cSEd Maste 			printf(" EXCEPTIONS FPU_MIN: %#x\n",
4055*2c23cb7cSEd Maste 			    info & OEX_FPU_MIN);
4056*2c23cb7cSEd Maste 			printf("%11.11s FPU_MAX: %#x\n", "",
4057*2c23cb7cSEd Maste 			    info & OEX_FPU_MAX);
4058*2c23cb7cSEd Maste 			dump_mips_option_flags("", mips_exceptions_option,
4059*2c23cb7cSEd Maste 			    info);
4060*2c23cb7cSEd Maste 			break;
4061*2c23cb7cSEd Maste 		case ODK_PAD:
4062*2c23cb7cSEd Maste 			printf(" %-10.10s section: %ju\n", "OPAD",
4063*2c23cb7cSEd Maste 			    (uintmax_t) sndx);
4064*2c23cb7cSEd Maste 			dump_mips_option_flags("", mips_pad_option, info);
4065*2c23cb7cSEd Maste 			break;
4066*2c23cb7cSEd Maste 		case ODK_HWPATCH:
4067*2c23cb7cSEd Maste 			dump_mips_option_flags("HWPATCH", mips_hwpatch_option,
4068*2c23cb7cSEd Maste 			    info);
4069*2c23cb7cSEd Maste 			break;
4070*2c23cb7cSEd Maste 		case ODK_HWAND:
4071*2c23cb7cSEd Maste 			dump_mips_option_flags("HWAND", mips_hwa_option, info);
4072*2c23cb7cSEd Maste 			break;
4073*2c23cb7cSEd Maste 		case ODK_HWOR:
4074*2c23cb7cSEd Maste 			dump_mips_option_flags("HWOR", mips_hwo_option, info);
4075*2c23cb7cSEd Maste 			break;
4076*2c23cb7cSEd Maste 		case ODK_FILL:
4077*2c23cb7cSEd Maste 			printf(" %-10.10s %#jx\n", "FILL", (uintmax_t) info);
4078*2c23cb7cSEd Maste 			break;
4079*2c23cb7cSEd Maste 		case ODK_TAGS:
4080*2c23cb7cSEd Maste 			printf(" %-10.10s\n", "TAGS");
4081*2c23cb7cSEd Maste 			break;
4082*2c23cb7cSEd Maste 		case ODK_GP_GROUP:
4083*2c23cb7cSEd Maste 			printf(" %-10.10s GP group number: %#x\n", "GP_GROUP",
4084*2c23cb7cSEd Maste 			    info & 0xFFFF);
4085*2c23cb7cSEd Maste 			if (info & 0x10000)
4086*2c23cb7cSEd Maste 				printf(" %-10.10s GP group is "
4087*2c23cb7cSEd Maste 				    "self-contained\n", "");
4088*2c23cb7cSEd Maste 			break;
4089*2c23cb7cSEd Maste 		case ODK_IDENT:
4090*2c23cb7cSEd Maste 			printf(" %-10.10s default GP group number: %#x\n",
4091*2c23cb7cSEd Maste 			    "IDENT", info & 0xFFFF);
4092*2c23cb7cSEd Maste 			if (info & 0x10000)
4093*2c23cb7cSEd Maste 				printf(" %-10.10s default GP group is "
4094*2c23cb7cSEd Maste 				    "self-contained\n", "");
4095*2c23cb7cSEd Maste 			break;
4096*2c23cb7cSEd Maste 		case ODK_PAGESIZE:
4097*2c23cb7cSEd Maste 			printf(" %-10.10s\n", "PAGESIZE");
4098*2c23cb7cSEd Maste 			break;
4099*2c23cb7cSEd Maste 		default:
4100*2c23cb7cSEd Maste 			break;
4101*2c23cb7cSEd Maste 		}
4102*2c23cb7cSEd Maste 		p += size - 8;
4103*2c23cb7cSEd Maste 	}
4104*2c23cb7cSEd Maste }
4105*2c23cb7cSEd Maste 
4106*2c23cb7cSEd Maste static void
4107*2c23cb7cSEd Maste dump_mips_option_flags(const char *name, struct mips_option *opt, uint64_t info)
4108*2c23cb7cSEd Maste {
4109*2c23cb7cSEd Maste 	int first;
4110*2c23cb7cSEd Maste 
4111*2c23cb7cSEd Maste 	first = 1;
4112*2c23cb7cSEd Maste 	for (; opt->desc != NULL; opt++) {
4113*2c23cb7cSEd Maste 		if (info & opt->flag) {
4114*2c23cb7cSEd Maste 			printf(" %-10.10s %s\n", first ? name : "",
4115*2c23cb7cSEd Maste 			    opt->desc);
4116*2c23cb7cSEd Maste 			first = 0;
4117*2c23cb7cSEd Maste 		}
4118*2c23cb7cSEd Maste 	}
4119*2c23cb7cSEd Maste }
4120*2c23cb7cSEd Maste 
4121*2c23cb7cSEd Maste static void
4122*2c23cb7cSEd Maste dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz)
4123*2c23cb7cSEd Maste {
4124*2c23cb7cSEd Maste 	uint32_t ri_gprmask;
4125*2c23cb7cSEd Maste 	uint32_t ri_cprmask[4];
4126*2c23cb7cSEd Maste 	uint64_t ri_gp_value;
4127*2c23cb7cSEd Maste 	uint8_t *pe;
4128*2c23cb7cSEd Maste 	int i;
4129*2c23cb7cSEd Maste 
4130*2c23cb7cSEd Maste 	pe = p + sz;
4131*2c23cb7cSEd Maste 	while (p < pe) {
4132*2c23cb7cSEd Maste 		ri_gprmask = re->dw_decode(&p, 4);
4133*2c23cb7cSEd Maste 		/* Skip ri_pad padding field for mips64. */
4134*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS64)
4135*2c23cb7cSEd Maste 			re->dw_decode(&p, 4);
4136*2c23cb7cSEd Maste 		for (i = 0; i < 4; i++)
4137*2c23cb7cSEd Maste 			ri_cprmask[i] = re->dw_decode(&p, 4);
4138*2c23cb7cSEd Maste 		if (re->ec == ELFCLASS32)
4139*2c23cb7cSEd Maste 			ri_gp_value = re->dw_decode(&p, 4);
4140*2c23cb7cSEd Maste 		else
4141*2c23cb7cSEd Maste 			ri_gp_value = re->dw_decode(&p, 8);
4142*2c23cb7cSEd Maste 		printf(" %s    ", option_kind(ODK_REGINFO));
4143*2c23cb7cSEd Maste 		printf("ri_gprmask:    0x%08jx\n", (uintmax_t) ri_gprmask);
4144*2c23cb7cSEd Maste 		for (i = 0; i < 4; i++)
4145*2c23cb7cSEd Maste 			printf("%11.11s ri_cprmask[%d]: 0x%08jx\n", "", i,
4146*2c23cb7cSEd Maste 			    (uintmax_t) ri_cprmask[i]);
4147*2c23cb7cSEd Maste 		printf("%12.12s", "");
4148*2c23cb7cSEd Maste 		printf("ri_gp_value:   %#jx\n", (uintmax_t) ri_gp_value);
4149*2c23cb7cSEd Maste 	}
4150*2c23cb7cSEd Maste }
4151*2c23cb7cSEd Maste 
4152*2c23cb7cSEd Maste static void
4153*2c23cb7cSEd Maste dump_arch_specific_info(struct readelf *re)
4154*2c23cb7cSEd Maste {
4155*2c23cb7cSEd Maste 
4156*2c23cb7cSEd Maste 	dump_liblist(re);
4157*2c23cb7cSEd Maste 	dump_attributes(re);
4158*2c23cb7cSEd Maste 
4159*2c23cb7cSEd Maste 	switch (re->ehdr.e_machine) {
4160*2c23cb7cSEd Maste 	case EM_MIPS:
4161*2c23cb7cSEd Maste 	case EM_MIPS_RS3_LE:
4162*2c23cb7cSEd Maste 		dump_mips_specific_info(re);
4163*2c23cb7cSEd Maste 	default:
4164*2c23cb7cSEd Maste 		break;
4165*2c23cb7cSEd Maste 	}
4166*2c23cb7cSEd Maste }
4167*2c23cb7cSEd Maste 
4168*2c23cb7cSEd Maste static void
4169*2c23cb7cSEd Maste dump_dwarf_line(struct readelf *re)
4170*2c23cb7cSEd Maste {
4171*2c23cb7cSEd Maste 	struct section *s;
4172*2c23cb7cSEd Maste 	Dwarf_Die die;
4173*2c23cb7cSEd Maste 	Dwarf_Error de;
4174*2c23cb7cSEd Maste 	Dwarf_Half tag, version, pointer_size;
4175*2c23cb7cSEd Maste 	Dwarf_Unsigned offset, endoff, length, hdrlen, dirndx, mtime, fsize;
4176*2c23cb7cSEd Maste 	Dwarf_Small minlen, defstmt, lrange, opbase, oplen;
4177*2c23cb7cSEd Maste 	Elf_Data *d;
4178*2c23cb7cSEd Maste 	char *pn;
4179*2c23cb7cSEd Maste 	uint64_t address, file, line, column, isa, opsize, udelta;
4180*2c23cb7cSEd Maste 	int64_t sdelta;
4181*2c23cb7cSEd Maste 	uint8_t *p, *pe;
4182*2c23cb7cSEd Maste 	int8_t lbase;
4183*2c23cb7cSEd Maste 	int is_stmt, basic_block, end_sequence;
4184*2c23cb7cSEd Maste 	int prologue_end, epilogue_begin;
4185*2c23cb7cSEd Maste 	int i, dwarf_size, elferr, ret;
4186*2c23cb7cSEd Maste 
4187*2c23cb7cSEd Maste 	printf("\nDump of debug contents of section .debug_line:\n");
4188*2c23cb7cSEd Maste 
4189*2c23cb7cSEd Maste 	s = NULL;
4190*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
4191*2c23cb7cSEd Maste 		s = &re->sl[i];
4192*2c23cb7cSEd Maste 		if (s->name != NULL && !strcmp(s->name, ".debug_line"))
4193*2c23cb7cSEd Maste 			break;
4194*2c23cb7cSEd Maste 	}
4195*2c23cb7cSEd Maste 	if ((size_t) i >= re->shnum)
4196*2c23cb7cSEd Maste 		return;
4197*2c23cb7cSEd Maste 
4198*2c23cb7cSEd Maste 	(void) elf_errno();
4199*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
4200*2c23cb7cSEd Maste 		elferr = elf_errno();
4201*2c23cb7cSEd Maste 		if (elferr != 0)
4202*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(-1));
4203*2c23cb7cSEd Maste 		return;
4204*2c23cb7cSEd Maste 	}
4205*2c23cb7cSEd Maste 	if (d->d_size <= 0)
4206*2c23cb7cSEd Maste 		return;
4207*2c23cb7cSEd Maste 
4208*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,
4209*2c23cb7cSEd Maste 	    NULL, &de)) ==  DW_DLV_OK) {
4210*2c23cb7cSEd Maste 		die = NULL;
4211*2c23cb7cSEd Maste 		while (dwarf_siblingof(re->dbg, die, &die, &de) == DW_DLV_OK) {
4212*2c23cb7cSEd Maste 			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
4213*2c23cb7cSEd Maste 				warnx("dwarf_tag failed: %s",
4214*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4215*2c23cb7cSEd Maste 				return;
4216*2c23cb7cSEd Maste 			}
4217*2c23cb7cSEd Maste 			/* XXX: What about DW_TAG_partial_unit? */
4218*2c23cb7cSEd Maste 			if (tag == DW_TAG_compile_unit)
4219*2c23cb7cSEd Maste 				break;
4220*2c23cb7cSEd Maste 		}
4221*2c23cb7cSEd Maste 		if (die == NULL) {
4222*2c23cb7cSEd Maste 			warnx("could not find DW_TAG_compile_unit die");
4223*2c23cb7cSEd Maste 			return;
4224*2c23cb7cSEd Maste 		}
4225*2c23cb7cSEd Maste 		if (dwarf_attrval_unsigned(die, DW_AT_stmt_list, &offset,
4226*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK)
4227*2c23cb7cSEd Maste 			continue;
4228*2c23cb7cSEd Maste 
4229*2c23cb7cSEd Maste 		length = re->dw_read(d, &offset, 4);
4230*2c23cb7cSEd Maste 		if (length == 0xffffffff) {
4231*2c23cb7cSEd Maste 			dwarf_size = 8;
4232*2c23cb7cSEd Maste 			length = re->dw_read(d, &offset, 8);
4233*2c23cb7cSEd Maste 		} else
4234*2c23cb7cSEd Maste 			dwarf_size = 4;
4235*2c23cb7cSEd Maste 
4236*2c23cb7cSEd Maste 		if (length > d->d_size - offset) {
4237*2c23cb7cSEd Maste 			warnx("invalid .dwarf_line section");
4238*2c23cb7cSEd Maste 			continue;
4239*2c23cb7cSEd Maste 		}
4240*2c23cb7cSEd Maste 
4241*2c23cb7cSEd Maste 		endoff = offset + length;
4242*2c23cb7cSEd Maste 		version = re->dw_read(d, &offset, 2);
4243*2c23cb7cSEd Maste 		hdrlen = re->dw_read(d, &offset, dwarf_size);
4244*2c23cb7cSEd Maste 		minlen = re->dw_read(d, &offset, 1);
4245*2c23cb7cSEd Maste 		defstmt = re->dw_read(d, &offset, 1);
4246*2c23cb7cSEd Maste 		lbase = re->dw_read(d, &offset, 1);
4247*2c23cb7cSEd Maste 		lrange = re->dw_read(d, &offset, 1);
4248*2c23cb7cSEd Maste 		opbase = re->dw_read(d, &offset, 1);
4249*2c23cb7cSEd Maste 
4250*2c23cb7cSEd Maste 		printf("\n");
4251*2c23cb7cSEd Maste 		printf("  Length:\t\t\t%ju\n", (uintmax_t) length);
4252*2c23cb7cSEd Maste 		printf("  DWARF version:\t\t%u\n", version);
4253*2c23cb7cSEd Maste 		printf("  Prologue Length:\t\t%ju\n", (uintmax_t) hdrlen);
4254*2c23cb7cSEd Maste 		printf("  Minimum Instruction Length:\t%u\n", minlen);
4255*2c23cb7cSEd Maste 		printf("  Initial value of 'is_stmt':\t%u\n", defstmt);
4256*2c23cb7cSEd Maste 		printf("  Line Base:\t\t\t%d\n", lbase);
4257*2c23cb7cSEd Maste 		printf("  Line Range:\t\t\t%u\n", lrange);
4258*2c23cb7cSEd Maste 		printf("  Opcode Base:\t\t\t%u\n", opbase);
4259*2c23cb7cSEd Maste 		(void) dwarf_get_address_size(re->dbg, &pointer_size, &de);
4260*2c23cb7cSEd Maste 		printf("  (Pointer size:\t\t%u)\n", pointer_size);
4261*2c23cb7cSEd Maste 
4262*2c23cb7cSEd Maste 		printf("\n");
4263*2c23cb7cSEd Maste 		printf(" Opcodes:\n");
4264*2c23cb7cSEd Maste 		for (i = 1; i < opbase; i++) {
4265*2c23cb7cSEd Maste 			oplen = re->dw_read(d, &offset, 1);
4266*2c23cb7cSEd Maste 			printf("  Opcode %d has %u args\n", i, oplen);
4267*2c23cb7cSEd Maste 		}
4268*2c23cb7cSEd Maste 
4269*2c23cb7cSEd Maste 		printf("\n");
4270*2c23cb7cSEd Maste 		printf(" The Directory Table:\n");
4271*2c23cb7cSEd Maste 		p = (uint8_t *) d->d_buf + offset;
4272*2c23cb7cSEd Maste 		while (*p != '\0') {
4273*2c23cb7cSEd Maste 			printf("  %s\n", (char *) p);
4274*2c23cb7cSEd Maste 			p += strlen((char *) p) + 1;
4275*2c23cb7cSEd Maste 		}
4276*2c23cb7cSEd Maste 
4277*2c23cb7cSEd Maste 		p++;
4278*2c23cb7cSEd Maste 		printf("\n");
4279*2c23cb7cSEd Maste 		printf(" The File Name Table:\n");
4280*2c23cb7cSEd Maste 		printf("  Entry\tDir\tTime\tSize\tName\n");
4281*2c23cb7cSEd Maste 		i = 0;
4282*2c23cb7cSEd Maste 		while (*p != '\0') {
4283*2c23cb7cSEd Maste 			i++;
4284*2c23cb7cSEd Maste 			pn = (char *) p;
4285*2c23cb7cSEd Maste 			p += strlen(pn) + 1;
4286*2c23cb7cSEd Maste 			dirndx = _decode_uleb128(&p);
4287*2c23cb7cSEd Maste 			mtime = _decode_uleb128(&p);
4288*2c23cb7cSEd Maste 			fsize = _decode_uleb128(&p);
4289*2c23cb7cSEd Maste 			printf("  %d\t%ju\t%ju\t%ju\t%s\n", i,
4290*2c23cb7cSEd Maste 			    (uintmax_t) dirndx, (uintmax_t) mtime,
4291*2c23cb7cSEd Maste 			    (uintmax_t) fsize, pn);
4292*2c23cb7cSEd Maste 		}
4293*2c23cb7cSEd Maste 
4294*2c23cb7cSEd Maste #define	RESET_REGISTERS						\
4295*2c23cb7cSEd Maste 	do {							\
4296*2c23cb7cSEd Maste 		address	       = 0;				\
4297*2c23cb7cSEd Maste 		file	       = 1;				\
4298*2c23cb7cSEd Maste 		line	       = 1;				\
4299*2c23cb7cSEd Maste 		column	       = 0;				\
4300*2c23cb7cSEd Maste 		is_stmt	       = defstmt;			\
4301*2c23cb7cSEd Maste 		basic_block    = 0;				\
4302*2c23cb7cSEd Maste 		end_sequence   = 0;				\
4303*2c23cb7cSEd Maste 		prologue_end   = 0;				\
4304*2c23cb7cSEd Maste 		epilogue_begin = 0;				\
4305*2c23cb7cSEd Maste 	} while(0)
4306*2c23cb7cSEd Maste 
4307*2c23cb7cSEd Maste #define	LINE(x) (lbase + (((x) - opbase) % lrange))
4308*2c23cb7cSEd Maste #define	ADDRESS(x) ((((x) - opbase) / lrange) * minlen)
4309*2c23cb7cSEd Maste 
4310*2c23cb7cSEd Maste 		p++;
4311*2c23cb7cSEd Maste 		pe = (uint8_t *) d->d_buf + endoff;
4312*2c23cb7cSEd Maste 		printf("\n");
4313*2c23cb7cSEd Maste 		printf(" Line Number Statements:\n");
4314*2c23cb7cSEd Maste 
4315*2c23cb7cSEd Maste 		RESET_REGISTERS;
4316*2c23cb7cSEd Maste 
4317*2c23cb7cSEd Maste 		while (p < pe) {
4318*2c23cb7cSEd Maste 
4319*2c23cb7cSEd Maste 			if (*p == 0) {
4320*2c23cb7cSEd Maste 				/*
4321*2c23cb7cSEd Maste 				 * Extended Opcodes.
4322*2c23cb7cSEd Maste 				 */
4323*2c23cb7cSEd Maste 				p++;
4324*2c23cb7cSEd Maste 				opsize = _decode_uleb128(&p);
4325*2c23cb7cSEd Maste 				printf("  Extended opcode %u: ", *p);
4326*2c23cb7cSEd Maste 				switch (*p) {
4327*2c23cb7cSEd Maste 				case DW_LNE_end_sequence:
4328*2c23cb7cSEd Maste 					p++;
4329*2c23cb7cSEd Maste 					end_sequence = 1;
4330*2c23cb7cSEd Maste 					RESET_REGISTERS;
4331*2c23cb7cSEd Maste 					printf("End of Sequence\n");
4332*2c23cb7cSEd Maste 					break;
4333*2c23cb7cSEd Maste 				case DW_LNE_set_address:
4334*2c23cb7cSEd Maste 					p++;
4335*2c23cb7cSEd Maste 					address = re->dw_decode(&p,
4336*2c23cb7cSEd Maste 					    pointer_size);
4337*2c23cb7cSEd Maste 					printf("set Address to %#jx\n",
4338*2c23cb7cSEd Maste 					    (uintmax_t) address);
4339*2c23cb7cSEd Maste 					break;
4340*2c23cb7cSEd Maste 				case DW_LNE_define_file:
4341*2c23cb7cSEd Maste 					p++;
4342*2c23cb7cSEd Maste 					pn = (char *) p;
4343*2c23cb7cSEd Maste 					p += strlen(pn) + 1;
4344*2c23cb7cSEd Maste 					dirndx = _decode_uleb128(&p);
4345*2c23cb7cSEd Maste 					mtime = _decode_uleb128(&p);
4346*2c23cb7cSEd Maste 					fsize = _decode_uleb128(&p);
4347*2c23cb7cSEd Maste 					printf("define new file: %s\n", pn);
4348*2c23cb7cSEd Maste 					break;
4349*2c23cb7cSEd Maste 				default:
4350*2c23cb7cSEd Maste 					/* Unrecognized extened opcodes. */
4351*2c23cb7cSEd Maste 					p += opsize;
4352*2c23cb7cSEd Maste 					printf("unknown opcode\n");
4353*2c23cb7cSEd Maste 				}
4354*2c23cb7cSEd Maste 			} else if (*p > 0 && *p < opbase) {
4355*2c23cb7cSEd Maste 				/*
4356*2c23cb7cSEd Maste 				 * Standard Opcodes.
4357*2c23cb7cSEd Maste 				 */
4358*2c23cb7cSEd Maste 				switch(*p++) {
4359*2c23cb7cSEd Maste 				case DW_LNS_copy:
4360*2c23cb7cSEd Maste 					basic_block = 0;
4361*2c23cb7cSEd Maste 					prologue_end = 0;
4362*2c23cb7cSEd Maste 					epilogue_begin = 0;
4363*2c23cb7cSEd Maste 					printf("  Copy\n");
4364*2c23cb7cSEd Maste 					break;
4365*2c23cb7cSEd Maste 				case DW_LNS_advance_pc:
4366*2c23cb7cSEd Maste 					udelta = _decode_uleb128(&p) *
4367*2c23cb7cSEd Maste 					    minlen;
4368*2c23cb7cSEd Maste 					address += udelta;
4369*2c23cb7cSEd Maste 					printf("  Advance PC by %ju to %#jx\n",
4370*2c23cb7cSEd Maste 					    (uintmax_t) udelta,
4371*2c23cb7cSEd Maste 					    (uintmax_t) address);
4372*2c23cb7cSEd Maste 					break;
4373*2c23cb7cSEd Maste 				case DW_LNS_advance_line:
4374*2c23cb7cSEd Maste 					sdelta = _decode_sleb128(&p);
4375*2c23cb7cSEd Maste 					line += sdelta;
4376*2c23cb7cSEd Maste 					printf("  Advance Line by %jd to %ju\n",
4377*2c23cb7cSEd Maste 					    (intmax_t) sdelta,
4378*2c23cb7cSEd Maste 					    (uintmax_t) line);
4379*2c23cb7cSEd Maste 					break;
4380*2c23cb7cSEd Maste 				case DW_LNS_set_file:
4381*2c23cb7cSEd Maste 					file = _decode_uleb128(&p);
4382*2c23cb7cSEd Maste 					printf("  Set File to %ju\n",
4383*2c23cb7cSEd Maste 					    (uintmax_t) file);
4384*2c23cb7cSEd Maste 					break;
4385*2c23cb7cSEd Maste 				case DW_LNS_set_column:
4386*2c23cb7cSEd Maste 					column = _decode_uleb128(&p);
4387*2c23cb7cSEd Maste 					printf("  Set Column to %ju\n",
4388*2c23cb7cSEd Maste 					    (uintmax_t) column);
4389*2c23cb7cSEd Maste 					break;
4390*2c23cb7cSEd Maste 				case DW_LNS_negate_stmt:
4391*2c23cb7cSEd Maste 					is_stmt = !is_stmt;
4392*2c23cb7cSEd Maste 					printf("  Set is_stmt to %d\n", is_stmt);
4393*2c23cb7cSEd Maste 					break;
4394*2c23cb7cSEd Maste 				case DW_LNS_set_basic_block:
4395*2c23cb7cSEd Maste 					basic_block = 1;
4396*2c23cb7cSEd Maste 					printf("  Set basic block flag\n");
4397*2c23cb7cSEd Maste 					break;
4398*2c23cb7cSEd Maste 				case DW_LNS_const_add_pc:
4399*2c23cb7cSEd Maste 					address += ADDRESS(255);
4400*2c23cb7cSEd Maste 					printf("  Advance PC by constant %ju"
4401*2c23cb7cSEd Maste 					    " to %#jx\n",
4402*2c23cb7cSEd Maste 					    (uintmax_t) ADDRESS(255),
4403*2c23cb7cSEd Maste 					    (uintmax_t) address);
4404*2c23cb7cSEd Maste 					break;
4405*2c23cb7cSEd Maste 				case DW_LNS_fixed_advance_pc:
4406*2c23cb7cSEd Maste 					udelta = re->dw_decode(&p, 2);
4407*2c23cb7cSEd Maste 					address += udelta;
4408*2c23cb7cSEd Maste 					printf("  Advance PC by fixed value "
4409*2c23cb7cSEd Maste 					    "%ju to %#jx\n",
4410*2c23cb7cSEd Maste 					    (uintmax_t) udelta,
4411*2c23cb7cSEd Maste 					    (uintmax_t) address);
4412*2c23cb7cSEd Maste 					break;
4413*2c23cb7cSEd Maste 				case DW_LNS_set_prologue_end:
4414*2c23cb7cSEd Maste 					prologue_end = 1;
4415*2c23cb7cSEd Maste 					printf("  Set prologue end flag\n");
4416*2c23cb7cSEd Maste 					break;
4417*2c23cb7cSEd Maste 				case DW_LNS_set_epilogue_begin:
4418*2c23cb7cSEd Maste 					epilogue_begin = 1;
4419*2c23cb7cSEd Maste 					printf("  Set epilogue begin flag\n");
4420*2c23cb7cSEd Maste 					break;
4421*2c23cb7cSEd Maste 				case DW_LNS_set_isa:
4422*2c23cb7cSEd Maste 					isa = _decode_uleb128(&p);
4423*2c23cb7cSEd Maste 					printf("  Set isa to %ju\n", isa);
4424*2c23cb7cSEd Maste 					break;
4425*2c23cb7cSEd Maste 				default:
4426*2c23cb7cSEd Maste 					/* Unrecognized extended opcodes. */
4427*2c23cb7cSEd Maste 					printf("  Unknown extended opcode %u\n",
4428*2c23cb7cSEd Maste 					    *(p - 1));
4429*2c23cb7cSEd Maste 					break;
4430*2c23cb7cSEd Maste 				}
4431*2c23cb7cSEd Maste 
4432*2c23cb7cSEd Maste 			} else {
4433*2c23cb7cSEd Maste 				/*
4434*2c23cb7cSEd Maste 				 * Special Opcodes.
4435*2c23cb7cSEd Maste 				 */
4436*2c23cb7cSEd Maste 				line += LINE(*p);
4437*2c23cb7cSEd Maste 				address += ADDRESS(*p);
4438*2c23cb7cSEd Maste 				basic_block = 0;
4439*2c23cb7cSEd Maste 				prologue_end = 0;
4440*2c23cb7cSEd Maste 				epilogue_begin = 0;
4441*2c23cb7cSEd Maste 				printf("  Special opcode %u: advance Address "
4442*2c23cb7cSEd Maste 				    "by %ju to %#jx and Line by %jd to %ju\n",
4443*2c23cb7cSEd Maste 				    *p - opbase, (uintmax_t) ADDRESS(*p),
4444*2c23cb7cSEd Maste 				    (uintmax_t) address, (intmax_t) LINE(*p),
4445*2c23cb7cSEd Maste 				    (uintmax_t) line);
4446*2c23cb7cSEd Maste 				p++;
4447*2c23cb7cSEd Maste 			}
4448*2c23cb7cSEd Maste 
4449*2c23cb7cSEd Maste 
4450*2c23cb7cSEd Maste 		}
4451*2c23cb7cSEd Maste 	}
4452*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
4453*2c23cb7cSEd Maste 		warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
4454*2c23cb7cSEd Maste 
4455*2c23cb7cSEd Maste #undef	RESET_REGISTERS
4456*2c23cb7cSEd Maste #undef	LINE
4457*2c23cb7cSEd Maste #undef	ADDRESS
4458*2c23cb7cSEd Maste }
4459*2c23cb7cSEd Maste 
4460*2c23cb7cSEd Maste static void
4461*2c23cb7cSEd Maste dump_dwarf_line_decoded(struct readelf *re)
4462*2c23cb7cSEd Maste {
4463*2c23cb7cSEd Maste 	Dwarf_Die die;
4464*2c23cb7cSEd Maste 	Dwarf_Line *linebuf, ln;
4465*2c23cb7cSEd Maste 	Dwarf_Addr lineaddr;
4466*2c23cb7cSEd Maste 	Dwarf_Signed linecount, srccount;
4467*2c23cb7cSEd Maste 	Dwarf_Unsigned lineno, fn;
4468*2c23cb7cSEd Maste 	Dwarf_Error de;
4469*2c23cb7cSEd Maste 	const char *dir, *file;
4470*2c23cb7cSEd Maste 	char **srcfiles;
4471*2c23cb7cSEd Maste 	int i, ret;
4472*2c23cb7cSEd Maste 
4473*2c23cb7cSEd Maste 	printf("Decoded dump of debug contents of section .debug_line:\n\n");
4474*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,
4475*2c23cb7cSEd Maste 	    NULL, &de)) == DW_DLV_OK) {
4476*2c23cb7cSEd Maste 		if (dwarf_siblingof(re->dbg, NULL, &die, &de) != DW_DLV_OK)
4477*2c23cb7cSEd Maste 			continue;
4478*2c23cb7cSEd Maste 		if (dwarf_attrval_string(die, DW_AT_name, &file, &de) !=
4479*2c23cb7cSEd Maste 		    DW_DLV_OK)
4480*2c23cb7cSEd Maste 			file = NULL;
4481*2c23cb7cSEd Maste 		if (dwarf_attrval_string(die, DW_AT_comp_dir, &dir, &de) !=
4482*2c23cb7cSEd Maste 		    DW_DLV_OK)
4483*2c23cb7cSEd Maste 			dir = NULL;
4484*2c23cb7cSEd Maste 		printf("CU: ");
4485*2c23cb7cSEd Maste 		if (dir && file)
4486*2c23cb7cSEd Maste 			printf("%s/", dir);
4487*2c23cb7cSEd Maste 		if (file)
4488*2c23cb7cSEd Maste 			printf("%s", file);
4489*2c23cb7cSEd Maste 		putchar('\n');
4490*2c23cb7cSEd Maste 		printf("%-37s %11s   %s\n", "Filename", "Line Number",
4491*2c23cb7cSEd Maste 		    "Starting Address");
4492*2c23cb7cSEd Maste 		if (dwarf_srclines(die, &linebuf, &linecount, &de) != DW_DLV_OK)
4493*2c23cb7cSEd Maste 			continue;
4494*2c23cb7cSEd Maste 		if (dwarf_srcfiles(die, &srcfiles, &srccount, &de) != DW_DLV_OK)
4495*2c23cb7cSEd Maste 			continue;
4496*2c23cb7cSEd Maste 		for (i = 0; i < linecount; i++) {
4497*2c23cb7cSEd Maste 			ln = linebuf[i];
4498*2c23cb7cSEd Maste 			if (dwarf_line_srcfileno(ln, &fn, &de) != DW_DLV_OK)
4499*2c23cb7cSEd Maste 				continue;
4500*2c23cb7cSEd Maste 			if (dwarf_lineno(ln, &lineno, &de) != DW_DLV_OK)
4501*2c23cb7cSEd Maste 				continue;
4502*2c23cb7cSEd Maste 			if (dwarf_lineaddr(ln, &lineaddr, &de) != DW_DLV_OK)
4503*2c23cb7cSEd Maste 				continue;
4504*2c23cb7cSEd Maste 			printf("%-37s %11ju %#18jx\n",
4505*2c23cb7cSEd Maste 			    basename(srcfiles[fn - 1]), (uintmax_t) lineno,
4506*2c23cb7cSEd Maste 			    (uintmax_t) lineaddr);
4507*2c23cb7cSEd Maste 		}
4508*2c23cb7cSEd Maste 		putchar('\n');
4509*2c23cb7cSEd Maste 	}
4510*2c23cb7cSEd Maste }
4511*2c23cb7cSEd Maste 
4512*2c23cb7cSEd Maste static void
4513*2c23cb7cSEd Maste dump_dwarf_die(struct readelf *re, Dwarf_Die die, int level)
4514*2c23cb7cSEd Maste {
4515*2c23cb7cSEd Maste 	Dwarf_Attribute *attr_list;
4516*2c23cb7cSEd Maste 	Dwarf_Die ret_die;
4517*2c23cb7cSEd Maste 	Dwarf_Off dieoff, cuoff, culen;
4518*2c23cb7cSEd Maste 	Dwarf_Unsigned ate, v_udata;
4519*2c23cb7cSEd Maste 	Dwarf_Signed attr_count, v_sdata;
4520*2c23cb7cSEd Maste 	Dwarf_Off v_off;
4521*2c23cb7cSEd Maste 	Dwarf_Addr v_addr;
4522*2c23cb7cSEd Maste 	Dwarf_Half tag, attr, form;
4523*2c23cb7cSEd Maste 	Dwarf_Block *v_block;
4524*2c23cb7cSEd Maste 	Dwarf_Bool v_bool;
4525*2c23cb7cSEd Maste 	Dwarf_Error de;
4526*2c23cb7cSEd Maste 	const char *tag_str, *attr_str, *ate_str;
4527*2c23cb7cSEd Maste 	char *v_str;
4528*2c23cb7cSEd Maste 	uint8_t *b;
4529*2c23cb7cSEd Maste 	int i, j, abc, ret;
4530*2c23cb7cSEd Maste 
4531*2c23cb7cSEd Maste 	if (dwarf_dieoffset(die, &dieoff, &de) != DW_DLV_OK) {
4532*2c23cb7cSEd Maste 		warnx("dwarf_dieoffset failed: %s", dwarf_errmsg(de));
4533*2c23cb7cSEd Maste 		goto cont_search;
4534*2c23cb7cSEd Maste 	}
4535*2c23cb7cSEd Maste 
4536*2c23cb7cSEd Maste 	printf("<%d><%jx>: ", level, (uintmax_t) dieoff);
4537*2c23cb7cSEd Maste 
4538*2c23cb7cSEd Maste 	if (dwarf_die_CU_offset_range(die, &cuoff, &culen, &de) != DW_DLV_OK) {
4539*2c23cb7cSEd Maste 		warnx("dwarf_die_CU_offset_range failed: %s",
4540*2c23cb7cSEd Maste 		      dwarf_errmsg(de));
4541*2c23cb7cSEd Maste 		cuoff = 0;
4542*2c23cb7cSEd Maste 	}
4543*2c23cb7cSEd Maste 
4544*2c23cb7cSEd Maste 	abc = dwarf_die_abbrev_code(die);
4545*2c23cb7cSEd Maste 	if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
4546*2c23cb7cSEd Maste 		warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
4547*2c23cb7cSEd Maste 		goto cont_search;
4548*2c23cb7cSEd Maste 	}
4549*2c23cb7cSEd Maste 	if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) {
4550*2c23cb7cSEd Maste 		warnx("dwarf_get_TAG_name failed");
4551*2c23cb7cSEd Maste 		goto cont_search;
4552*2c23cb7cSEd Maste 	}
4553*2c23cb7cSEd Maste 
4554*2c23cb7cSEd Maste 	printf("Abbrev Number: %d (%s)\n", abc, tag_str);
4555*2c23cb7cSEd Maste 
4556*2c23cb7cSEd Maste 	if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=
4557*2c23cb7cSEd Maste 	    DW_DLV_OK) {
4558*2c23cb7cSEd Maste 		if (ret == DW_DLV_ERROR)
4559*2c23cb7cSEd Maste 			warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));
4560*2c23cb7cSEd Maste 		goto cont_search;
4561*2c23cb7cSEd Maste 	}
4562*2c23cb7cSEd Maste 
4563*2c23cb7cSEd Maste 	for (i = 0; i < attr_count; i++) {
4564*2c23cb7cSEd Maste 		if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) {
4565*2c23cb7cSEd Maste 			warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));
4566*2c23cb7cSEd Maste 			continue;
4567*2c23cb7cSEd Maste 		}
4568*2c23cb7cSEd Maste 		if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {
4569*2c23cb7cSEd Maste 			warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));
4570*2c23cb7cSEd Maste 			continue;
4571*2c23cb7cSEd Maste 		}
4572*2c23cb7cSEd Maste 		if (dwarf_get_AT_name(attr, &attr_str) != DW_DLV_OK) {
4573*2c23cb7cSEd Maste 			warnx("dwarf_get_AT_name failed");
4574*2c23cb7cSEd Maste 			continue;
4575*2c23cb7cSEd Maste 		}
4576*2c23cb7cSEd Maste 		printf("     %-18s: ", attr_str);
4577*2c23cb7cSEd Maste 		switch (form) {
4578*2c23cb7cSEd Maste 		case DW_FORM_ref_addr:
4579*2c23cb7cSEd Maste 			if (dwarf_global_formref(attr_list[i], &v_off, &de) !=
4580*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4581*2c23cb7cSEd Maste 				warnx("dwarf_global_formref failed: %s",
4582*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4583*2c23cb7cSEd Maste 				continue;
4584*2c23cb7cSEd Maste 			}
4585*2c23cb7cSEd Maste 			printf("<%jx>", (uintmax_t) v_off);
4586*2c23cb7cSEd Maste 			break;
4587*2c23cb7cSEd Maste 
4588*2c23cb7cSEd Maste 		case DW_FORM_ref1:
4589*2c23cb7cSEd Maste 		case DW_FORM_ref2:
4590*2c23cb7cSEd Maste 		case DW_FORM_ref4:
4591*2c23cb7cSEd Maste 		case DW_FORM_ref8:
4592*2c23cb7cSEd Maste 		case DW_FORM_ref_udata:
4593*2c23cb7cSEd Maste 			if (dwarf_formref(attr_list[i], &v_off, &de) !=
4594*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4595*2c23cb7cSEd Maste 				warnx("dwarf_formref failed: %s",
4596*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4597*2c23cb7cSEd Maste 				continue;
4598*2c23cb7cSEd Maste 			}
4599*2c23cb7cSEd Maste 			v_off += cuoff;
4600*2c23cb7cSEd Maste 			printf("<%jx>", (uintmax_t) v_off);
4601*2c23cb7cSEd Maste 			break;
4602*2c23cb7cSEd Maste 
4603*2c23cb7cSEd Maste 		case DW_FORM_addr:
4604*2c23cb7cSEd Maste 			if (dwarf_formaddr(attr_list[i], &v_addr, &de) !=
4605*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4606*2c23cb7cSEd Maste 				warnx("dwarf_formaddr failed: %s",
4607*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4608*2c23cb7cSEd Maste 				continue;
4609*2c23cb7cSEd Maste 			}
4610*2c23cb7cSEd Maste 			printf("%#jx", (uintmax_t) v_addr);
4611*2c23cb7cSEd Maste 			break;
4612*2c23cb7cSEd Maste 
4613*2c23cb7cSEd Maste 		case DW_FORM_data1:
4614*2c23cb7cSEd Maste 		case DW_FORM_data2:
4615*2c23cb7cSEd Maste 		case DW_FORM_data4:
4616*2c23cb7cSEd Maste 		case DW_FORM_data8:
4617*2c23cb7cSEd Maste 		case DW_FORM_udata:
4618*2c23cb7cSEd Maste 			if (dwarf_formudata(attr_list[i], &v_udata, &de) !=
4619*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4620*2c23cb7cSEd Maste 				warnx("dwarf_formudata failed: %s",
4621*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4622*2c23cb7cSEd Maste 				continue;
4623*2c23cb7cSEd Maste 			}
4624*2c23cb7cSEd Maste 			printf("%ju", (uintmax_t) v_udata);
4625*2c23cb7cSEd Maste 			break;
4626*2c23cb7cSEd Maste 
4627*2c23cb7cSEd Maste 		case DW_FORM_sdata:
4628*2c23cb7cSEd Maste 			if (dwarf_formsdata(attr_list[i], &v_sdata, &de) !=
4629*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4630*2c23cb7cSEd Maste 				warnx("dwarf_formudata failed: %s",
4631*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4632*2c23cb7cSEd Maste 				continue;
4633*2c23cb7cSEd Maste 			}
4634*2c23cb7cSEd Maste 			printf("%jd", (intmax_t) v_sdata);
4635*2c23cb7cSEd Maste 			break;
4636*2c23cb7cSEd Maste 
4637*2c23cb7cSEd Maste 		case DW_FORM_flag:
4638*2c23cb7cSEd Maste 			if (dwarf_formflag(attr_list[i], &v_bool, &de) !=
4639*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4640*2c23cb7cSEd Maste 				warnx("dwarf_formflag failed: %s",
4641*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4642*2c23cb7cSEd Maste 				continue;
4643*2c23cb7cSEd Maste 			}
4644*2c23cb7cSEd Maste 			printf("%jd", (intmax_t) v_bool);
4645*2c23cb7cSEd Maste 			break;
4646*2c23cb7cSEd Maste 
4647*2c23cb7cSEd Maste 		case DW_FORM_string:
4648*2c23cb7cSEd Maste 		case DW_FORM_strp:
4649*2c23cb7cSEd Maste 			if (dwarf_formstring(attr_list[i], &v_str, &de) !=
4650*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4651*2c23cb7cSEd Maste 				warnx("dwarf_formstring failed: %s",
4652*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4653*2c23cb7cSEd Maste 				continue;
4654*2c23cb7cSEd Maste 			}
4655*2c23cb7cSEd Maste 			if (form == DW_FORM_string)
4656*2c23cb7cSEd Maste 				printf("%s", v_str);
4657*2c23cb7cSEd Maste 			else
4658*2c23cb7cSEd Maste 				printf("(indirect string) %s", v_str);
4659*2c23cb7cSEd Maste 			break;
4660*2c23cb7cSEd Maste 
4661*2c23cb7cSEd Maste 		case DW_FORM_block:
4662*2c23cb7cSEd Maste 		case DW_FORM_block1:
4663*2c23cb7cSEd Maste 		case DW_FORM_block2:
4664*2c23cb7cSEd Maste 		case DW_FORM_block4:
4665*2c23cb7cSEd Maste 			if (dwarf_formblock(attr_list[i], &v_block, &de) !=
4666*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4667*2c23cb7cSEd Maste 				warnx("dwarf_formblock failed: %s",
4668*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4669*2c23cb7cSEd Maste 				continue;
4670*2c23cb7cSEd Maste 			}
4671*2c23cb7cSEd Maste 			printf("%ju byte block:", v_block->bl_len);
4672*2c23cb7cSEd Maste 			b = v_block->bl_data;
4673*2c23cb7cSEd Maste 			for (j = 0; (Dwarf_Unsigned) j < v_block->bl_len; j++)
4674*2c23cb7cSEd Maste 				printf(" %x", b[j]);
4675*2c23cb7cSEd Maste 			break;
4676*2c23cb7cSEd Maste 		}
4677*2c23cb7cSEd Maste 		switch (attr) {
4678*2c23cb7cSEd Maste 		case DW_AT_encoding:
4679*2c23cb7cSEd Maste 			if (dwarf_attrval_unsigned(die, attr, &ate, &de) !=
4680*2c23cb7cSEd Maste 			    DW_DLV_OK)
4681*2c23cb7cSEd Maste 				break;
4682*2c23cb7cSEd Maste 			if (dwarf_get_ATE_name(ate, &ate_str) != DW_DLV_OK)
4683*2c23cb7cSEd Maste 				break;
4684*2c23cb7cSEd Maste 			printf("\t(%s)", &ate_str[strlen("DW_ATE_")]);
4685*2c23cb7cSEd Maste 			break;
4686*2c23cb7cSEd Maste 		default:
4687*2c23cb7cSEd Maste 			break;
4688*2c23cb7cSEd Maste 		}
4689*2c23cb7cSEd Maste 		putchar('\n');
4690*2c23cb7cSEd Maste 	}
4691*2c23cb7cSEd Maste 
4692*2c23cb7cSEd Maste 
4693*2c23cb7cSEd Maste cont_search:
4694*2c23cb7cSEd Maste 	/* Search children. */
4695*2c23cb7cSEd Maste 	ret = dwarf_child(die, &ret_die, &de);
4696*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
4697*2c23cb7cSEd Maste 		warnx("dwarf_child: %s", dwarf_errmsg(de));
4698*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
4699*2c23cb7cSEd Maste 		dump_dwarf_die(re, ret_die, level + 1);
4700*2c23cb7cSEd Maste 
4701*2c23cb7cSEd Maste 	/* Search sibling. */
4702*2c23cb7cSEd Maste 	ret = dwarf_siblingof(re->dbg, die, &ret_die, &de);
4703*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
4704*2c23cb7cSEd Maste 		warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
4705*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
4706*2c23cb7cSEd Maste 		dump_dwarf_die(re, ret_die, level);
4707*2c23cb7cSEd Maste 
4708*2c23cb7cSEd Maste 	dwarf_dealloc(re->dbg, die, DW_DLA_DIE);
4709*2c23cb7cSEd Maste }
4710*2c23cb7cSEd Maste 
4711*2c23cb7cSEd Maste static void
4712*2c23cb7cSEd Maste dump_dwarf_info(struct readelf *re)
4713*2c23cb7cSEd Maste {
4714*2c23cb7cSEd Maste 	struct section *s;
4715*2c23cb7cSEd Maste 	Dwarf_Die die;
4716*2c23cb7cSEd Maste 	Dwarf_Error de;
4717*2c23cb7cSEd Maste 	Dwarf_Half tag, version, pointer_size;
4718*2c23cb7cSEd Maste 	Dwarf_Off cu_offset, cu_length;
4719*2c23cb7cSEd Maste 	Dwarf_Off aboff;
4720*2c23cb7cSEd Maste 	Elf_Data *d;
4721*2c23cb7cSEd Maste 	int i, elferr, ret;
4722*2c23cb7cSEd Maste 
4723*2c23cb7cSEd Maste 	printf("\nDump of debug contents of section .debug_info:\n");
4724*2c23cb7cSEd Maste 
4725*2c23cb7cSEd Maste 	s = NULL;
4726*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
4727*2c23cb7cSEd Maste 		s = &re->sl[i];
4728*2c23cb7cSEd Maste 		if (s->name != NULL && !strcmp(s->name, ".debug_info"))
4729*2c23cb7cSEd Maste 			break;
4730*2c23cb7cSEd Maste 	}
4731*2c23cb7cSEd Maste 	if ((size_t) i >= re->shnum)
4732*2c23cb7cSEd Maste 		return;
4733*2c23cb7cSEd Maste 
4734*2c23cb7cSEd Maste 	(void) elf_errno();
4735*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
4736*2c23cb7cSEd Maste 		elferr = elf_errno();
4737*2c23cb7cSEd Maste 		if (elferr != 0)
4738*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(-1));
4739*2c23cb7cSEd Maste 		return;
4740*2c23cb7cSEd Maste 	}
4741*2c23cb7cSEd Maste 	if (d->d_size <= 0)
4742*2c23cb7cSEd Maste 		return;
4743*2c23cb7cSEd Maste 
4744*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, &version, &aboff,
4745*2c23cb7cSEd Maste 	    &pointer_size, NULL, &de)) == DW_DLV_OK) {
4746*2c23cb7cSEd Maste 		die = NULL;
4747*2c23cb7cSEd Maste 		while (dwarf_siblingof(re->dbg, die, &die, &de) == DW_DLV_OK) {
4748*2c23cb7cSEd Maste 			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
4749*2c23cb7cSEd Maste 				warnx("dwarf_tag failed: %s",
4750*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4751*2c23cb7cSEd Maste 				return;
4752*2c23cb7cSEd Maste 			}
4753*2c23cb7cSEd Maste 			/* XXX: What about DW_TAG_partial_unit? */
4754*2c23cb7cSEd Maste 			if (tag == DW_TAG_compile_unit)
4755*2c23cb7cSEd Maste 				break;
4756*2c23cb7cSEd Maste 		}
4757*2c23cb7cSEd Maste 		if (die == NULL) {
4758*2c23cb7cSEd Maste 			warnx("could not find DW_TAG_compile_unit die");
4759*2c23cb7cSEd Maste 			return;
4760*2c23cb7cSEd Maste 		}
4761*2c23cb7cSEd Maste 
4762*2c23cb7cSEd Maste 		if (dwarf_die_CU_offset_range(die, &cu_offset, &cu_length,
4763*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK) {
4764*2c23cb7cSEd Maste 			warnx("dwarf_die_CU_offset failed: %s",
4765*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
4766*2c23cb7cSEd Maste 			continue;
4767*2c23cb7cSEd Maste 		}
4768*2c23cb7cSEd Maste 
4769*2c23cb7cSEd Maste 		printf("  Compilation Unit @ %jd:\n", (intmax_t) cu_offset);
4770*2c23cb7cSEd Maste 		printf("    Length:\t\t%jd\n", (intmax_t) cu_length);
4771*2c23cb7cSEd Maste 		printf("    Version:\t\t%u\n", version);
4772*2c23cb7cSEd Maste 		printf("    Abbrev Offset:\t%ju\n", (uintmax_t) aboff);
4773*2c23cb7cSEd Maste 		printf("    Pointer Size:\t%u\n", pointer_size);
4774*2c23cb7cSEd Maste 
4775*2c23cb7cSEd Maste 		dump_dwarf_die(re, die, 0);
4776*2c23cb7cSEd Maste 	}
4777*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
4778*2c23cb7cSEd Maste 		warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
4779*2c23cb7cSEd Maste }
4780*2c23cb7cSEd Maste 
4781*2c23cb7cSEd Maste static void
4782*2c23cb7cSEd Maste dump_dwarf_abbrev(struct readelf *re)
4783*2c23cb7cSEd Maste {
4784*2c23cb7cSEd Maste 	Dwarf_Abbrev ab;
4785*2c23cb7cSEd Maste 	Dwarf_Off aboff, atoff;
4786*2c23cb7cSEd Maste 	Dwarf_Unsigned length, attr_count;
4787*2c23cb7cSEd Maste 	Dwarf_Signed flag, form;
4788*2c23cb7cSEd Maste 	Dwarf_Half tag, attr;
4789*2c23cb7cSEd Maste 	Dwarf_Error de;
4790*2c23cb7cSEd Maste 	const char *tag_str, *attr_str, *form_str;
4791*2c23cb7cSEd Maste 	int i, j, ret;
4792*2c23cb7cSEd Maste 
4793*2c23cb7cSEd Maste 	printf("\nContents of section .debug_abbrev:\n\n");
4794*2c23cb7cSEd Maste 
4795*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, &aboff,
4796*2c23cb7cSEd Maste 	    NULL, NULL, &de)) ==  DW_DLV_OK) {
4797*2c23cb7cSEd Maste 		printf("  Number TAG\n");
4798*2c23cb7cSEd Maste 		i = 0;
4799*2c23cb7cSEd Maste 		while ((ret = dwarf_get_abbrev(re->dbg, aboff, &ab, &length,
4800*2c23cb7cSEd Maste 		    &attr_count, &de)) == DW_DLV_OK) {
4801*2c23cb7cSEd Maste 			if (length == 1) {
4802*2c23cb7cSEd Maste 				dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV);
4803*2c23cb7cSEd Maste 				break;
4804*2c23cb7cSEd Maste 			}
4805*2c23cb7cSEd Maste 			aboff += length;
4806*2c23cb7cSEd Maste 			printf("%4d", ++i);
4807*2c23cb7cSEd Maste 			if (dwarf_get_abbrev_tag(ab, &tag, &de) != DW_DLV_OK) {
4808*2c23cb7cSEd Maste 				warnx("dwarf_get_abbrev_tag failed: %s",
4809*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
4810*2c23cb7cSEd Maste 				goto next_abbrev;
4811*2c23cb7cSEd Maste 			}
4812*2c23cb7cSEd Maste 			if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) {
4813*2c23cb7cSEd Maste 				warnx("dwarf_get_TAG_name failed");
4814*2c23cb7cSEd Maste 				goto next_abbrev;
4815*2c23cb7cSEd Maste 			}
4816*2c23cb7cSEd Maste 			if (dwarf_get_abbrev_children_flag(ab, &flag, &de) !=
4817*2c23cb7cSEd Maste 			    DW_DLV_OK) {
4818*2c23cb7cSEd Maste 				warnx("dwarf_get_abbrev_children_flag failed:"
4819*2c23cb7cSEd Maste 				    " %s", dwarf_errmsg(de));
4820*2c23cb7cSEd Maste 				goto next_abbrev;
4821*2c23cb7cSEd Maste 			}
4822*2c23cb7cSEd Maste 			printf("      %s    %s\n", tag_str,
4823*2c23cb7cSEd Maste 			    flag ? "[has children]" : "[no children]");
4824*2c23cb7cSEd Maste 			for (j = 0; (Dwarf_Unsigned) j < attr_count; j++) {
4825*2c23cb7cSEd Maste 				if (dwarf_get_abbrev_entry(ab, (Dwarf_Signed) j,
4826*2c23cb7cSEd Maste 				    &attr, &form, &atoff, &de) != DW_DLV_OK) {
4827*2c23cb7cSEd Maste 					warnx("dwarf_get_abbrev_entry failed:"
4828*2c23cb7cSEd Maste 					    " %s", dwarf_errmsg(de));
4829*2c23cb7cSEd Maste 					continue;
4830*2c23cb7cSEd Maste 				}
4831*2c23cb7cSEd Maste 				if (dwarf_get_AT_name(attr, &attr_str) !=
4832*2c23cb7cSEd Maste 				    DW_DLV_OK) {
4833*2c23cb7cSEd Maste 					warnx("dwarf_get_AT_name failed");
4834*2c23cb7cSEd Maste 					continue;
4835*2c23cb7cSEd Maste 				}
4836*2c23cb7cSEd Maste 				if (dwarf_get_FORM_name(form, &form_str) !=
4837*2c23cb7cSEd Maste 				    DW_DLV_OK) {
4838*2c23cb7cSEd Maste 					warnx("dwarf_get_FORM_name failed");
4839*2c23cb7cSEd Maste 					continue;
4840*2c23cb7cSEd Maste 				}
4841*2c23cb7cSEd Maste 				printf("    %-18s %s\n", attr_str, form_str);
4842*2c23cb7cSEd Maste 			}
4843*2c23cb7cSEd Maste 		next_abbrev:
4844*2c23cb7cSEd Maste 			dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV);
4845*2c23cb7cSEd Maste 		}
4846*2c23cb7cSEd Maste 		if (ret != DW_DLV_OK)
4847*2c23cb7cSEd Maste 			warnx("dwarf_get_abbrev: %s", dwarf_errmsg(de));
4848*2c23cb7cSEd Maste 	}
4849*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
4850*2c23cb7cSEd Maste 		warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
4851*2c23cb7cSEd Maste }
4852*2c23cb7cSEd Maste 
4853*2c23cb7cSEd Maste static void
4854*2c23cb7cSEd Maste dump_dwarf_pubnames(struct readelf *re)
4855*2c23cb7cSEd Maste {
4856*2c23cb7cSEd Maste 	struct section *s;
4857*2c23cb7cSEd Maste 	Dwarf_Off die_off;
4858*2c23cb7cSEd Maste 	Dwarf_Unsigned offset, length, nt_cu_offset, nt_cu_length;
4859*2c23cb7cSEd Maste 	Dwarf_Signed cnt;
4860*2c23cb7cSEd Maste 	Dwarf_Global *globs;
4861*2c23cb7cSEd Maste 	Dwarf_Half nt_version;
4862*2c23cb7cSEd Maste 	Dwarf_Error de;
4863*2c23cb7cSEd Maste 	Elf_Data *d;
4864*2c23cb7cSEd Maste 	char *glob_name;
4865*2c23cb7cSEd Maste 	int i, dwarf_size, elferr;
4866*2c23cb7cSEd Maste 
4867*2c23cb7cSEd Maste 	printf("\nContents of the .debug_pubnames section:\n");
4868*2c23cb7cSEd Maste 
4869*2c23cb7cSEd Maste 	s = NULL;
4870*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
4871*2c23cb7cSEd Maste 		s = &re->sl[i];
4872*2c23cb7cSEd Maste 		if (s->name != NULL && !strcmp(s->name, ".debug_pubnames"))
4873*2c23cb7cSEd Maste 			break;
4874*2c23cb7cSEd Maste 	}
4875*2c23cb7cSEd Maste 	if ((size_t) i >= re->shnum)
4876*2c23cb7cSEd Maste 		return;
4877*2c23cb7cSEd Maste 
4878*2c23cb7cSEd Maste 	(void) elf_errno();
4879*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
4880*2c23cb7cSEd Maste 		elferr = elf_errno();
4881*2c23cb7cSEd Maste 		if (elferr != 0)
4882*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(-1));
4883*2c23cb7cSEd Maste 		return;
4884*2c23cb7cSEd Maste 	}
4885*2c23cb7cSEd Maste 	if (d->d_size <= 0)
4886*2c23cb7cSEd Maste 		return;
4887*2c23cb7cSEd Maste 
4888*2c23cb7cSEd Maste 	/* Read in .debug_pubnames section table header. */
4889*2c23cb7cSEd Maste 	offset = 0;
4890*2c23cb7cSEd Maste 	length = re->dw_read(d, &offset, 4);
4891*2c23cb7cSEd Maste 	if (length == 0xffffffff) {
4892*2c23cb7cSEd Maste 		dwarf_size = 8;
4893*2c23cb7cSEd Maste 		length = re->dw_read(d, &offset, 8);
4894*2c23cb7cSEd Maste 	} else
4895*2c23cb7cSEd Maste 		dwarf_size = 4;
4896*2c23cb7cSEd Maste 
4897*2c23cb7cSEd Maste 	if (length > d->d_size - offset) {
4898*2c23cb7cSEd Maste 		warnx("invalid .dwarf_pubnames section");
4899*2c23cb7cSEd Maste 		return;
4900*2c23cb7cSEd Maste 	}
4901*2c23cb7cSEd Maste 
4902*2c23cb7cSEd Maste 	nt_version = re->dw_read(d, &offset, 2);
4903*2c23cb7cSEd Maste 	nt_cu_offset = re->dw_read(d, &offset, dwarf_size);
4904*2c23cb7cSEd Maste 	nt_cu_length = re->dw_read(d, &offset, dwarf_size);
4905*2c23cb7cSEd Maste 	printf("  Length:\t\t\t\t%ju\n", (uintmax_t) length);
4906*2c23cb7cSEd Maste 	printf("  Version:\t\t\t\t%u\n", nt_version);
4907*2c23cb7cSEd Maste 	printf("  Offset into .debug_info section:\t%ju\n",
4908*2c23cb7cSEd Maste 	    (uintmax_t) nt_cu_offset);
4909*2c23cb7cSEd Maste 	printf("  Size of area in .debug_info section:\t%ju\n",
4910*2c23cb7cSEd Maste 	    (uintmax_t) nt_cu_length);
4911*2c23cb7cSEd Maste 
4912*2c23cb7cSEd Maste 	if (dwarf_get_globals(re->dbg, &globs, &cnt, &de) != DW_DLV_OK) {
4913*2c23cb7cSEd Maste 		warnx("dwarf_get_globals failed: %s", dwarf_errmsg(de));
4914*2c23cb7cSEd Maste 		return;
4915*2c23cb7cSEd Maste 	}
4916*2c23cb7cSEd Maste 
4917*2c23cb7cSEd Maste 	printf("\n    Offset      Name\n");
4918*2c23cb7cSEd Maste 	for (i = 0; i < cnt; i++) {
4919*2c23cb7cSEd Maste 		if (dwarf_globname(globs[i], &glob_name, &de) != DW_DLV_OK) {
4920*2c23cb7cSEd Maste 			warnx("dwarf_globname failed: %s", dwarf_errmsg(de));
4921*2c23cb7cSEd Maste 			continue;
4922*2c23cb7cSEd Maste 		}
4923*2c23cb7cSEd Maste 		if (dwarf_global_die_offset(globs[i], &die_off, &de) !=
4924*2c23cb7cSEd Maste 		    DW_DLV_OK) {
4925*2c23cb7cSEd Maste 			warnx("dwarf_global_die_offset failed: %s",
4926*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
4927*2c23cb7cSEd Maste 			continue;
4928*2c23cb7cSEd Maste 		}
4929*2c23cb7cSEd Maste 		printf("    %-11ju %s\n", (uintmax_t) die_off, glob_name);
4930*2c23cb7cSEd Maste 	}
4931*2c23cb7cSEd Maste }
4932*2c23cb7cSEd Maste 
4933*2c23cb7cSEd Maste static void
4934*2c23cb7cSEd Maste dump_dwarf_aranges(struct readelf *re)
4935*2c23cb7cSEd Maste {
4936*2c23cb7cSEd Maste 	struct section *s;
4937*2c23cb7cSEd Maste 	Dwarf_Arange *aranges;
4938*2c23cb7cSEd Maste 	Dwarf_Addr start;
4939*2c23cb7cSEd Maste 	Dwarf_Unsigned offset, length, as_cu_offset;
4940*2c23cb7cSEd Maste 	Dwarf_Off die_off;
4941*2c23cb7cSEd Maste 	Dwarf_Signed cnt;
4942*2c23cb7cSEd Maste 	Dwarf_Half as_version, as_addrsz, as_segsz;
4943*2c23cb7cSEd Maste 	Dwarf_Error de;
4944*2c23cb7cSEd Maste 	Elf_Data *d;
4945*2c23cb7cSEd Maste 	int i, dwarf_size, elferr;
4946*2c23cb7cSEd Maste 
4947*2c23cb7cSEd Maste 	printf("\nContents of section .debug_aranges:\n");
4948*2c23cb7cSEd Maste 
4949*2c23cb7cSEd Maste 	s = NULL;
4950*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
4951*2c23cb7cSEd Maste 		s = &re->sl[i];
4952*2c23cb7cSEd Maste 		if (s->name != NULL && !strcmp(s->name, ".debug_aranges"))
4953*2c23cb7cSEd Maste 			break;
4954*2c23cb7cSEd Maste 	}
4955*2c23cb7cSEd Maste 	if ((size_t) i >= re->shnum)
4956*2c23cb7cSEd Maste 		return;
4957*2c23cb7cSEd Maste 
4958*2c23cb7cSEd Maste 	(void) elf_errno();
4959*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
4960*2c23cb7cSEd Maste 		elferr = elf_errno();
4961*2c23cb7cSEd Maste 		if (elferr != 0)
4962*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(-1));
4963*2c23cb7cSEd Maste 		return;
4964*2c23cb7cSEd Maste 	}
4965*2c23cb7cSEd Maste 	if (d->d_size <= 0)
4966*2c23cb7cSEd Maste 		return;
4967*2c23cb7cSEd Maste 
4968*2c23cb7cSEd Maste 	/* Read in the .debug_aranges section table header. */
4969*2c23cb7cSEd Maste 	offset = 0;
4970*2c23cb7cSEd Maste 	length = re->dw_read(d, &offset, 4);
4971*2c23cb7cSEd Maste 	if (length == 0xffffffff) {
4972*2c23cb7cSEd Maste 		dwarf_size = 8;
4973*2c23cb7cSEd Maste 		length = re->dw_read(d, &offset, 8);
4974*2c23cb7cSEd Maste 	} else
4975*2c23cb7cSEd Maste 		dwarf_size = 4;
4976*2c23cb7cSEd Maste 
4977*2c23cb7cSEd Maste 	if (length > d->d_size - offset) {
4978*2c23cb7cSEd Maste 		warnx("invalid .dwarf_aranges section");
4979*2c23cb7cSEd Maste 		return;
4980*2c23cb7cSEd Maste 	}
4981*2c23cb7cSEd Maste 
4982*2c23cb7cSEd Maste 	as_version = re->dw_read(d, &offset, 2);
4983*2c23cb7cSEd Maste 	as_cu_offset = re->dw_read(d, &offset, dwarf_size);
4984*2c23cb7cSEd Maste 	as_addrsz = re->dw_read(d, &offset, 1);
4985*2c23cb7cSEd Maste 	as_segsz = re->dw_read(d, &offset, 1);
4986*2c23cb7cSEd Maste 
4987*2c23cb7cSEd Maste 	printf("  Length:\t\t\t%ju\n", (uintmax_t) length);
4988*2c23cb7cSEd Maste 	printf("  Version:\t\t\t%u\n", as_version);
4989*2c23cb7cSEd Maste 	printf("  Offset into .debug_info:\t%ju\n", (uintmax_t) as_cu_offset);
4990*2c23cb7cSEd Maste 	printf("  Pointer Size:\t\t\t%u\n", as_addrsz);
4991*2c23cb7cSEd Maste 	printf("  Segment Size:\t\t\t%u\n", as_segsz);
4992*2c23cb7cSEd Maste 
4993*2c23cb7cSEd Maste 	if (dwarf_get_aranges(re->dbg, &aranges, &cnt, &de) != DW_DLV_OK) {
4994*2c23cb7cSEd Maste 		warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de));
4995*2c23cb7cSEd Maste 		return;
4996*2c23cb7cSEd Maste 	}
4997*2c23cb7cSEd Maste 
4998*2c23cb7cSEd Maste 	printf("\n    Address  Length\n");
4999*2c23cb7cSEd Maste 	for (i = 0; i < cnt; i++) {
5000*2c23cb7cSEd Maste 		if (dwarf_get_arange_info(aranges[i], &start, &length,
5001*2c23cb7cSEd Maste 		    &die_off, &de) != DW_DLV_OK) {
5002*2c23cb7cSEd Maste 			warnx("dwarf_get_arange_info failed: %s",
5003*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5004*2c23cb7cSEd Maste 			continue;
5005*2c23cb7cSEd Maste 		}
5006*2c23cb7cSEd Maste 		printf("    %08jx %ju\n", (uintmax_t) start,
5007*2c23cb7cSEd Maste 		    (uintmax_t) length);
5008*2c23cb7cSEd Maste 	}
5009*2c23cb7cSEd Maste }
5010*2c23cb7cSEd Maste 
5011*2c23cb7cSEd Maste static void
5012*2c23cb7cSEd Maste dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die, Dwarf_Addr base)
5013*2c23cb7cSEd Maste {
5014*2c23cb7cSEd Maste 	Dwarf_Attribute *attr_list;
5015*2c23cb7cSEd Maste 	Dwarf_Ranges *ranges;
5016*2c23cb7cSEd Maste 	Dwarf_Die ret_die;
5017*2c23cb7cSEd Maste 	Dwarf_Error de;
5018*2c23cb7cSEd Maste 	Dwarf_Addr base0;
5019*2c23cb7cSEd Maste 	Dwarf_Half attr;
5020*2c23cb7cSEd Maste 	Dwarf_Signed attr_count, cnt;
5021*2c23cb7cSEd Maste 	Dwarf_Unsigned off, bytecnt;
5022*2c23cb7cSEd Maste 	int i, j, ret;
5023*2c23cb7cSEd Maste 
5024*2c23cb7cSEd Maste 	if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=
5025*2c23cb7cSEd Maste 	    DW_DLV_OK) {
5026*2c23cb7cSEd Maste 		if (ret == DW_DLV_ERROR)
5027*2c23cb7cSEd Maste 			warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));
5028*2c23cb7cSEd Maste 		goto cont_search;
5029*2c23cb7cSEd Maste 	}
5030*2c23cb7cSEd Maste 
5031*2c23cb7cSEd Maste 	for (i = 0; i < attr_count; i++) {
5032*2c23cb7cSEd Maste 		if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {
5033*2c23cb7cSEd Maste 			warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));
5034*2c23cb7cSEd Maste 			continue;
5035*2c23cb7cSEd Maste 		}
5036*2c23cb7cSEd Maste 		if (attr != DW_AT_ranges)
5037*2c23cb7cSEd Maste 			continue;
5038*2c23cb7cSEd Maste 		if (dwarf_formudata(attr_list[i], &off, &de) != DW_DLV_OK) {
5039*2c23cb7cSEd Maste 			warnx("dwarf_formudata failed: %s", dwarf_errmsg(de));
5040*2c23cb7cSEd Maste 			continue;
5041*2c23cb7cSEd Maste 		}
5042*2c23cb7cSEd Maste 		if (dwarf_get_ranges(re->dbg, (Dwarf_Off) off, &ranges, &cnt,
5043*2c23cb7cSEd Maste 		    &bytecnt, &de) != DW_DLV_OK)
5044*2c23cb7cSEd Maste 			continue;
5045*2c23cb7cSEd Maste 		base0 = base;
5046*2c23cb7cSEd Maste 		for (j = 0; j < cnt; j++) {
5047*2c23cb7cSEd Maste 			printf("    %08jx ", (uintmax_t) off);
5048*2c23cb7cSEd Maste 			if (ranges[j].dwr_type == DW_RANGES_END) {
5049*2c23cb7cSEd Maste 				printf("%s\n", "<End of list>");
5050*2c23cb7cSEd Maste 				continue;
5051*2c23cb7cSEd Maste 			} else if (ranges[j].dwr_type ==
5052*2c23cb7cSEd Maste 			    DW_RANGES_ADDRESS_SELECTION) {
5053*2c23cb7cSEd Maste 				base0 = ranges[j].dwr_addr2;
5054*2c23cb7cSEd Maste 				continue;
5055*2c23cb7cSEd Maste 			}
5056*2c23cb7cSEd Maste 			if (re->ec == ELFCLASS32)
5057*2c23cb7cSEd Maste 				printf("%08jx %08jx\n",
5058*2c23cb7cSEd Maste 				    ranges[j].dwr_addr1 + base0,
5059*2c23cb7cSEd Maste 				    ranges[j].dwr_addr2 + base0);
5060*2c23cb7cSEd Maste 			else
5061*2c23cb7cSEd Maste 				printf("%016jx %016jx\n",
5062*2c23cb7cSEd Maste 				    ranges[j].dwr_addr1 + base0,
5063*2c23cb7cSEd Maste 				    ranges[j].dwr_addr2 + base0);
5064*2c23cb7cSEd Maste 		}
5065*2c23cb7cSEd Maste 	}
5066*2c23cb7cSEd Maste 
5067*2c23cb7cSEd Maste cont_search:
5068*2c23cb7cSEd Maste 	/* Search children. */
5069*2c23cb7cSEd Maste 	ret = dwarf_child(die, &ret_die, &de);
5070*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
5071*2c23cb7cSEd Maste 		warnx("dwarf_child: %s", dwarf_errmsg(de));
5072*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
5073*2c23cb7cSEd Maste 		dump_dwarf_ranges_foreach(re, ret_die, base);
5074*2c23cb7cSEd Maste 
5075*2c23cb7cSEd Maste 	/* Search sibling. */
5076*2c23cb7cSEd Maste 	ret = dwarf_siblingof(re->dbg, die, &ret_die, &de);
5077*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
5078*2c23cb7cSEd Maste 		warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
5079*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
5080*2c23cb7cSEd Maste 		dump_dwarf_ranges_foreach(re, ret_die, base);
5081*2c23cb7cSEd Maste }
5082*2c23cb7cSEd Maste 
5083*2c23cb7cSEd Maste static void
5084*2c23cb7cSEd Maste dump_dwarf_ranges(struct readelf *re)
5085*2c23cb7cSEd Maste {
5086*2c23cb7cSEd Maste 	Dwarf_Ranges *ranges;
5087*2c23cb7cSEd Maste 	Dwarf_Die die;
5088*2c23cb7cSEd Maste 	Dwarf_Signed cnt;
5089*2c23cb7cSEd Maste 	Dwarf_Unsigned bytecnt;
5090*2c23cb7cSEd Maste 	Dwarf_Half tag;
5091*2c23cb7cSEd Maste 	Dwarf_Error de;
5092*2c23cb7cSEd Maste 	Dwarf_Unsigned lowpc;
5093*2c23cb7cSEd Maste 	int ret;
5094*2c23cb7cSEd Maste 
5095*2c23cb7cSEd Maste 	if (dwarf_get_ranges(re->dbg, 0, &ranges, &cnt, &bytecnt, &de) !=
5096*2c23cb7cSEd Maste 	    DW_DLV_OK)
5097*2c23cb7cSEd Maste 		return;
5098*2c23cb7cSEd Maste 
5099*2c23cb7cSEd Maste 	printf("Contents of the .debug_ranges section:\n\n");
5100*2c23cb7cSEd Maste 	if (re->ec == ELFCLASS32)
5101*2c23cb7cSEd Maste 		printf("    %-8s %-8s %s\n", "Offset", "Begin", "End");
5102*2c23cb7cSEd Maste 	else
5103*2c23cb7cSEd Maste 		printf("    %-8s %-16s %s\n", "Offset", "Begin", "End");
5104*2c23cb7cSEd Maste 
5105*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,
5106*2c23cb7cSEd Maste 	    NULL, &de)) == DW_DLV_OK) {
5107*2c23cb7cSEd Maste 		die = NULL;
5108*2c23cb7cSEd Maste 		if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK)
5109*2c23cb7cSEd Maste 			continue;
5110*2c23cb7cSEd Maste 		if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
5111*2c23cb7cSEd Maste 			warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
5112*2c23cb7cSEd Maste 			continue;
5113*2c23cb7cSEd Maste 		}
5114*2c23cb7cSEd Maste 		/* XXX: What about DW_TAG_partial_unit? */
5115*2c23cb7cSEd Maste 		lowpc = 0;
5116*2c23cb7cSEd Maste 		if (tag == DW_TAG_compile_unit) {
5117*2c23cb7cSEd Maste 			if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc,
5118*2c23cb7cSEd Maste 			    &de) != DW_DLV_OK)
5119*2c23cb7cSEd Maste 				lowpc = 0;
5120*2c23cb7cSEd Maste 		}
5121*2c23cb7cSEd Maste 
5122*2c23cb7cSEd Maste 		dump_dwarf_ranges_foreach(re, die, (Dwarf_Addr) lowpc);
5123*2c23cb7cSEd Maste 	}
5124*2c23cb7cSEd Maste 	putchar('\n');
5125*2c23cb7cSEd Maste }
5126*2c23cb7cSEd Maste 
5127*2c23cb7cSEd Maste static void
5128*2c23cb7cSEd Maste dump_dwarf_macinfo(struct readelf *re)
5129*2c23cb7cSEd Maste {
5130*2c23cb7cSEd Maste 	Dwarf_Unsigned offset;
5131*2c23cb7cSEd Maste 	Dwarf_Signed cnt;
5132*2c23cb7cSEd Maste 	Dwarf_Macro_Details *md;
5133*2c23cb7cSEd Maste 	Dwarf_Error de;
5134*2c23cb7cSEd Maste 	const char *mi_str;
5135*2c23cb7cSEd Maste 	int i;
5136*2c23cb7cSEd Maste 
5137*2c23cb7cSEd Maste #define	_MAX_MACINFO_ENTRY	65535
5138*2c23cb7cSEd Maste 
5139*2c23cb7cSEd Maste 	printf("\nContents of section .debug_macinfo:\n\n");
5140*2c23cb7cSEd Maste 
5141*2c23cb7cSEd Maste 	offset = 0;
5142*2c23cb7cSEd Maste 	while (dwarf_get_macro_details(re->dbg, offset, _MAX_MACINFO_ENTRY,
5143*2c23cb7cSEd Maste 	    &cnt, &md, &de) == DW_DLV_OK) {
5144*2c23cb7cSEd Maste 		for (i = 0; i < cnt; i++) {
5145*2c23cb7cSEd Maste 			offset = md[i].dmd_offset + 1;
5146*2c23cb7cSEd Maste 			if (md[i].dmd_type == 0)
5147*2c23cb7cSEd Maste 				break;
5148*2c23cb7cSEd Maste 			if (dwarf_get_MACINFO_name(md[i].dmd_type, &mi_str) !=
5149*2c23cb7cSEd Maste 			    DW_DLV_OK) {
5150*2c23cb7cSEd Maste 				warnx("dwarf_get_MACINFO_name failed: %s",
5151*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
5152*2c23cb7cSEd Maste 				continue;
5153*2c23cb7cSEd Maste 			}
5154*2c23cb7cSEd Maste 			printf(" %s", mi_str);
5155*2c23cb7cSEd Maste 			switch (md[i].dmd_type) {
5156*2c23cb7cSEd Maste 			case DW_MACINFO_define:
5157*2c23cb7cSEd Maste 			case DW_MACINFO_undef:
5158*2c23cb7cSEd Maste 				printf(" - lineno : %jd macro : %s\n",
5159*2c23cb7cSEd Maste 				    (intmax_t) md[i].dmd_lineno,
5160*2c23cb7cSEd Maste 				    md[i].dmd_macro);
5161*2c23cb7cSEd Maste 				break;
5162*2c23cb7cSEd Maste 			case DW_MACINFO_start_file:
5163*2c23cb7cSEd Maste 				printf(" - lineno : %jd filenum : %jd\n",
5164*2c23cb7cSEd Maste 				    (intmax_t) md[i].dmd_lineno,
5165*2c23cb7cSEd Maste 				    (intmax_t) md[i].dmd_fileindex);
5166*2c23cb7cSEd Maste 				break;
5167*2c23cb7cSEd Maste 			default:
5168*2c23cb7cSEd Maste 				putchar('\n');
5169*2c23cb7cSEd Maste 				break;
5170*2c23cb7cSEd Maste 			}
5171*2c23cb7cSEd Maste 		}
5172*2c23cb7cSEd Maste 	}
5173*2c23cb7cSEd Maste 
5174*2c23cb7cSEd Maste #undef	_MAX_MACINFO_ENTRY
5175*2c23cb7cSEd Maste }
5176*2c23cb7cSEd Maste 
5177*2c23cb7cSEd Maste static void
5178*2c23cb7cSEd Maste dump_dwarf_frame_inst(Dwarf_Cie cie, uint8_t *insts, Dwarf_Unsigned len,
5179*2c23cb7cSEd Maste     Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc, Dwarf_Debug dbg)
5180*2c23cb7cSEd Maste {
5181*2c23cb7cSEd Maste 	Dwarf_Frame_Op *oplist;
5182*2c23cb7cSEd Maste 	Dwarf_Signed opcnt, delta;
5183*2c23cb7cSEd Maste 	Dwarf_Small op;
5184*2c23cb7cSEd Maste 	Dwarf_Error de;
5185*2c23cb7cSEd Maste 	const char *op_str;
5186*2c23cb7cSEd Maste 	int i;
5187*2c23cb7cSEd Maste 
5188*2c23cb7cSEd Maste 	if (dwarf_expand_frame_instructions(cie, insts, len, &oplist,
5189*2c23cb7cSEd Maste 	    &opcnt, &de) != DW_DLV_OK) {
5190*2c23cb7cSEd Maste 		warnx("dwarf_expand_frame_instructions failed: %s",
5191*2c23cb7cSEd Maste 		    dwarf_errmsg(de));
5192*2c23cb7cSEd Maste 		return;
5193*2c23cb7cSEd Maste 	}
5194*2c23cb7cSEd Maste 
5195*2c23cb7cSEd Maste 	for (i = 0; i < opcnt; i++) {
5196*2c23cb7cSEd Maste 		if (oplist[i].fp_base_op != 0)
5197*2c23cb7cSEd Maste 			op = oplist[i].fp_base_op << 6;
5198*2c23cb7cSEd Maste 		else
5199*2c23cb7cSEd Maste 			op = oplist[i].fp_extended_op;
5200*2c23cb7cSEd Maste 		if (dwarf_get_CFA_name(op, &op_str) != DW_DLV_OK) {
5201*2c23cb7cSEd Maste 			warnx("dwarf_get_CFA_name failed: %s",
5202*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5203*2c23cb7cSEd Maste 			continue;
5204*2c23cb7cSEd Maste 		}
5205*2c23cb7cSEd Maste 		printf("  %s", op_str);
5206*2c23cb7cSEd Maste 		switch (op) {
5207*2c23cb7cSEd Maste 		case DW_CFA_advance_loc:
5208*2c23cb7cSEd Maste 			delta = oplist[i].fp_offset * caf;
5209*2c23cb7cSEd Maste 			pc += delta;
5210*2c23cb7cSEd Maste 			printf(": %ju to %08jx", (uintmax_t) delta,
5211*2c23cb7cSEd Maste 			    (uintmax_t) pc);
5212*2c23cb7cSEd Maste 			break;
5213*2c23cb7cSEd Maste 		case DW_CFA_offset:
5214*2c23cb7cSEd Maste 		case DW_CFA_offset_extended:
5215*2c23cb7cSEd Maste 		case DW_CFA_offset_extended_sf:
5216*2c23cb7cSEd Maste 			delta = oplist[i].fp_offset * daf;
5217*2c23cb7cSEd Maste 			printf(": r%u at cfa%+jd", oplist[i].fp_register,
5218*2c23cb7cSEd Maste 			    (intmax_t) delta);
5219*2c23cb7cSEd Maste 			break;
5220*2c23cb7cSEd Maste 		case DW_CFA_restore:
5221*2c23cb7cSEd Maste 			printf(": r%u", oplist[i].fp_register);
5222*2c23cb7cSEd Maste 			break;
5223*2c23cb7cSEd Maste 		case DW_CFA_set_loc:
5224*2c23cb7cSEd Maste 			pc = oplist[i].fp_offset;
5225*2c23cb7cSEd Maste 			printf(": to %08jx", (uintmax_t) pc);
5226*2c23cb7cSEd Maste 			break;
5227*2c23cb7cSEd Maste 		case DW_CFA_advance_loc1:
5228*2c23cb7cSEd Maste 		case DW_CFA_advance_loc2:
5229*2c23cb7cSEd Maste 		case DW_CFA_advance_loc4:
5230*2c23cb7cSEd Maste 			pc += oplist[i].fp_offset;
5231*2c23cb7cSEd Maste 			printf(": %jd to %08jx", (intmax_t) oplist[i].fp_offset,
5232*2c23cb7cSEd Maste 			    (uintmax_t) pc);
5233*2c23cb7cSEd Maste 			break;
5234*2c23cb7cSEd Maste 		case DW_CFA_def_cfa:
5235*2c23cb7cSEd Maste 			printf(": r%u ofs %ju", oplist[i].fp_register,
5236*2c23cb7cSEd Maste 			    (uintmax_t) oplist[i].fp_offset);
5237*2c23cb7cSEd Maste 			break;
5238*2c23cb7cSEd Maste 		case DW_CFA_def_cfa_sf:
5239*2c23cb7cSEd Maste 			printf(": r%u ofs %jd", oplist[i].fp_register,
5240*2c23cb7cSEd Maste 			    (intmax_t) (oplist[i].fp_offset * daf));
5241*2c23cb7cSEd Maste 			break;
5242*2c23cb7cSEd Maste 		case DW_CFA_def_cfa_register:
5243*2c23cb7cSEd Maste 			printf(": r%u", oplist[i].fp_register);
5244*2c23cb7cSEd Maste 			break;
5245*2c23cb7cSEd Maste 		case DW_CFA_def_cfa_offset:
5246*2c23cb7cSEd Maste 			printf(": %ju", (uintmax_t) oplist[i].fp_offset);
5247*2c23cb7cSEd Maste 			break;
5248*2c23cb7cSEd Maste 		case DW_CFA_def_cfa_offset_sf:
5249*2c23cb7cSEd Maste 			printf(": %jd", (intmax_t) (oplist[i].fp_offset * daf));
5250*2c23cb7cSEd Maste 			break;
5251*2c23cb7cSEd Maste 		default:
5252*2c23cb7cSEd Maste 			break;
5253*2c23cb7cSEd Maste 		}
5254*2c23cb7cSEd Maste 		putchar('\n');
5255*2c23cb7cSEd Maste 	}
5256*2c23cb7cSEd Maste 
5257*2c23cb7cSEd Maste 	dwarf_dealloc(dbg, oplist, DW_DLA_FRAME_BLOCK);
5258*2c23cb7cSEd Maste }
5259*2c23cb7cSEd Maste 
5260*2c23cb7cSEd Maste static char *
5261*2c23cb7cSEd Maste get_regoff_str(Dwarf_Half reg, Dwarf_Addr off)
5262*2c23cb7cSEd Maste {
5263*2c23cb7cSEd Maste 	static char rs[16];
5264*2c23cb7cSEd Maste 
5265*2c23cb7cSEd Maste 	if (reg == DW_FRAME_UNDEFINED_VAL || reg == DW_FRAME_REG_INITIAL_VALUE)
5266*2c23cb7cSEd Maste 		snprintf(rs, sizeof(rs), "%c", 'u');
5267*2c23cb7cSEd Maste 	else if (reg == DW_FRAME_CFA_COL)
5268*2c23cb7cSEd Maste 		snprintf(rs, sizeof(rs), "c%+jd", (intmax_t) off);
5269*2c23cb7cSEd Maste 	else
5270*2c23cb7cSEd Maste 		snprintf(rs, sizeof(rs), "r%u%+jd", reg, (intmax_t) off);
5271*2c23cb7cSEd Maste 
5272*2c23cb7cSEd Maste 	return (rs);
5273*2c23cb7cSEd Maste }
5274*2c23cb7cSEd Maste 
5275*2c23cb7cSEd Maste static int
5276*2c23cb7cSEd Maste dump_dwarf_frame_regtable(Dwarf_Fde fde, Dwarf_Addr pc, Dwarf_Unsigned func_len,
5277*2c23cb7cSEd Maste     Dwarf_Half cie_ra)
5278*2c23cb7cSEd Maste {
5279*2c23cb7cSEd Maste 	Dwarf_Regtable rt;
5280*2c23cb7cSEd Maste 	Dwarf_Addr row_pc, end_pc, pre_pc, cur_pc;
5281*2c23cb7cSEd Maste 	Dwarf_Error de;
5282*2c23cb7cSEd Maste 	char rn[16];
5283*2c23cb7cSEd Maste 	char *vec;
5284*2c23cb7cSEd Maste 	int i;
5285*2c23cb7cSEd Maste 
5286*2c23cb7cSEd Maste #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
5287*2c23cb7cSEd Maste #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
5288*2c23cb7cSEd Maste #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
5289*2c23cb7cSEd Maste #define	RT(x) rt.rules[(x)]
5290*2c23cb7cSEd Maste 
5291*2c23cb7cSEd Maste 	vec = calloc((DW_REG_TABLE_SIZE + 7) / 8, 1);
5292*2c23cb7cSEd Maste 	if (vec == NULL)
5293*2c23cb7cSEd Maste 		err(EXIT_FAILURE, "calloc failed");
5294*2c23cb7cSEd Maste 
5295*2c23cb7cSEd Maste 	pre_pc = ~((Dwarf_Addr) 0);
5296*2c23cb7cSEd Maste 	cur_pc = pc;
5297*2c23cb7cSEd Maste 	end_pc = pc + func_len;
5298*2c23cb7cSEd Maste 	for (; cur_pc < end_pc; cur_pc++) {
5299*2c23cb7cSEd Maste 		if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc,
5300*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK) {
5301*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_info_for_all_regs failed: %s\n",
5302*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5303*2c23cb7cSEd Maste 			return (-1);
5304*2c23cb7cSEd Maste 		}
5305*2c23cb7cSEd Maste 		if (row_pc == pre_pc)
5306*2c23cb7cSEd Maste 			continue;
5307*2c23cb7cSEd Maste 		pre_pc = row_pc;
5308*2c23cb7cSEd Maste 		for (i = 1; i < DW_REG_TABLE_SIZE; i++) {
5309*2c23cb7cSEd Maste 			if (rt.rules[i].dw_regnum != DW_FRAME_REG_INITIAL_VALUE)
5310*2c23cb7cSEd Maste 				BIT_SET(vec, i);
5311*2c23cb7cSEd Maste 		}
5312*2c23cb7cSEd Maste 	}
5313*2c23cb7cSEd Maste 
5314*2c23cb7cSEd Maste 	printf("   LOC   CFA      ");
5315*2c23cb7cSEd Maste 	for (i = 1; i < DW_REG_TABLE_SIZE; i++) {
5316*2c23cb7cSEd Maste 		if (BIT_ISSET(vec, i)) {
5317*2c23cb7cSEd Maste 			if ((Dwarf_Half) i == cie_ra)
5318*2c23cb7cSEd Maste 				printf("ra   ");
5319*2c23cb7cSEd Maste 			else {
5320*2c23cb7cSEd Maste 				snprintf(rn, sizeof(rn), "r%d", i);
5321*2c23cb7cSEd Maste 				printf("%-5s", rn);
5322*2c23cb7cSEd Maste 			}
5323*2c23cb7cSEd Maste 		}
5324*2c23cb7cSEd Maste 	}
5325*2c23cb7cSEd Maste 	putchar('\n');
5326*2c23cb7cSEd Maste 
5327*2c23cb7cSEd Maste 	pre_pc = ~((Dwarf_Addr) 0);
5328*2c23cb7cSEd Maste 	cur_pc = pc;
5329*2c23cb7cSEd Maste 	end_pc = pc + func_len;
5330*2c23cb7cSEd Maste 	for (; cur_pc < end_pc; cur_pc++) {
5331*2c23cb7cSEd Maste 		if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc,
5332*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK) {
5333*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_info_for_all_regs failed: %s\n",
5334*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5335*2c23cb7cSEd Maste 			return (-1);
5336*2c23cb7cSEd Maste 		}
5337*2c23cb7cSEd Maste 		if (row_pc == pre_pc)
5338*2c23cb7cSEd Maste 			continue;
5339*2c23cb7cSEd Maste 		pre_pc = row_pc;
5340*2c23cb7cSEd Maste 		printf("%08jx ", (uintmax_t) row_pc);
5341*2c23cb7cSEd Maste 		printf("%-8s ", get_regoff_str(RT(0).dw_regnum,
5342*2c23cb7cSEd Maste 		    RT(0).dw_offset));
5343*2c23cb7cSEd Maste 		for (i = 1; i < DW_REG_TABLE_SIZE; i++) {
5344*2c23cb7cSEd Maste 			if (BIT_ISSET(vec, i)) {
5345*2c23cb7cSEd Maste 				printf("%-5s", get_regoff_str(RT(i).dw_regnum,
5346*2c23cb7cSEd Maste 				    RT(i).dw_offset));
5347*2c23cb7cSEd Maste 			}
5348*2c23cb7cSEd Maste 		}
5349*2c23cb7cSEd Maste 		putchar('\n');
5350*2c23cb7cSEd Maste 	}
5351*2c23cb7cSEd Maste 
5352*2c23cb7cSEd Maste 	free(vec);
5353*2c23cb7cSEd Maste 
5354*2c23cb7cSEd Maste 	return (0);
5355*2c23cb7cSEd Maste 
5356*2c23cb7cSEd Maste #undef	BIT_SET
5357*2c23cb7cSEd Maste #undef	BIT_CLR
5358*2c23cb7cSEd Maste #undef	BIT_ISSET
5359*2c23cb7cSEd Maste #undef	RT
5360*2c23cb7cSEd Maste }
5361*2c23cb7cSEd Maste 
5362*2c23cb7cSEd Maste static void
5363*2c23cb7cSEd Maste dump_dwarf_frame_section(struct readelf *re, struct section *s, int alt)
5364*2c23cb7cSEd Maste {
5365*2c23cb7cSEd Maste 	Dwarf_Cie *cie_list, cie, pre_cie;
5366*2c23cb7cSEd Maste 	Dwarf_Fde *fde_list, fde;
5367*2c23cb7cSEd Maste 	Dwarf_Off cie_offset, fde_offset;
5368*2c23cb7cSEd Maste 	Dwarf_Unsigned cie_length, fde_instlen;
5369*2c23cb7cSEd Maste 	Dwarf_Unsigned cie_caf, cie_daf, cie_instlen, func_len, fde_length;
5370*2c23cb7cSEd Maste 	Dwarf_Signed cie_count, fde_count, cie_index;
5371*2c23cb7cSEd Maste 	Dwarf_Addr low_pc;
5372*2c23cb7cSEd Maste 	Dwarf_Half cie_ra;
5373*2c23cb7cSEd Maste 	Dwarf_Small cie_version;
5374*2c23cb7cSEd Maste 	Dwarf_Ptr fde_addr, fde_inst, cie_inst;
5375*2c23cb7cSEd Maste 	char *cie_aug, c;
5376*2c23cb7cSEd Maste 	int i, eh_frame;
5377*2c23cb7cSEd Maste 	Dwarf_Error de;
5378*2c23cb7cSEd Maste 
5379*2c23cb7cSEd Maste 	printf("\nThe section %s contains:\n\n", s->name);
5380*2c23cb7cSEd Maste 
5381*2c23cb7cSEd Maste 	if (!strcmp(s->name, ".debug_frame")) {
5382*2c23cb7cSEd Maste 		eh_frame = 0;
5383*2c23cb7cSEd Maste 		if (dwarf_get_fde_list(re->dbg, &cie_list, &cie_count,
5384*2c23cb7cSEd Maste 		    &fde_list, &fde_count, &de) != DW_DLV_OK) {
5385*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_list failed: %s",
5386*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5387*2c23cb7cSEd Maste 			return;
5388*2c23cb7cSEd Maste 		}
5389*2c23cb7cSEd Maste 	} else if (!strcmp(s->name, ".eh_frame")) {
5390*2c23cb7cSEd Maste 		eh_frame = 1;
5391*2c23cb7cSEd Maste 		if (dwarf_get_fde_list_eh(re->dbg, &cie_list, &cie_count,
5392*2c23cb7cSEd Maste 		    &fde_list, &fde_count, &de) != DW_DLV_OK) {
5393*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_list_eh failed: %s",
5394*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5395*2c23cb7cSEd Maste 			return;
5396*2c23cb7cSEd Maste 		}
5397*2c23cb7cSEd Maste 	} else
5398*2c23cb7cSEd Maste 		return;
5399*2c23cb7cSEd Maste 
5400*2c23cb7cSEd Maste 	pre_cie = NULL;
5401*2c23cb7cSEd Maste 	for (i = 0; i < fde_count; i++) {
5402*2c23cb7cSEd Maste 		if (dwarf_get_fde_n(fde_list, i, &fde, &de) != DW_DLV_OK) {
5403*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de));
5404*2c23cb7cSEd Maste 			continue;
5405*2c23cb7cSEd Maste 		}
5406*2c23cb7cSEd Maste 		if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) {
5407*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de));
5408*2c23cb7cSEd Maste 			continue;
5409*2c23cb7cSEd Maste 		}
5410*2c23cb7cSEd Maste 		if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_addr,
5411*2c23cb7cSEd Maste 		    &fde_length, &cie_offset, &cie_index, &fde_offset,
5412*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK) {
5413*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_range failed: %s",
5414*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5415*2c23cb7cSEd Maste 			continue;
5416*2c23cb7cSEd Maste 		}
5417*2c23cb7cSEd Maste 		if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_instlen,
5418*2c23cb7cSEd Maste 		    &de) != DW_DLV_OK) {
5419*2c23cb7cSEd Maste 			warnx("dwarf_get_fde_instr_bytes failed: %s",
5420*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
5421*2c23cb7cSEd Maste 			continue;
5422*2c23cb7cSEd Maste 		}
5423*2c23cb7cSEd Maste 		if (pre_cie == NULL || cie != pre_cie) {
5424*2c23cb7cSEd Maste 			pre_cie = cie;
5425*2c23cb7cSEd Maste 			if (dwarf_get_cie_info(cie, &cie_length, &cie_version,
5426*2c23cb7cSEd Maste 			    &cie_aug, &cie_caf, &cie_daf, &cie_ra,
5427*2c23cb7cSEd Maste 			    &cie_inst, &cie_instlen, &de) != DW_DLV_OK) {
5428*2c23cb7cSEd Maste 				warnx("dwarf_get_cie_info failed: %s",
5429*2c23cb7cSEd Maste 				    dwarf_errmsg(de));
5430*2c23cb7cSEd Maste 				continue;
5431*2c23cb7cSEd Maste 			}
5432*2c23cb7cSEd Maste 			printf("%08jx %08jx %8.8jx CIE",
5433*2c23cb7cSEd Maste 			    (uintmax_t) cie_offset,
5434*2c23cb7cSEd Maste 			    (uintmax_t) cie_length,
5435*2c23cb7cSEd Maste 			    (uintmax_t) (eh_frame ? 0 : ~0U));
5436*2c23cb7cSEd Maste 			if (!alt) {
5437*2c23cb7cSEd Maste 				putchar('\n');
5438*2c23cb7cSEd Maste 				printf("  Version:\t\t\t%u\n", cie_version);
5439*2c23cb7cSEd Maste 				printf("  Augmentation:\t\t\t\"");
5440*2c23cb7cSEd Maste 				while ((c = *cie_aug++) != '\0')
5441*2c23cb7cSEd Maste 					putchar(c);
5442*2c23cb7cSEd Maste 				printf("\"\n");
5443*2c23cb7cSEd Maste 				printf("  Code alignment factor:\t%ju\n",
5444*2c23cb7cSEd Maste 				    (uintmax_t) cie_caf);
5445*2c23cb7cSEd Maste 				printf("  Data alignment factor:\t%jd\n",
5446*2c23cb7cSEd Maste 				    (intmax_t) cie_daf);
5447*2c23cb7cSEd Maste 				printf("  Return address column:\t%ju\n",
5448*2c23cb7cSEd Maste 				    (uintmax_t) cie_ra);
5449*2c23cb7cSEd Maste 				putchar('\n');
5450*2c23cb7cSEd Maste 				dump_dwarf_frame_inst(cie, cie_inst,
5451*2c23cb7cSEd Maste 				    cie_instlen, cie_caf, cie_daf, 0,
5452*2c23cb7cSEd Maste 				    re->dbg);
5453*2c23cb7cSEd Maste 				putchar('\n');
5454*2c23cb7cSEd Maste 			} else {
5455*2c23cb7cSEd Maste 				printf(" \"");
5456*2c23cb7cSEd Maste 				while ((c = *cie_aug++) != '\0')
5457*2c23cb7cSEd Maste 					putchar(c);
5458*2c23cb7cSEd Maste 				putchar('"');
5459*2c23cb7cSEd Maste 				printf(" cf=%ju df=%jd ra=%ju\n",
5460*2c23cb7cSEd Maste 				    (uintmax_t) cie_caf,
5461*2c23cb7cSEd Maste 				    (uintmax_t) cie_daf,
5462*2c23cb7cSEd Maste 				    (uintmax_t) cie_ra);
5463*2c23cb7cSEd Maste 				dump_dwarf_frame_regtable(fde, low_pc, 1,
5464*2c23cb7cSEd Maste 				    cie_ra);
5465*2c23cb7cSEd Maste 				putchar('\n');
5466*2c23cb7cSEd Maste 			}
5467*2c23cb7cSEd Maste 		}
5468*2c23cb7cSEd Maste 		printf("%08jx %08jx %08jx FDE cie=%08jx pc=%08jx..%08jx\n",
5469*2c23cb7cSEd Maste 		    (uintmax_t) fde_offset, (uintmax_t) fde_length,
5470*2c23cb7cSEd Maste 		    (uintmax_t) cie_offset,
5471*2c23cb7cSEd Maste 		    (uintmax_t) (eh_frame ? fde_offset + 4 - cie_offset :
5472*2c23cb7cSEd Maste 			cie_offset),
5473*2c23cb7cSEd Maste 		    (uintmax_t) low_pc, (uintmax_t) (low_pc + func_len));
5474*2c23cb7cSEd Maste 		if (!alt)
5475*2c23cb7cSEd Maste 			dump_dwarf_frame_inst(cie, fde_inst, fde_instlen,
5476*2c23cb7cSEd Maste 			    cie_caf, cie_daf, low_pc, re->dbg);
5477*2c23cb7cSEd Maste 		else
5478*2c23cb7cSEd Maste 			dump_dwarf_frame_regtable(fde, low_pc, func_len,
5479*2c23cb7cSEd Maste 			    cie_ra);
5480*2c23cb7cSEd Maste 		putchar('\n');
5481*2c23cb7cSEd Maste 	}
5482*2c23cb7cSEd Maste }
5483*2c23cb7cSEd Maste 
5484*2c23cb7cSEd Maste static void
5485*2c23cb7cSEd Maste dump_dwarf_frame(struct readelf *re, int alt)
5486*2c23cb7cSEd Maste {
5487*2c23cb7cSEd Maste 	struct section *s;
5488*2c23cb7cSEd Maste 	int i;
5489*2c23cb7cSEd Maste 
5490*2c23cb7cSEd Maste 	(void) dwarf_set_frame_cfa_value(re->dbg, DW_FRAME_CFA_COL);
5491*2c23cb7cSEd Maste 
5492*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
5493*2c23cb7cSEd Maste 		s = &re->sl[i];
5494*2c23cb7cSEd Maste 		if (s->name != NULL && (!strcmp(s->name, ".debug_frame") ||
5495*2c23cb7cSEd Maste 		    !strcmp(s->name, ".eh_frame")))
5496*2c23cb7cSEd Maste 			dump_dwarf_frame_section(re, s, alt);
5497*2c23cb7cSEd Maste 	}
5498*2c23cb7cSEd Maste }
5499*2c23cb7cSEd Maste 
5500*2c23cb7cSEd Maste static void
5501*2c23cb7cSEd Maste dump_dwarf_str(struct readelf *re)
5502*2c23cb7cSEd Maste {
5503*2c23cb7cSEd Maste 	struct section *s;
5504*2c23cb7cSEd Maste 	Elf_Data *d;
5505*2c23cb7cSEd Maste 	unsigned char *p;
5506*2c23cb7cSEd Maste 	int elferr, end, i, j;
5507*2c23cb7cSEd Maste 
5508*2c23cb7cSEd Maste 	printf("\nContents of section .debug_str:\n");
5509*2c23cb7cSEd Maste 
5510*2c23cb7cSEd Maste 	s = NULL;
5511*2c23cb7cSEd Maste 	for (i = 0; (size_t) i < re->shnum; i++) {
5512*2c23cb7cSEd Maste 		s = &re->sl[i];
5513*2c23cb7cSEd Maste 		if (s->name != NULL && !strcmp(s->name, ".debug_str"))
5514*2c23cb7cSEd Maste 			break;
5515*2c23cb7cSEd Maste 	}
5516*2c23cb7cSEd Maste 	if ((size_t) i >= re->shnum)
5517*2c23cb7cSEd Maste 		return;
5518*2c23cb7cSEd Maste 
5519*2c23cb7cSEd Maste 	(void) elf_errno();
5520*2c23cb7cSEd Maste 	if ((d = elf_getdata(s->scn, NULL)) == NULL) {
5521*2c23cb7cSEd Maste 		elferr = elf_errno();
5522*2c23cb7cSEd Maste 		if (elferr != 0)
5523*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(-1));
5524*2c23cb7cSEd Maste 		return;
5525*2c23cb7cSEd Maste 	}
5526*2c23cb7cSEd Maste 	if (d->d_size <= 0)
5527*2c23cb7cSEd Maste 		return;
5528*2c23cb7cSEd Maste 
5529*2c23cb7cSEd Maste 	for (i = 0, p = d->d_buf; (size_t) i < d->d_size; i += 16) {
5530*2c23cb7cSEd Maste 		printf("  0x%08x", (unsigned int) i);
5531*2c23cb7cSEd Maste 		if ((size_t) i + 16 > d->d_size)
5532*2c23cb7cSEd Maste 			end = d->d_size;
5533*2c23cb7cSEd Maste 		else
5534*2c23cb7cSEd Maste 			end = i + 16;
5535*2c23cb7cSEd Maste 		for (j = i; j < i + 16; j++) {
5536*2c23cb7cSEd Maste 			if ((j - i) % 4 == 0)
5537*2c23cb7cSEd Maste 				putchar(' ');
5538*2c23cb7cSEd Maste 			if (j >= end) {
5539*2c23cb7cSEd Maste 				printf("  ");
5540*2c23cb7cSEd Maste 				continue;
5541*2c23cb7cSEd Maste 			}
5542*2c23cb7cSEd Maste 			printf("%02x", (uint8_t) p[j]);
5543*2c23cb7cSEd Maste 		}
5544*2c23cb7cSEd Maste 		putchar(' ');
5545*2c23cb7cSEd Maste 		for (j = i; j < end; j++) {
5546*2c23cb7cSEd Maste 			if (isprint(p[j]))
5547*2c23cb7cSEd Maste 				putchar(p[j]);
5548*2c23cb7cSEd Maste 			else if (p[j] == 0)
5549*2c23cb7cSEd Maste 				putchar('.');
5550*2c23cb7cSEd Maste 			else
5551*2c23cb7cSEd Maste 				putchar(' ');
5552*2c23cb7cSEd Maste 		}
5553*2c23cb7cSEd Maste 		putchar('\n');
5554*2c23cb7cSEd Maste 	}
5555*2c23cb7cSEd Maste }
5556*2c23cb7cSEd Maste 
5557*2c23cb7cSEd Maste struct loc_at {
5558*2c23cb7cSEd Maste 	Dwarf_Attribute la_at;
5559*2c23cb7cSEd Maste 	Dwarf_Unsigned la_off;
5560*2c23cb7cSEd Maste 	Dwarf_Unsigned la_lowpc;
5561*2c23cb7cSEd Maste 	TAILQ_ENTRY(loc_at) la_next;
5562*2c23cb7cSEd Maste };
5563*2c23cb7cSEd Maste 
5564*2c23cb7cSEd Maste static TAILQ_HEAD(, loc_at) lalist = TAILQ_HEAD_INITIALIZER(lalist);
5565*2c23cb7cSEd Maste 
5566*2c23cb7cSEd Maste static void
5567*2c23cb7cSEd Maste search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc)
5568*2c23cb7cSEd Maste {
5569*2c23cb7cSEd Maste 	Dwarf_Attribute *attr_list;
5570*2c23cb7cSEd Maste 	Dwarf_Die ret_die;
5571*2c23cb7cSEd Maste 	Dwarf_Unsigned off;
5572*2c23cb7cSEd Maste 	Dwarf_Signed attr_count;
5573*2c23cb7cSEd Maste 	Dwarf_Half attr, form;
5574*2c23cb7cSEd Maste 	Dwarf_Error de;
5575*2c23cb7cSEd Maste 	struct loc_at *la, *nla;
5576*2c23cb7cSEd Maste 	int i, ret;
5577*2c23cb7cSEd Maste 
5578*2c23cb7cSEd Maste 	if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=
5579*2c23cb7cSEd Maste 	    DW_DLV_OK) {
5580*2c23cb7cSEd Maste 		if (ret == DW_DLV_ERROR)
5581*2c23cb7cSEd Maste 			warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));
5582*2c23cb7cSEd Maste 		goto cont_search;
5583*2c23cb7cSEd Maste 	}
5584*2c23cb7cSEd Maste 	for (i = 0; i < attr_count; i++) {
5585*2c23cb7cSEd Maste 		if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {
5586*2c23cb7cSEd Maste 			warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));
5587*2c23cb7cSEd Maste 			continue;
5588*2c23cb7cSEd Maste 		}
5589*2c23cb7cSEd Maste 		if (attr != DW_AT_location &&
5590*2c23cb7cSEd Maste 		    attr != DW_AT_string_length &&
5591*2c23cb7cSEd Maste 		    attr != DW_AT_return_addr &&
5592*2c23cb7cSEd Maste 		    attr != DW_AT_data_member_location &&
5593*2c23cb7cSEd Maste 		    attr != DW_AT_frame_base &&
5594*2c23cb7cSEd Maste 		    attr != DW_AT_segment &&
5595*2c23cb7cSEd Maste 		    attr != DW_AT_static_link &&
5596*2c23cb7cSEd Maste 		    attr != DW_AT_use_location &&
5597*2c23cb7cSEd Maste 		    attr != DW_AT_vtable_elem_location)
5598*2c23cb7cSEd Maste 			continue;
5599*2c23cb7cSEd Maste 		if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) {
5600*2c23cb7cSEd Maste 			warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));
5601*2c23cb7cSEd Maste 			continue;
5602*2c23cb7cSEd Maste 		}
5603*2c23cb7cSEd Maste 		if (form != DW_FORM_data4 && form != DW_FORM_data8)
5604*2c23cb7cSEd Maste 			continue;
5605*2c23cb7cSEd Maste 		if (dwarf_formudata(attr_list[i], &off, &de) != DW_DLV_OK) {
5606*2c23cb7cSEd Maste 			warnx("dwarf_formudata failed: %s", dwarf_errmsg(de));
5607*2c23cb7cSEd Maste 			continue;
5608*2c23cb7cSEd Maste 		}
5609*2c23cb7cSEd Maste 		TAILQ_FOREACH(la, &lalist, la_next) {
5610*2c23cb7cSEd Maste 			if (off == la->la_off)
5611*2c23cb7cSEd Maste 				break;
5612*2c23cb7cSEd Maste 			if (off < la->la_off) {
5613*2c23cb7cSEd Maste 				if ((nla = malloc(sizeof(*nla))) == NULL)
5614*2c23cb7cSEd Maste 					err(EXIT_FAILURE, "malloc failed");
5615*2c23cb7cSEd Maste 				nla->la_at = attr_list[i];
5616*2c23cb7cSEd Maste 				nla->la_off = off;
5617*2c23cb7cSEd Maste 				nla->la_lowpc = lowpc;
5618*2c23cb7cSEd Maste 				TAILQ_INSERT_BEFORE(la, nla, la_next);
5619*2c23cb7cSEd Maste 				break;
5620*2c23cb7cSEd Maste 			}
5621*2c23cb7cSEd Maste 		}
5622*2c23cb7cSEd Maste 		if (la == NULL) {
5623*2c23cb7cSEd Maste 			if ((nla = malloc(sizeof(*nla))) == NULL)
5624*2c23cb7cSEd Maste 				err(EXIT_FAILURE, "malloc failed");
5625*2c23cb7cSEd Maste 			nla->la_at = attr_list[i];
5626*2c23cb7cSEd Maste 			nla->la_off = off;
5627*2c23cb7cSEd Maste 			nla->la_lowpc = lowpc;
5628*2c23cb7cSEd Maste 			TAILQ_INSERT_TAIL(&lalist, nla, la_next);
5629*2c23cb7cSEd Maste 		}
5630*2c23cb7cSEd Maste 	}
5631*2c23cb7cSEd Maste 
5632*2c23cb7cSEd Maste cont_search:
5633*2c23cb7cSEd Maste 	/* Search children. */
5634*2c23cb7cSEd Maste 	ret = dwarf_child(die, &ret_die, &de);
5635*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
5636*2c23cb7cSEd Maste 		warnx("dwarf_child: %s", dwarf_errmsg(de));
5637*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
5638*2c23cb7cSEd Maste 		search_loclist_at(re, ret_die, lowpc);
5639*2c23cb7cSEd Maste 
5640*2c23cb7cSEd Maste 	/* Search sibling. */
5641*2c23cb7cSEd Maste 	ret = dwarf_siblingof(re->dbg, die, &ret_die, &de);
5642*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
5643*2c23cb7cSEd Maste 		warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
5644*2c23cb7cSEd Maste 	else if (ret == DW_DLV_OK)
5645*2c23cb7cSEd Maste 		search_loclist_at(re, ret_die, lowpc);
5646*2c23cb7cSEd Maste }
5647*2c23cb7cSEd Maste 
5648*2c23cb7cSEd Maste static void
5649*2c23cb7cSEd Maste dump_dwarf_loclist(struct readelf *re)
5650*2c23cb7cSEd Maste {
5651*2c23cb7cSEd Maste 	Dwarf_Die die;
5652*2c23cb7cSEd Maste 	Dwarf_Locdesc **llbuf;
5653*2c23cb7cSEd Maste 	Dwarf_Unsigned lowpc;
5654*2c23cb7cSEd Maste 	Dwarf_Signed lcnt;
5655*2c23cb7cSEd Maste 	Dwarf_Half tag;
5656*2c23cb7cSEd Maste 	Dwarf_Error de;
5657*2c23cb7cSEd Maste 	Dwarf_Loc *lr;
5658*2c23cb7cSEd Maste 	struct loc_at *la;
5659*2c23cb7cSEd Maste 	const char *op_str;
5660*2c23cb7cSEd Maste 	int i, j, ret;
5661*2c23cb7cSEd Maste 
5662*2c23cb7cSEd Maste 	printf("\nContents of section .debug_loc:\n");
5663*2c23cb7cSEd Maste 
5664*2c23cb7cSEd Maste 	while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,
5665*2c23cb7cSEd Maste 	    NULL, &de)) == DW_DLV_OK) {
5666*2c23cb7cSEd Maste 		die = NULL;
5667*2c23cb7cSEd Maste 		if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK)
5668*2c23cb7cSEd Maste 			continue;
5669*2c23cb7cSEd Maste 		if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
5670*2c23cb7cSEd Maste 			warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
5671*2c23cb7cSEd Maste 			continue;
5672*2c23cb7cSEd Maste 		}
5673*2c23cb7cSEd Maste 		/* XXX: What about DW_TAG_partial_unit? */
5674*2c23cb7cSEd Maste 		lowpc = 0;
5675*2c23cb7cSEd Maste 		if (tag == DW_TAG_compile_unit) {
5676*2c23cb7cSEd Maste 			if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc,
5677*2c23cb7cSEd Maste 			    &de) != DW_DLV_OK)
5678*2c23cb7cSEd Maste 				lowpc = 0;
5679*2c23cb7cSEd Maste 		}
5680*2c23cb7cSEd Maste 
5681*2c23cb7cSEd Maste 		/* Search attributes for reference to .debug_loc section. */
5682*2c23cb7cSEd Maste 		search_loclist_at(re, die, lowpc);
5683*2c23cb7cSEd Maste 	}
5684*2c23cb7cSEd Maste 	if (ret == DW_DLV_ERROR)
5685*2c23cb7cSEd Maste 		warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
5686*2c23cb7cSEd Maste 
5687*2c23cb7cSEd Maste 	if (TAILQ_EMPTY(&lalist))
5688*2c23cb7cSEd Maste 		return;
5689*2c23cb7cSEd Maste 
5690*2c23cb7cSEd Maste 	printf("    Offset   Begin    End      Expression\n");
5691*2c23cb7cSEd Maste 
5692*2c23cb7cSEd Maste 	TAILQ_FOREACH(la, &lalist, la_next) {
5693*2c23cb7cSEd Maste 		if (dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de) !=
5694*2c23cb7cSEd Maste 		    DW_DLV_OK) {
5695*2c23cb7cSEd Maste 			warnx("dwarf_loclist_n failed: %s", dwarf_errmsg(de));
5696*2c23cb7cSEd Maste 			continue;
5697*2c23cb7cSEd Maste 		}
5698*2c23cb7cSEd Maste 		for (i = 0; i < lcnt; i++) {
5699*2c23cb7cSEd Maste 			printf("    %8.8jx ", la->la_off);
5700*2c23cb7cSEd Maste 			if (llbuf[i]->ld_lopc == 0 && llbuf[i]->ld_hipc == 0) {
5701*2c23cb7cSEd Maste 				printf("<End of list>\n");
5702*2c23cb7cSEd Maste 				continue;
5703*2c23cb7cSEd Maste 			}
5704*2c23cb7cSEd Maste 
5705*2c23cb7cSEd Maste 			/* TODO: handle base selection entry. */
5706*2c23cb7cSEd Maste 
5707*2c23cb7cSEd Maste 			printf("%8.8jx %8.8jx ",
5708*2c23cb7cSEd Maste 			    (uintmax_t) (la->la_lowpc + llbuf[i]->ld_lopc),
5709*2c23cb7cSEd Maste 			    (uintmax_t) (la->la_lowpc + llbuf[i]->ld_hipc));
5710*2c23cb7cSEd Maste 
5711*2c23cb7cSEd Maste 			putchar('(');
5712*2c23cb7cSEd Maste 			for (j = 0; (Dwarf_Half) j < llbuf[i]->ld_cents; j++) {
5713*2c23cb7cSEd Maste 				lr = &llbuf[i]->ld_s[j];
5714*2c23cb7cSEd Maste 				if (dwarf_get_OP_name(lr->lr_atom, &op_str) !=
5715*2c23cb7cSEd Maste 				    DW_DLV_OK) {
5716*2c23cb7cSEd Maste 					warnx("dwarf_get_OP_name failed: %s",
5717*2c23cb7cSEd Maste 					    dwarf_errmsg(de));
5718*2c23cb7cSEd Maste 					continue;
5719*2c23cb7cSEd Maste 				}
5720*2c23cb7cSEd Maste 
5721*2c23cb7cSEd Maste 				printf("%s", op_str);
5722*2c23cb7cSEd Maste 
5723*2c23cb7cSEd Maste 				switch (lr->lr_atom) {
5724*2c23cb7cSEd Maste 				/* Operations with no operands. */
5725*2c23cb7cSEd Maste 				case DW_OP_deref:
5726*2c23cb7cSEd Maste 				case DW_OP_reg0:
5727*2c23cb7cSEd Maste 				case DW_OP_reg1:
5728*2c23cb7cSEd Maste 				case DW_OP_reg2:
5729*2c23cb7cSEd Maste 				case DW_OP_reg3:
5730*2c23cb7cSEd Maste 				case DW_OP_reg4:
5731*2c23cb7cSEd Maste 				case DW_OP_reg5:
5732*2c23cb7cSEd Maste 				case DW_OP_reg6:
5733*2c23cb7cSEd Maste 				case DW_OP_reg7:
5734*2c23cb7cSEd Maste 				case DW_OP_reg8:
5735*2c23cb7cSEd Maste 				case DW_OP_reg9:
5736*2c23cb7cSEd Maste 				case DW_OP_reg10:
5737*2c23cb7cSEd Maste 				case DW_OP_reg11:
5738*2c23cb7cSEd Maste 				case DW_OP_reg12:
5739*2c23cb7cSEd Maste 				case DW_OP_reg13:
5740*2c23cb7cSEd Maste 				case DW_OP_reg14:
5741*2c23cb7cSEd Maste 				case DW_OP_reg15:
5742*2c23cb7cSEd Maste 				case DW_OP_reg16:
5743*2c23cb7cSEd Maste 				case DW_OP_reg17:
5744*2c23cb7cSEd Maste 				case DW_OP_reg18:
5745*2c23cb7cSEd Maste 				case DW_OP_reg19:
5746*2c23cb7cSEd Maste 				case DW_OP_reg20:
5747*2c23cb7cSEd Maste 				case DW_OP_reg21:
5748*2c23cb7cSEd Maste 				case DW_OP_reg22:
5749*2c23cb7cSEd Maste 				case DW_OP_reg23:
5750*2c23cb7cSEd Maste 				case DW_OP_reg24:
5751*2c23cb7cSEd Maste 				case DW_OP_reg25:
5752*2c23cb7cSEd Maste 				case DW_OP_reg26:
5753*2c23cb7cSEd Maste 				case DW_OP_reg27:
5754*2c23cb7cSEd Maste 				case DW_OP_reg28:
5755*2c23cb7cSEd Maste 				case DW_OP_reg29:
5756*2c23cb7cSEd Maste 				case DW_OP_reg30:
5757*2c23cb7cSEd Maste 				case DW_OP_reg31:
5758*2c23cb7cSEd Maste 				case DW_OP_lit0:
5759*2c23cb7cSEd Maste 				case DW_OP_lit1:
5760*2c23cb7cSEd Maste 				case DW_OP_lit2:
5761*2c23cb7cSEd Maste 				case DW_OP_lit3:
5762*2c23cb7cSEd Maste 				case DW_OP_lit4:
5763*2c23cb7cSEd Maste 				case DW_OP_lit5:
5764*2c23cb7cSEd Maste 				case DW_OP_lit6:
5765*2c23cb7cSEd Maste 				case DW_OP_lit7:
5766*2c23cb7cSEd Maste 				case DW_OP_lit8:
5767*2c23cb7cSEd Maste 				case DW_OP_lit9:
5768*2c23cb7cSEd Maste 				case DW_OP_lit10:
5769*2c23cb7cSEd Maste 				case DW_OP_lit11:
5770*2c23cb7cSEd Maste 				case DW_OP_lit12:
5771*2c23cb7cSEd Maste 				case DW_OP_lit13:
5772*2c23cb7cSEd Maste 				case DW_OP_lit14:
5773*2c23cb7cSEd Maste 				case DW_OP_lit15:
5774*2c23cb7cSEd Maste 				case DW_OP_lit16:
5775*2c23cb7cSEd Maste 				case DW_OP_lit17:
5776*2c23cb7cSEd Maste 				case DW_OP_lit18:
5777*2c23cb7cSEd Maste 				case DW_OP_lit19:
5778*2c23cb7cSEd Maste 				case DW_OP_lit20:
5779*2c23cb7cSEd Maste 				case DW_OP_lit21:
5780*2c23cb7cSEd Maste 				case DW_OP_lit22:
5781*2c23cb7cSEd Maste 				case DW_OP_lit23:
5782*2c23cb7cSEd Maste 				case DW_OP_lit24:
5783*2c23cb7cSEd Maste 				case DW_OP_lit25:
5784*2c23cb7cSEd Maste 				case DW_OP_lit26:
5785*2c23cb7cSEd Maste 				case DW_OP_lit27:
5786*2c23cb7cSEd Maste 				case DW_OP_lit28:
5787*2c23cb7cSEd Maste 				case DW_OP_lit29:
5788*2c23cb7cSEd Maste 				case DW_OP_lit30:
5789*2c23cb7cSEd Maste 				case DW_OP_lit31:
5790*2c23cb7cSEd Maste 				case DW_OP_dup:
5791*2c23cb7cSEd Maste 				case DW_OP_drop:
5792*2c23cb7cSEd Maste 				case DW_OP_over:
5793*2c23cb7cSEd Maste 				case DW_OP_swap:
5794*2c23cb7cSEd Maste 				case DW_OP_rot:
5795*2c23cb7cSEd Maste 				case DW_OP_xderef:
5796*2c23cb7cSEd Maste 				case DW_OP_abs:
5797*2c23cb7cSEd Maste 				case DW_OP_and:
5798*2c23cb7cSEd Maste 				case DW_OP_div:
5799*2c23cb7cSEd Maste 				case DW_OP_minus:
5800*2c23cb7cSEd Maste 				case DW_OP_mod:
5801*2c23cb7cSEd Maste 				case DW_OP_mul:
5802*2c23cb7cSEd Maste 				case DW_OP_neg:
5803*2c23cb7cSEd Maste 				case DW_OP_not:
5804*2c23cb7cSEd Maste 				case DW_OP_or:
5805*2c23cb7cSEd Maste 				case DW_OP_plus:
5806*2c23cb7cSEd Maste 				case DW_OP_shl:
5807*2c23cb7cSEd Maste 				case DW_OP_shr:
5808*2c23cb7cSEd Maste 				case DW_OP_shra:
5809*2c23cb7cSEd Maste 				case DW_OP_xor:
5810*2c23cb7cSEd Maste 				case DW_OP_eq:
5811*2c23cb7cSEd Maste 				case DW_OP_ge:
5812*2c23cb7cSEd Maste 				case DW_OP_gt:
5813*2c23cb7cSEd Maste 				case DW_OP_le:
5814*2c23cb7cSEd Maste 				case DW_OP_lt:
5815*2c23cb7cSEd Maste 				case DW_OP_ne:
5816*2c23cb7cSEd Maste 				case DW_OP_nop:
5817*2c23cb7cSEd Maste 					break;
5818*2c23cb7cSEd Maste 
5819*2c23cb7cSEd Maste 				case DW_OP_const1u:
5820*2c23cb7cSEd Maste 				case DW_OP_const1s:
5821*2c23cb7cSEd Maste 				case DW_OP_pick:
5822*2c23cb7cSEd Maste 				case DW_OP_deref_size:
5823*2c23cb7cSEd Maste 				case DW_OP_xderef_size:
5824*2c23cb7cSEd Maste 				case DW_OP_const2u:
5825*2c23cb7cSEd Maste 				case DW_OP_const2s:
5826*2c23cb7cSEd Maste 				case DW_OP_bra:
5827*2c23cb7cSEd Maste 				case DW_OP_skip:
5828*2c23cb7cSEd Maste 				case DW_OP_const4u:
5829*2c23cb7cSEd Maste 				case DW_OP_const4s:
5830*2c23cb7cSEd Maste 				case DW_OP_const8u:
5831*2c23cb7cSEd Maste 				case DW_OP_const8s:
5832*2c23cb7cSEd Maste 				case DW_OP_constu:
5833*2c23cb7cSEd Maste 				case DW_OP_plus_uconst:
5834*2c23cb7cSEd Maste 				case DW_OP_regx:
5835*2c23cb7cSEd Maste 				case DW_OP_piece:
5836*2c23cb7cSEd Maste 					printf(": %ju", (uintmax_t)
5837*2c23cb7cSEd Maste 					    lr->lr_number);
5838*2c23cb7cSEd Maste 					break;
5839*2c23cb7cSEd Maste 
5840*2c23cb7cSEd Maste 				case DW_OP_consts:
5841*2c23cb7cSEd Maste 				case DW_OP_breg0:
5842*2c23cb7cSEd Maste 				case DW_OP_breg1:
5843*2c23cb7cSEd Maste 				case DW_OP_breg2:
5844*2c23cb7cSEd Maste 				case DW_OP_breg3:
5845*2c23cb7cSEd Maste 				case DW_OP_breg4:
5846*2c23cb7cSEd Maste 				case DW_OP_breg5:
5847*2c23cb7cSEd Maste 				case DW_OP_breg6:
5848*2c23cb7cSEd Maste 				case DW_OP_breg7:
5849*2c23cb7cSEd Maste 				case DW_OP_breg8:
5850*2c23cb7cSEd Maste 				case DW_OP_breg9:
5851*2c23cb7cSEd Maste 				case DW_OP_breg10:
5852*2c23cb7cSEd Maste 				case DW_OP_breg11:
5853*2c23cb7cSEd Maste 				case DW_OP_breg12:
5854*2c23cb7cSEd Maste 				case DW_OP_breg13:
5855*2c23cb7cSEd Maste 				case DW_OP_breg14:
5856*2c23cb7cSEd Maste 				case DW_OP_breg15:
5857*2c23cb7cSEd Maste 				case DW_OP_breg16:
5858*2c23cb7cSEd Maste 				case DW_OP_breg17:
5859*2c23cb7cSEd Maste 				case DW_OP_breg18:
5860*2c23cb7cSEd Maste 				case DW_OP_breg19:
5861*2c23cb7cSEd Maste 				case DW_OP_breg20:
5862*2c23cb7cSEd Maste 				case DW_OP_breg21:
5863*2c23cb7cSEd Maste 				case DW_OP_breg22:
5864*2c23cb7cSEd Maste 				case DW_OP_breg23:
5865*2c23cb7cSEd Maste 				case DW_OP_breg24:
5866*2c23cb7cSEd Maste 				case DW_OP_breg25:
5867*2c23cb7cSEd Maste 				case DW_OP_breg26:
5868*2c23cb7cSEd Maste 				case DW_OP_breg27:
5869*2c23cb7cSEd Maste 				case DW_OP_breg28:
5870*2c23cb7cSEd Maste 				case DW_OP_breg29:
5871*2c23cb7cSEd Maste 				case DW_OP_breg30:
5872*2c23cb7cSEd Maste 				case DW_OP_breg31:
5873*2c23cb7cSEd Maste 				case DW_OP_fbreg:
5874*2c23cb7cSEd Maste 					printf(": %jd", (intmax_t)
5875*2c23cb7cSEd Maste 					    lr->lr_number);
5876*2c23cb7cSEd Maste 					break;
5877*2c23cb7cSEd Maste 
5878*2c23cb7cSEd Maste 				case DW_OP_bregx:
5879*2c23cb7cSEd Maste 					printf(": %ju %jd",
5880*2c23cb7cSEd Maste 					    (uintmax_t) lr->lr_number,
5881*2c23cb7cSEd Maste 					    (intmax_t) lr->lr_number2);
5882*2c23cb7cSEd Maste 					break;
5883*2c23cb7cSEd Maste 
5884*2c23cb7cSEd Maste 				case DW_OP_addr:
5885*2c23cb7cSEd Maste 					printf(": %#jx", (uintmax_t)
5886*2c23cb7cSEd Maste 					    lr->lr_number);
5887*2c23cb7cSEd Maste 					break;
5888*2c23cb7cSEd Maste 				}
5889*2c23cb7cSEd Maste 				if (j < llbuf[i]->ld_cents - 1)
5890*2c23cb7cSEd Maste 					printf(", ");
5891*2c23cb7cSEd Maste 			}
5892*2c23cb7cSEd Maste 			putchar(')');
5893*2c23cb7cSEd Maste 
5894*2c23cb7cSEd Maste 			if (llbuf[i]->ld_lopc == llbuf[i]->ld_hipc)
5895*2c23cb7cSEd Maste 				printf(" (start == end)");
5896*2c23cb7cSEd Maste 			putchar('\n');
5897*2c23cb7cSEd Maste 		}
5898*2c23cb7cSEd Maste 	}
5899*2c23cb7cSEd Maste }
5900*2c23cb7cSEd Maste 
5901*2c23cb7cSEd Maste /*
5902*2c23cb7cSEd Maste  * Retrieve a string using string table section index and the string offset.
5903*2c23cb7cSEd Maste  */
5904*2c23cb7cSEd Maste static const char*
5905*2c23cb7cSEd Maste get_string(struct readelf *re, int strtab, size_t off)
5906*2c23cb7cSEd Maste {
5907*2c23cb7cSEd Maste 	const char *name;
5908*2c23cb7cSEd Maste 
5909*2c23cb7cSEd Maste 	if ((name = elf_strptr(re->elf, strtab, off)) == NULL)
5910*2c23cb7cSEd Maste 		return ("");
5911*2c23cb7cSEd Maste 
5912*2c23cb7cSEd Maste 	return (name);
5913*2c23cb7cSEd Maste }
5914*2c23cb7cSEd Maste 
5915*2c23cb7cSEd Maste /*
5916*2c23cb7cSEd Maste  * Retrieve the name of a symbol using the section index of the symbol
5917*2c23cb7cSEd Maste  * table and the index of the symbol within that table.
5918*2c23cb7cSEd Maste  */
5919*2c23cb7cSEd Maste static const char *
5920*2c23cb7cSEd Maste get_symbol_name(struct readelf *re, int symtab, int i)
5921*2c23cb7cSEd Maste {
5922*2c23cb7cSEd Maste 	struct section	*s;
5923*2c23cb7cSEd Maste 	const char	*name;
5924*2c23cb7cSEd Maste 	GElf_Sym	 sym;
5925*2c23cb7cSEd Maste 	Elf_Data	*data;
5926*2c23cb7cSEd Maste 	int		 elferr;
5927*2c23cb7cSEd Maste 
5928*2c23cb7cSEd Maste 	s = &re->sl[symtab];
5929*2c23cb7cSEd Maste 	if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM)
5930*2c23cb7cSEd Maste 		return ("");
5931*2c23cb7cSEd Maste 	(void) elf_errno();
5932*2c23cb7cSEd Maste 	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
5933*2c23cb7cSEd Maste 		elferr = elf_errno();
5934*2c23cb7cSEd Maste 		if (elferr != 0)
5935*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
5936*2c23cb7cSEd Maste 		return ("");
5937*2c23cb7cSEd Maste 	}
5938*2c23cb7cSEd Maste 	if (gelf_getsym(data, i, &sym) != &sym)
5939*2c23cb7cSEd Maste 		return ("");
5940*2c23cb7cSEd Maste 	/* Return section name for STT_SECTION symbol. */
5941*2c23cb7cSEd Maste 	if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
5942*2c23cb7cSEd Maste 	    re->sl[sym.st_shndx].name != NULL)
5943*2c23cb7cSEd Maste 		return (re->sl[sym.st_shndx].name);
5944*2c23cb7cSEd Maste 	if ((name = elf_strptr(re->elf, s->link, sym.st_name)) == NULL)
5945*2c23cb7cSEd Maste 		return ("");
5946*2c23cb7cSEd Maste 
5947*2c23cb7cSEd Maste 	return (name);
5948*2c23cb7cSEd Maste }
5949*2c23cb7cSEd Maste 
5950*2c23cb7cSEd Maste static uint64_t
5951*2c23cb7cSEd Maste get_symbol_value(struct readelf *re, int symtab, int i)
5952*2c23cb7cSEd Maste {
5953*2c23cb7cSEd Maste 	struct section	*s;
5954*2c23cb7cSEd Maste 	GElf_Sym	 sym;
5955*2c23cb7cSEd Maste 	Elf_Data	*data;
5956*2c23cb7cSEd Maste 	int		 elferr;
5957*2c23cb7cSEd Maste 
5958*2c23cb7cSEd Maste 	s = &re->sl[symtab];
5959*2c23cb7cSEd Maste 	if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM)
5960*2c23cb7cSEd Maste 		return (0);
5961*2c23cb7cSEd Maste 	(void) elf_errno();
5962*2c23cb7cSEd Maste 	if ((data = elf_getdata(s->scn, NULL)) == NULL) {
5963*2c23cb7cSEd Maste 		elferr = elf_errno();
5964*2c23cb7cSEd Maste 		if (elferr != 0)
5965*2c23cb7cSEd Maste 			warnx("elf_getdata failed: %s", elf_errmsg(elferr));
5966*2c23cb7cSEd Maste 		return (0);
5967*2c23cb7cSEd Maste 	}
5968*2c23cb7cSEd Maste 	if (gelf_getsym(data, i, &sym) != &sym)
5969*2c23cb7cSEd Maste 		return (0);
5970*2c23cb7cSEd Maste 
5971*2c23cb7cSEd Maste 	return (sym.st_value);
5972*2c23cb7cSEd Maste }
5973*2c23cb7cSEd Maste 
5974*2c23cb7cSEd Maste static void
5975*2c23cb7cSEd Maste hex_dump(struct readelf *re)
5976*2c23cb7cSEd Maste {
5977*2c23cb7cSEd Maste 	struct section *s;
5978*2c23cb7cSEd Maste 	Elf_Data *d;
5979*2c23cb7cSEd Maste 	uint8_t *buf;
5980*2c23cb7cSEd Maste 	size_t sz, nbytes;
5981*2c23cb7cSEd Maste 	uint64_t addr;
5982*2c23cb7cSEd Maste 	int elferr, i, j;
5983*2c23cb7cSEd Maste 
5984*2c23cb7cSEd Maste 	for (i = 1; (size_t) i < re->shnum; i++) {
5985*2c23cb7cSEd Maste 		s = &re->sl[i];
5986*2c23cb7cSEd Maste 		if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL)
5987*2c23cb7cSEd Maste 			continue;
5988*2c23cb7cSEd Maste 		(void) elf_errno();
5989*2c23cb7cSEd Maste 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
5990*2c23cb7cSEd Maste 			elferr = elf_errno();
5991*2c23cb7cSEd Maste 			if (elferr != 0)
5992*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s",
5993*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
5994*2c23cb7cSEd Maste 			continue;
5995*2c23cb7cSEd Maste 		}
5996*2c23cb7cSEd Maste 		if (d->d_size <= 0 || d->d_buf == NULL) {
5997*2c23cb7cSEd Maste 			printf("\nSection '%s' has no data to dump.\n",
5998*2c23cb7cSEd Maste 			    s->name);
5999*2c23cb7cSEd Maste 			continue;
6000*2c23cb7cSEd Maste 		}
6001*2c23cb7cSEd Maste 		buf = d->d_buf;
6002*2c23cb7cSEd Maste 		sz = d->d_size;
6003*2c23cb7cSEd Maste 		addr = s->addr;
6004*2c23cb7cSEd Maste 		printf("\nHex dump of section '%s':\n", s->name);
6005*2c23cb7cSEd Maste 		while (sz > 0) {
6006*2c23cb7cSEd Maste 			printf("  0x%8.8jx ", (uintmax_t)addr);
6007*2c23cb7cSEd Maste 			nbytes = sz > 16? 16 : sz;
6008*2c23cb7cSEd Maste 			for (j = 0; j < 16; j++) {
6009*2c23cb7cSEd Maste 				if ((size_t)j < nbytes)
6010*2c23cb7cSEd Maste 					printf("%2.2x", buf[j]);
6011*2c23cb7cSEd Maste 				else
6012*2c23cb7cSEd Maste 					printf("  ");
6013*2c23cb7cSEd Maste 				if ((j & 3) == 3)
6014*2c23cb7cSEd Maste 					printf(" ");
6015*2c23cb7cSEd Maste 			}
6016*2c23cb7cSEd Maste 			for (j = 0; (size_t)j < nbytes; j++) {
6017*2c23cb7cSEd Maste 				if (isprint(buf[j]))
6018*2c23cb7cSEd Maste 					printf("%c", buf[j]);
6019*2c23cb7cSEd Maste 				else
6020*2c23cb7cSEd Maste 					printf(".");
6021*2c23cb7cSEd Maste 			}
6022*2c23cb7cSEd Maste 			printf("\n");
6023*2c23cb7cSEd Maste 			buf += nbytes;
6024*2c23cb7cSEd Maste 			addr += nbytes;
6025*2c23cb7cSEd Maste 			sz -= nbytes;
6026*2c23cb7cSEd Maste 		}
6027*2c23cb7cSEd Maste 	}
6028*2c23cb7cSEd Maste }
6029*2c23cb7cSEd Maste 
6030*2c23cb7cSEd Maste static void
6031*2c23cb7cSEd Maste str_dump(struct readelf *re)
6032*2c23cb7cSEd Maste {
6033*2c23cb7cSEd Maste 	struct section *s;
6034*2c23cb7cSEd Maste 	Elf_Data *d;
6035*2c23cb7cSEd Maste 	unsigned char *start, *end, *buf_end;
6036*2c23cb7cSEd Maste 	unsigned int len;
6037*2c23cb7cSEd Maste 	int i, j, elferr, found;
6038*2c23cb7cSEd Maste 
6039*2c23cb7cSEd Maste 	for (i = 1; (size_t) i < re->shnum; i++) {
6040*2c23cb7cSEd Maste 		s = &re->sl[i];
6041*2c23cb7cSEd Maste 		if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL)
6042*2c23cb7cSEd Maste 			continue;
6043*2c23cb7cSEd Maste 		(void) elf_errno();
6044*2c23cb7cSEd Maste 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
6045*2c23cb7cSEd Maste 			elferr = elf_errno();
6046*2c23cb7cSEd Maste 			if (elferr != 0)
6047*2c23cb7cSEd Maste 				warnx("elf_getdata failed: %s",
6048*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
6049*2c23cb7cSEd Maste 			continue;
6050*2c23cb7cSEd Maste 		}
6051*2c23cb7cSEd Maste 		if (d->d_size <= 0 || d->d_buf == NULL) {
6052*2c23cb7cSEd Maste 			printf("\nSection '%s' has no data to dump.\n",
6053*2c23cb7cSEd Maste 			    s->name);
6054*2c23cb7cSEd Maste 			continue;
6055*2c23cb7cSEd Maste 		}
6056*2c23cb7cSEd Maste 		buf_end = (unsigned char *) d->d_buf + d->d_size;
6057*2c23cb7cSEd Maste 		start = (unsigned char *) d->d_buf;
6058*2c23cb7cSEd Maste 		found = 0;
6059*2c23cb7cSEd Maste 		printf("\nString dump of section '%s':\n", s->name);
6060*2c23cb7cSEd Maste 		for (;;) {
6061*2c23cb7cSEd Maste 			while (start < buf_end && !isprint(*start))
6062*2c23cb7cSEd Maste 				start++;
6063*2c23cb7cSEd Maste 			if (start >= buf_end)
6064*2c23cb7cSEd Maste 				break;
6065*2c23cb7cSEd Maste 			end = start + 1;
6066*2c23cb7cSEd Maste 			while (end < buf_end && isprint(*end))
6067*2c23cb7cSEd Maste 				end++;
6068*2c23cb7cSEd Maste 			printf("  [%6lx]  ",
6069*2c23cb7cSEd Maste 			    (long) (start - (unsigned char *) d->d_buf));
6070*2c23cb7cSEd Maste 			len = end - start;
6071*2c23cb7cSEd Maste 			for (j = 0; (unsigned int) j < len; j++)
6072*2c23cb7cSEd Maste 				putchar(start[j]);
6073*2c23cb7cSEd Maste 			putchar('\n');
6074*2c23cb7cSEd Maste 			found = 1;
6075*2c23cb7cSEd Maste 			if (end >= buf_end)
6076*2c23cb7cSEd Maste 				break;
6077*2c23cb7cSEd Maste 			start = end + 1;
6078*2c23cb7cSEd Maste 		}
6079*2c23cb7cSEd Maste 		if (!found)
6080*2c23cb7cSEd Maste 			printf("  No strings found in this section.");
6081*2c23cb7cSEd Maste 		putchar('\n');
6082*2c23cb7cSEd Maste 	}
6083*2c23cb7cSEd Maste }
6084*2c23cb7cSEd Maste 
6085*2c23cb7cSEd Maste static void
6086*2c23cb7cSEd Maste load_sections(struct readelf *re)
6087*2c23cb7cSEd Maste {
6088*2c23cb7cSEd Maste 	struct section	*s;
6089*2c23cb7cSEd Maste 	const char	*name;
6090*2c23cb7cSEd Maste 	Elf_Scn		*scn;
6091*2c23cb7cSEd Maste 	GElf_Shdr	 sh;
6092*2c23cb7cSEd Maste 	size_t		 shstrndx, ndx;
6093*2c23cb7cSEd Maste 	int		 elferr;
6094*2c23cb7cSEd Maste 
6095*2c23cb7cSEd Maste 	/* Allocate storage for internal section list. */
6096*2c23cb7cSEd Maste 	if (!elf_getshnum(re->elf, &re->shnum)) {
6097*2c23cb7cSEd Maste 		warnx("elf_getshnum failed: %s", elf_errmsg(-1));
6098*2c23cb7cSEd Maste 		return;
6099*2c23cb7cSEd Maste 	}
6100*2c23cb7cSEd Maste 	if (re->sl != NULL)
6101*2c23cb7cSEd Maste 		free(re->sl);
6102*2c23cb7cSEd Maste 	if ((re->sl = calloc(re->shnum, sizeof(*re->sl))) == NULL)
6103*2c23cb7cSEd Maste 		err(EXIT_FAILURE, "calloc failed");
6104*2c23cb7cSEd Maste 
6105*2c23cb7cSEd Maste 	/* Get the index of .shstrtab section. */
6106*2c23cb7cSEd Maste 	if (!elf_getshstrndx(re->elf, &shstrndx)) {
6107*2c23cb7cSEd Maste 		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
6108*2c23cb7cSEd Maste 		return;
6109*2c23cb7cSEd Maste 	}
6110*2c23cb7cSEd Maste 
6111*2c23cb7cSEd Maste 	if ((scn = elf_getscn(re->elf, 0)) == NULL) {
6112*2c23cb7cSEd Maste 		warnx("elf_getscn failed: %s", elf_errmsg(-1));
6113*2c23cb7cSEd Maste 		return;
6114*2c23cb7cSEd Maste 	}
6115*2c23cb7cSEd Maste 
6116*2c23cb7cSEd Maste 	(void) elf_errno();
6117*2c23cb7cSEd Maste 	do {
6118*2c23cb7cSEd Maste 		if (gelf_getshdr(scn, &sh) == NULL) {
6119*2c23cb7cSEd Maste 			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
6120*2c23cb7cSEd Maste 			(void) elf_errno();
6121*2c23cb7cSEd Maste 			continue;
6122*2c23cb7cSEd Maste 		}
6123*2c23cb7cSEd Maste 		if ((name = elf_strptr(re->elf, shstrndx, sh.sh_name)) == NULL) {
6124*2c23cb7cSEd Maste 			(void) elf_errno();
6125*2c23cb7cSEd Maste 			name = "ERROR";
6126*2c23cb7cSEd Maste 		}
6127*2c23cb7cSEd Maste 		if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) {
6128*2c23cb7cSEd Maste 			if ((elferr = elf_errno()) != 0)
6129*2c23cb7cSEd Maste 				warnx("elf_ndxscn failed: %s",
6130*2c23cb7cSEd Maste 				    elf_errmsg(elferr));
6131*2c23cb7cSEd Maste 			continue;
6132*2c23cb7cSEd Maste 		}
6133*2c23cb7cSEd Maste 		if (ndx >= re->shnum) {
6134*2c23cb7cSEd Maste 			warnx("section index of '%s' out of range", name);
6135*2c23cb7cSEd Maste 			continue;
6136*2c23cb7cSEd Maste 		}
6137*2c23cb7cSEd Maste 		s = &re->sl[ndx];
6138*2c23cb7cSEd Maste 		s->name = name;
6139*2c23cb7cSEd Maste 		s->scn = scn;
6140*2c23cb7cSEd Maste 		s->off = sh.sh_offset;
6141*2c23cb7cSEd Maste 		s->sz = sh.sh_size;
6142*2c23cb7cSEd Maste 		s->entsize = sh.sh_entsize;
6143*2c23cb7cSEd Maste 		s->align = sh.sh_addralign;
6144*2c23cb7cSEd Maste 		s->type = sh.sh_type;
6145*2c23cb7cSEd Maste 		s->flags = sh.sh_flags;
6146*2c23cb7cSEd Maste 		s->addr = sh.sh_addr;
6147*2c23cb7cSEd Maste 		s->link = sh.sh_link;
6148*2c23cb7cSEd Maste 		s->info = sh.sh_info;
6149*2c23cb7cSEd Maste 	} while ((scn = elf_nextscn(re->elf, scn)) != NULL);
6150*2c23cb7cSEd Maste 	elferr = elf_errno();
6151*2c23cb7cSEd Maste 	if (elferr != 0)
6152*2c23cb7cSEd Maste 		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
6153*2c23cb7cSEd Maste }
6154*2c23cb7cSEd Maste 
6155*2c23cb7cSEd Maste static void
6156*2c23cb7cSEd Maste unload_sections(struct readelf *re)
6157*2c23cb7cSEd Maste {
6158*2c23cb7cSEd Maste 
6159*2c23cb7cSEd Maste 	if (re->sl != NULL) {
6160*2c23cb7cSEd Maste 		free(re->sl);
6161*2c23cb7cSEd Maste 		re->sl = NULL;
6162*2c23cb7cSEd Maste 	}
6163*2c23cb7cSEd Maste 	re->shnum = 0;
6164*2c23cb7cSEd Maste 	re->vd_s = NULL;
6165*2c23cb7cSEd Maste 	re->vn_s = NULL;
6166*2c23cb7cSEd Maste 	re->vs_s = NULL;
6167*2c23cb7cSEd Maste 	re->vs = NULL;
6168*2c23cb7cSEd Maste 	re->vs_sz = 0;
6169*2c23cb7cSEd Maste 	if (re->ver != NULL) {
6170*2c23cb7cSEd Maste 		free(re->ver);
6171*2c23cb7cSEd Maste 		re->ver = NULL;
6172*2c23cb7cSEd Maste 		re->ver_sz = 0;
6173*2c23cb7cSEd Maste 	}
6174*2c23cb7cSEd Maste }
6175*2c23cb7cSEd Maste 
6176*2c23cb7cSEd Maste static void
6177*2c23cb7cSEd Maste dump_elf(struct readelf *re)
6178*2c23cb7cSEd Maste {
6179*2c23cb7cSEd Maste 
6180*2c23cb7cSEd Maste 	/* Fetch ELF header. No need to continue if it fails. */
6181*2c23cb7cSEd Maste 	if (gelf_getehdr(re->elf, &re->ehdr) == NULL) {
6182*2c23cb7cSEd Maste 		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
6183*2c23cb7cSEd Maste 		return;
6184*2c23cb7cSEd Maste 	}
6185*2c23cb7cSEd Maste 	if ((re->ec = gelf_getclass(re->elf)) == ELFCLASSNONE) {
6186*2c23cb7cSEd Maste 		warnx("gelf_getclass failed: %s", elf_errmsg(-1));
6187*2c23cb7cSEd Maste 		return;
6188*2c23cb7cSEd Maste 	}
6189*2c23cb7cSEd Maste 	if (re->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) {
6190*2c23cb7cSEd Maste 		re->dw_read = _read_msb;
6191*2c23cb7cSEd Maste 		re->dw_decode = _decode_msb;
6192*2c23cb7cSEd Maste 	} else {
6193*2c23cb7cSEd Maste 		re->dw_read = _read_lsb;
6194*2c23cb7cSEd Maste 		re->dw_decode = _decode_lsb;
6195*2c23cb7cSEd Maste 	}
6196*2c23cb7cSEd Maste 
6197*2c23cb7cSEd Maste 	if (re->options & ~RE_H)
6198*2c23cb7cSEd Maste 		load_sections(re);
6199*2c23cb7cSEd Maste 	if ((re->options & RE_VV) || (re->options & RE_S))
6200*2c23cb7cSEd Maste 		search_ver(re);
6201*2c23cb7cSEd Maste 	if (re->options & RE_H)
6202*2c23cb7cSEd Maste 		dump_ehdr(re);
6203*2c23cb7cSEd Maste 	if (re->options & RE_L)
6204*2c23cb7cSEd Maste 		dump_phdr(re);
6205*2c23cb7cSEd Maste 	if (re->options & RE_SS)
6206*2c23cb7cSEd Maste 		dump_shdr(re);
6207*2c23cb7cSEd Maste 	if (re->options & RE_D)
6208*2c23cb7cSEd Maste 		dump_dynamic(re);
6209*2c23cb7cSEd Maste 	if (re->options & RE_R)
6210*2c23cb7cSEd Maste 		dump_reloc(re);
6211*2c23cb7cSEd Maste 	if (re->options & RE_S)
6212*2c23cb7cSEd Maste 		dump_symtabs(re);
6213*2c23cb7cSEd Maste 	if (re->options & RE_N)
6214*2c23cb7cSEd Maste 		dump_notes(re);
6215*2c23cb7cSEd Maste 	if (re->options & RE_II)
6216*2c23cb7cSEd Maste 		dump_hash(re);
6217*2c23cb7cSEd Maste 	if (re->options & RE_X)
6218*2c23cb7cSEd Maste 		hex_dump(re);
6219*2c23cb7cSEd Maste 	if (re->options & RE_P)
6220*2c23cb7cSEd Maste 		str_dump(re);
6221*2c23cb7cSEd Maste 	if (re->options & RE_VV)
6222*2c23cb7cSEd Maste 		dump_ver(re);
6223*2c23cb7cSEd Maste 	if (re->options & RE_AA)
6224*2c23cb7cSEd Maste 		dump_arch_specific_info(re);
6225*2c23cb7cSEd Maste 	if (re->options & RE_W)
6226*2c23cb7cSEd Maste 		dump_dwarf(re);
6227*2c23cb7cSEd Maste 	if (re->options & ~RE_H)
6228*2c23cb7cSEd Maste 		unload_sections(re);
6229*2c23cb7cSEd Maste }
6230*2c23cb7cSEd Maste 
6231*2c23cb7cSEd Maste static void
6232*2c23cb7cSEd Maste dump_dwarf(struct readelf *re)
6233*2c23cb7cSEd Maste {
6234*2c23cb7cSEd Maste 	int error;
6235*2c23cb7cSEd Maste 	Dwarf_Error de;
6236*2c23cb7cSEd Maste 
6237*2c23cb7cSEd Maste 	if (dwarf_elf_init(re->elf, DW_DLC_READ, NULL, NULL, &re->dbg, &de)) {
6238*2c23cb7cSEd Maste 		if ((error = dwarf_errno(de)) != DW_DLE_DEBUG_INFO_NULL)
6239*2c23cb7cSEd Maste 			errx(EXIT_FAILURE, "dwarf_elf_init failed: %s",
6240*2c23cb7cSEd Maste 			    dwarf_errmsg(de));
6241*2c23cb7cSEd Maste 		return;
6242*2c23cb7cSEd Maste 	}
6243*2c23cb7cSEd Maste 
6244*2c23cb7cSEd Maste 	if (re->dop & DW_A)
6245*2c23cb7cSEd Maste 		dump_dwarf_abbrev(re);
6246*2c23cb7cSEd Maste 	if (re->dop & DW_L)
6247*2c23cb7cSEd Maste 		dump_dwarf_line(re);
6248*2c23cb7cSEd Maste 	if (re->dop & DW_LL)
6249*2c23cb7cSEd Maste 		dump_dwarf_line_decoded(re);
6250*2c23cb7cSEd Maste 	if (re->dop & DW_I)
6251*2c23cb7cSEd Maste 		dump_dwarf_info(re);
6252*2c23cb7cSEd Maste 	if (re->dop & DW_P)
6253*2c23cb7cSEd Maste 		dump_dwarf_pubnames(re);
6254*2c23cb7cSEd Maste 	if (re->dop & DW_R)
6255*2c23cb7cSEd Maste 		dump_dwarf_aranges(re);
6256*2c23cb7cSEd Maste 	if (re->dop & DW_RR)
6257*2c23cb7cSEd Maste 		dump_dwarf_ranges(re);
6258*2c23cb7cSEd Maste 	if (re->dop & DW_M)
6259*2c23cb7cSEd Maste 		dump_dwarf_macinfo(re);
6260*2c23cb7cSEd Maste 	if (re->dop & DW_F)
6261*2c23cb7cSEd Maste 		dump_dwarf_frame(re, 0);
6262*2c23cb7cSEd Maste 	else if (re->dop & DW_FF)
6263*2c23cb7cSEd Maste 		dump_dwarf_frame(re, 1);
6264*2c23cb7cSEd Maste 	if (re->dop & DW_S)
6265*2c23cb7cSEd Maste 		dump_dwarf_str(re);
6266*2c23cb7cSEd Maste 	if (re->dop & DW_O)
6267*2c23cb7cSEd Maste 		dump_dwarf_loclist(re);
6268*2c23cb7cSEd Maste 
6269*2c23cb7cSEd Maste 	dwarf_finish(re->dbg, &de);
6270*2c23cb7cSEd Maste }
6271*2c23cb7cSEd Maste 
6272*2c23cb7cSEd Maste static void
6273*2c23cb7cSEd Maste dump_ar(struct readelf *re, int fd)
6274*2c23cb7cSEd Maste {
6275*2c23cb7cSEd Maste 	Elf_Arsym *arsym;
6276*2c23cb7cSEd Maste 	Elf_Arhdr *arhdr;
6277*2c23cb7cSEd Maste 	Elf_Cmd cmd;
6278*2c23cb7cSEd Maste 	Elf *e;
6279*2c23cb7cSEd Maste 	size_t sz;
6280*2c23cb7cSEd Maste 	off_t off;
6281*2c23cb7cSEd Maste 	int i;
6282*2c23cb7cSEd Maste 
6283*2c23cb7cSEd Maste 	re->ar = re->elf;
6284*2c23cb7cSEd Maste 
6285*2c23cb7cSEd Maste 	if (re->options & RE_C) {
6286*2c23cb7cSEd Maste 		if ((arsym = elf_getarsym(re->ar, &sz)) == NULL) {
6287*2c23cb7cSEd Maste 			warnx("elf_getarsym() failed: %s", elf_errmsg(-1));
6288*2c23cb7cSEd Maste 			goto process_members;
6289*2c23cb7cSEd Maste 		}
6290*2c23cb7cSEd Maste 		printf("Index of archive %s: (%ju entries)\n", re->filename,
6291*2c23cb7cSEd Maste 		    (uintmax_t) sz - 1);
6292*2c23cb7cSEd Maste 		off = 0;
6293*2c23cb7cSEd Maste 		for (i = 0; (size_t) i < sz; i++) {
6294*2c23cb7cSEd Maste 			if (arsym[i].as_name == NULL)
6295*2c23cb7cSEd Maste 				break;
6296*2c23cb7cSEd Maste 			if (arsym[i].as_off != off) {
6297*2c23cb7cSEd Maste 				off = arsym[i].as_off;
6298*2c23cb7cSEd Maste 				if (elf_rand(re->ar, off) != off) {
6299*2c23cb7cSEd Maste 					warnx("elf_rand() failed: %s",
6300*2c23cb7cSEd Maste 					    elf_errmsg(-1));
6301*2c23cb7cSEd Maste 					continue;
6302*2c23cb7cSEd Maste 				}
6303*2c23cb7cSEd Maste 				if ((e = elf_begin(fd, ELF_C_READ, re->ar)) ==
6304*2c23cb7cSEd Maste 				    NULL) {
6305*2c23cb7cSEd Maste 					warnx("elf_begin() failed: %s",
6306*2c23cb7cSEd Maste 					    elf_errmsg(-1));
6307*2c23cb7cSEd Maste 					continue;
6308*2c23cb7cSEd Maste 				}
6309*2c23cb7cSEd Maste 				if ((arhdr = elf_getarhdr(e)) == NULL) {
6310*2c23cb7cSEd Maste 					warnx("elf_getarhdr() failed: %s",
6311*2c23cb7cSEd Maste 					    elf_errmsg(-1));
6312*2c23cb7cSEd Maste 					elf_end(e);
6313*2c23cb7cSEd Maste 					continue;
6314*2c23cb7cSEd Maste 				}
6315*2c23cb7cSEd Maste 				printf("Binary %s(%s) contains:\n",
6316*2c23cb7cSEd Maste 				    re->filename, arhdr->ar_name);
6317*2c23cb7cSEd Maste 			}
6318*2c23cb7cSEd Maste 			printf("\t%s\n", arsym[i].as_name);
6319*2c23cb7cSEd Maste 		}
6320*2c23cb7cSEd Maste 		if (elf_rand(re->ar, SARMAG) != SARMAG) {
6321*2c23cb7cSEd Maste 			warnx("elf_rand() failed: %s", elf_errmsg(-1));
6322*2c23cb7cSEd Maste 			return;
6323*2c23cb7cSEd Maste 		}
6324*2c23cb7cSEd Maste 	}
6325*2c23cb7cSEd Maste 
6326*2c23cb7cSEd Maste process_members:
6327*2c23cb7cSEd Maste 
6328*2c23cb7cSEd Maste 	if ((re->options & ~RE_C) == 0)
6329*2c23cb7cSEd Maste 		return;
6330*2c23cb7cSEd Maste 
6331*2c23cb7cSEd Maste 	cmd = ELF_C_READ;
6332*2c23cb7cSEd Maste 	while ((re->elf = elf_begin(fd, cmd, re->ar)) != NULL) {
6333*2c23cb7cSEd Maste 		if ((arhdr = elf_getarhdr(re->elf)) == NULL) {
6334*2c23cb7cSEd Maste 			warnx("elf_getarhdr() failed: %s", elf_errmsg(-1));
6335*2c23cb7cSEd Maste 			goto next_member;
6336*2c23cb7cSEd Maste 		}
6337*2c23cb7cSEd Maste 		if (strcmp(arhdr->ar_name, "/") == 0 ||
6338*2c23cb7cSEd Maste 		    strcmp(arhdr->ar_name, "//") == 0 ||
6339*2c23cb7cSEd Maste 		    strcmp(arhdr->ar_name, "__.SYMDEF") == 0)
6340*2c23cb7cSEd Maste 			goto next_member;
6341*2c23cb7cSEd Maste 		printf("\nFile: %s(%s)\n", re->filename, arhdr->ar_name);
6342*2c23cb7cSEd Maste 		dump_elf(re);
6343*2c23cb7cSEd Maste 
6344*2c23cb7cSEd Maste 	next_member:
6345*2c23cb7cSEd Maste 		cmd = elf_next(re->elf);
6346*2c23cb7cSEd Maste 		elf_end(re->elf);
6347*2c23cb7cSEd Maste 	}
6348*2c23cb7cSEd Maste 	re->elf = re->ar;
6349*2c23cb7cSEd Maste }
6350*2c23cb7cSEd Maste 
6351*2c23cb7cSEd Maste static void
6352*2c23cb7cSEd Maste dump_object(struct readelf *re)
6353*2c23cb7cSEd Maste {
6354*2c23cb7cSEd Maste 	int fd;
6355*2c23cb7cSEd Maste 
6356*2c23cb7cSEd Maste 	if ((fd = open(re->filename, O_RDONLY)) == -1) {
6357*2c23cb7cSEd Maste 		warn("open %s failed", re->filename);
6358*2c23cb7cSEd Maste 		return;
6359*2c23cb7cSEd Maste 	}
6360*2c23cb7cSEd Maste 
6361*2c23cb7cSEd Maste 	if ((re->flags & DISPLAY_FILENAME) != 0)
6362*2c23cb7cSEd Maste 		printf("\nFile: %s\n", re->filename);
6363*2c23cb7cSEd Maste 
6364*2c23cb7cSEd Maste 	if ((re->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
6365*2c23cb7cSEd Maste 		warnx("elf_begin() failed: %s", elf_errmsg(-1));
6366*2c23cb7cSEd Maste 		return;
6367*2c23cb7cSEd Maste 	}
6368*2c23cb7cSEd Maste 
6369*2c23cb7cSEd Maste 	switch (elf_kind(re->elf)) {
6370*2c23cb7cSEd Maste 	case ELF_K_NONE:
6371*2c23cb7cSEd Maste 		warnx("Not an ELF file.");
6372*2c23cb7cSEd Maste 		return;
6373*2c23cb7cSEd Maste 	case ELF_K_ELF:
6374*2c23cb7cSEd Maste 		dump_elf(re);
6375*2c23cb7cSEd Maste 		break;
6376*2c23cb7cSEd Maste 	case ELF_K_AR:
6377*2c23cb7cSEd Maste 		dump_ar(re, fd);
6378*2c23cb7cSEd Maste 		break;
6379*2c23cb7cSEd Maste 	default:
6380*2c23cb7cSEd Maste 		warnx("Internal: libelf returned unknown elf kind.");
6381*2c23cb7cSEd Maste 		return;
6382*2c23cb7cSEd Maste 	}
6383*2c23cb7cSEd Maste 
6384*2c23cb7cSEd Maste 	elf_end(re->elf);
6385*2c23cb7cSEd Maste }
6386*2c23cb7cSEd Maste 
6387*2c23cb7cSEd Maste static void
6388*2c23cb7cSEd Maste add_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t)
6389*2c23cb7cSEd Maste {
6390*2c23cb7cSEd Maste 	struct dumpop *d;
6391*2c23cb7cSEd Maste 
6392*2c23cb7cSEd Maste 	if ((d = find_dumpop(re, si, sn, -1, t)) == NULL) {
6393*2c23cb7cSEd Maste 		if ((d = calloc(1, sizeof(*d))) == NULL)
6394*2c23cb7cSEd Maste 			err(EXIT_FAILURE, "calloc failed");
6395*2c23cb7cSEd Maste 		if (t == DUMP_BY_INDEX)
6396*2c23cb7cSEd Maste 			d->u.si = si;
6397*2c23cb7cSEd Maste 		else
6398*2c23cb7cSEd Maste 			d->u.sn = sn;
6399*2c23cb7cSEd Maste 		d->type = t;
6400*2c23cb7cSEd Maste 		d->op = op;
6401*2c23cb7cSEd Maste 		STAILQ_INSERT_TAIL(&re->v_dumpop, d, dumpop_list);
6402*2c23cb7cSEd Maste 	} else
6403*2c23cb7cSEd Maste 		d->op |= op;
6404*2c23cb7cSEd Maste }
6405*2c23cb7cSEd Maste 
6406*2c23cb7cSEd Maste static struct dumpop *
6407*2c23cb7cSEd Maste find_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t)
6408*2c23cb7cSEd Maste {
6409*2c23cb7cSEd Maste 	struct dumpop *d;
6410*2c23cb7cSEd Maste 
6411*2c23cb7cSEd Maste 	STAILQ_FOREACH(d, &re->v_dumpop, dumpop_list) {
6412*2c23cb7cSEd Maste 		if ((op == -1 || op & d->op) &&
6413*2c23cb7cSEd Maste 		    (t == -1 || (unsigned) t == d->type)) {
6414*2c23cb7cSEd Maste 			if ((d->type == DUMP_BY_INDEX && d->u.si == si) ||
6415*2c23cb7cSEd Maste 			    (d->type == DUMP_BY_NAME && !strcmp(d->u.sn, sn)))
6416*2c23cb7cSEd Maste 				return (d);
6417*2c23cb7cSEd Maste 		}
6418*2c23cb7cSEd Maste 	}
6419*2c23cb7cSEd Maste 
6420*2c23cb7cSEd Maste 	return (NULL);
6421*2c23cb7cSEd Maste }
6422*2c23cb7cSEd Maste 
6423*2c23cb7cSEd Maste static struct {
6424*2c23cb7cSEd Maste 	const char *ln;
6425*2c23cb7cSEd Maste 	char sn;
6426*2c23cb7cSEd Maste 	int value;
6427*2c23cb7cSEd Maste } dwarf_op[] = {
6428*2c23cb7cSEd Maste 	{"rawline", 'l', DW_L},
6429*2c23cb7cSEd Maste 	{"decodedline", 'L', DW_LL},
6430*2c23cb7cSEd Maste 	{"info", 'i', DW_I},
6431*2c23cb7cSEd Maste 	{"abbrev", 'a', DW_A},
6432*2c23cb7cSEd Maste 	{"pubnames", 'p', DW_P},
6433*2c23cb7cSEd Maste 	{"aranges", 'r', DW_R},
6434*2c23cb7cSEd Maste 	{"ranges", 'r', DW_R},
6435*2c23cb7cSEd Maste 	{"Ranges", 'R', DW_RR},
6436*2c23cb7cSEd Maste 	{"macro", 'm', DW_M},
6437*2c23cb7cSEd Maste 	{"frames", 'f', DW_F},
6438*2c23cb7cSEd Maste 	{"", 'F', DW_FF},
6439*2c23cb7cSEd Maste 	{"str", 's', DW_S},
6440*2c23cb7cSEd Maste 	{"loc", 'o', DW_O},
6441*2c23cb7cSEd Maste 	{NULL, 0, 0}
6442*2c23cb7cSEd Maste };
6443*2c23cb7cSEd Maste 
6444*2c23cb7cSEd Maste static void
6445*2c23cb7cSEd Maste parse_dwarf_op_short(struct readelf *re, const char *op)
6446*2c23cb7cSEd Maste {
6447*2c23cb7cSEd Maste 	int i;
6448*2c23cb7cSEd Maste 
6449*2c23cb7cSEd Maste 	if (op == NULL) {
6450*2c23cb7cSEd Maste 		re->dop |= DW_DEFAULT_OPTIONS;
6451*2c23cb7cSEd Maste 		return;
6452*2c23cb7cSEd Maste 	}
6453*2c23cb7cSEd Maste 
6454*2c23cb7cSEd Maste 	for (; *op != '\0'; op++) {
6455*2c23cb7cSEd Maste 		for (i = 0; dwarf_op[i].ln != NULL; i++) {
6456*2c23cb7cSEd Maste 			if (dwarf_op[i].sn == *op) {
6457*2c23cb7cSEd Maste 				re->dop |= dwarf_op[i].value;
6458*2c23cb7cSEd Maste 				break;
6459*2c23cb7cSEd Maste 			}
6460*2c23cb7cSEd Maste 		}
6461*2c23cb7cSEd Maste 	}
6462*2c23cb7cSEd Maste }
6463*2c23cb7cSEd Maste 
6464*2c23cb7cSEd Maste static void
6465*2c23cb7cSEd Maste parse_dwarf_op_long(struct readelf *re, const char *op)
6466*2c23cb7cSEd Maste {
6467*2c23cb7cSEd Maste 	char *p, *token, *bp;
6468*2c23cb7cSEd Maste 	int i;
6469*2c23cb7cSEd Maste 
6470*2c23cb7cSEd Maste 	if (op == NULL) {
6471*2c23cb7cSEd Maste 		re->dop |= DW_DEFAULT_OPTIONS;
6472*2c23cb7cSEd Maste 		return;
6473*2c23cb7cSEd Maste 	}
6474*2c23cb7cSEd Maste 
6475*2c23cb7cSEd Maste 	if ((p = strdup(op)) == NULL)
6476*2c23cb7cSEd Maste 		err(EXIT_FAILURE, "strdup failed");
6477*2c23cb7cSEd Maste 	bp = p;
6478*2c23cb7cSEd Maste 
6479*2c23cb7cSEd Maste 	while ((token = strsep(&p, ",")) != NULL) {
6480*2c23cb7cSEd Maste 		for (i = 0; dwarf_op[i].ln != NULL; i++) {
6481*2c23cb7cSEd Maste 			if (!strcmp(token, dwarf_op[i].ln)) {
6482*2c23cb7cSEd Maste 				re->dop |= dwarf_op[i].value;
6483*2c23cb7cSEd Maste 				break;
6484*2c23cb7cSEd Maste 			}
6485*2c23cb7cSEd Maste 		}
6486*2c23cb7cSEd Maste 	}
6487*2c23cb7cSEd Maste 
6488*2c23cb7cSEd Maste 	free(bp);
6489*2c23cb7cSEd Maste }
6490*2c23cb7cSEd Maste 
6491*2c23cb7cSEd Maste static uint64_t
6492*2c23cb7cSEd Maste _read_lsb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read)
6493*2c23cb7cSEd Maste {
6494*2c23cb7cSEd Maste 	uint64_t ret;
6495*2c23cb7cSEd Maste 	uint8_t *src;
6496*2c23cb7cSEd Maste 
6497*2c23cb7cSEd Maste 	src = (uint8_t *) d->d_buf + *offsetp;
6498*2c23cb7cSEd Maste 
6499*2c23cb7cSEd Maste 	ret = 0;
6500*2c23cb7cSEd Maste 	switch (bytes_to_read) {
6501*2c23cb7cSEd Maste 	case 8:
6502*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;
6503*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;
6504*2c23cb7cSEd Maste 	case 4:
6505*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;
6506*2c23cb7cSEd Maste 	case 2:
6507*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 8;
6508*2c23cb7cSEd Maste 	case 1:
6509*2c23cb7cSEd Maste 		ret |= src[0];
6510*2c23cb7cSEd Maste 		break;
6511*2c23cb7cSEd Maste 	default:
6512*2c23cb7cSEd Maste 		return (0);
6513*2c23cb7cSEd Maste 	}
6514*2c23cb7cSEd Maste 
6515*2c23cb7cSEd Maste 	*offsetp += bytes_to_read;
6516*2c23cb7cSEd Maste 
6517*2c23cb7cSEd Maste 	return (ret);
6518*2c23cb7cSEd Maste }
6519*2c23cb7cSEd Maste 
6520*2c23cb7cSEd Maste static uint64_t
6521*2c23cb7cSEd Maste _read_msb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read)
6522*2c23cb7cSEd Maste {
6523*2c23cb7cSEd Maste 	uint64_t ret;
6524*2c23cb7cSEd Maste 	uint8_t *src;
6525*2c23cb7cSEd Maste 
6526*2c23cb7cSEd Maste 	src = (uint8_t *) d->d_buf + *offsetp;
6527*2c23cb7cSEd Maste 
6528*2c23cb7cSEd Maste 	switch (bytes_to_read) {
6529*2c23cb7cSEd Maste 	case 1:
6530*2c23cb7cSEd Maste 		ret = src[0];
6531*2c23cb7cSEd Maste 		break;
6532*2c23cb7cSEd Maste 	case 2:
6533*2c23cb7cSEd Maste 		ret = src[1] | ((uint64_t) src[0]) << 8;
6534*2c23cb7cSEd Maste 		break;
6535*2c23cb7cSEd Maste 	case 4:
6536*2c23cb7cSEd Maste 		ret = src[3] | ((uint64_t) src[2]) << 8;
6537*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;
6538*2c23cb7cSEd Maste 		break;
6539*2c23cb7cSEd Maste 	case 8:
6540*2c23cb7cSEd Maste 		ret = src[7] | ((uint64_t) src[6]) << 8;
6541*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;
6542*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;
6543*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;
6544*2c23cb7cSEd Maste 		break;
6545*2c23cb7cSEd Maste 	default:
6546*2c23cb7cSEd Maste 		return (0);
6547*2c23cb7cSEd Maste 	}
6548*2c23cb7cSEd Maste 
6549*2c23cb7cSEd Maste 	*offsetp += bytes_to_read;
6550*2c23cb7cSEd Maste 
6551*2c23cb7cSEd Maste 	return (ret);
6552*2c23cb7cSEd Maste }
6553*2c23cb7cSEd Maste 
6554*2c23cb7cSEd Maste static uint64_t
6555*2c23cb7cSEd Maste _decode_lsb(uint8_t **data, int bytes_to_read)
6556*2c23cb7cSEd Maste {
6557*2c23cb7cSEd Maste 	uint64_t ret;
6558*2c23cb7cSEd Maste 	uint8_t *src;
6559*2c23cb7cSEd Maste 
6560*2c23cb7cSEd Maste 	src = *data;
6561*2c23cb7cSEd Maste 
6562*2c23cb7cSEd Maste 	ret = 0;
6563*2c23cb7cSEd Maste 	switch (bytes_to_read) {
6564*2c23cb7cSEd Maste 	case 8:
6565*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;
6566*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;
6567*2c23cb7cSEd Maste 	case 4:
6568*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;
6569*2c23cb7cSEd Maste 	case 2:
6570*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 8;
6571*2c23cb7cSEd Maste 	case 1:
6572*2c23cb7cSEd Maste 		ret |= src[0];
6573*2c23cb7cSEd Maste 		break;
6574*2c23cb7cSEd Maste 	default:
6575*2c23cb7cSEd Maste 		return (0);
6576*2c23cb7cSEd Maste 	}
6577*2c23cb7cSEd Maste 
6578*2c23cb7cSEd Maste 	*data += bytes_to_read;
6579*2c23cb7cSEd Maste 
6580*2c23cb7cSEd Maste 	return (ret);
6581*2c23cb7cSEd Maste }
6582*2c23cb7cSEd Maste 
6583*2c23cb7cSEd Maste static uint64_t
6584*2c23cb7cSEd Maste _decode_msb(uint8_t **data, int bytes_to_read)
6585*2c23cb7cSEd Maste {
6586*2c23cb7cSEd Maste 	uint64_t ret;
6587*2c23cb7cSEd Maste 	uint8_t *src;
6588*2c23cb7cSEd Maste 
6589*2c23cb7cSEd Maste 	src = *data;
6590*2c23cb7cSEd Maste 
6591*2c23cb7cSEd Maste 	ret = 0;
6592*2c23cb7cSEd Maste 	switch (bytes_to_read) {
6593*2c23cb7cSEd Maste 	case 1:
6594*2c23cb7cSEd Maste 		ret = src[0];
6595*2c23cb7cSEd Maste 		break;
6596*2c23cb7cSEd Maste 	case 2:
6597*2c23cb7cSEd Maste 		ret = src[1] | ((uint64_t) src[0]) << 8;
6598*2c23cb7cSEd Maste 		break;
6599*2c23cb7cSEd Maste 	case 4:
6600*2c23cb7cSEd Maste 		ret = src[3] | ((uint64_t) src[2]) << 8;
6601*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;
6602*2c23cb7cSEd Maste 		break;
6603*2c23cb7cSEd Maste 	case 8:
6604*2c23cb7cSEd Maste 		ret = src[7] | ((uint64_t) src[6]) << 8;
6605*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;
6606*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;
6607*2c23cb7cSEd Maste 		ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;
6608*2c23cb7cSEd Maste 		break;
6609*2c23cb7cSEd Maste 	default:
6610*2c23cb7cSEd Maste 		return (0);
6611*2c23cb7cSEd Maste 		break;
6612*2c23cb7cSEd Maste 	}
6613*2c23cb7cSEd Maste 
6614*2c23cb7cSEd Maste 	*data += bytes_to_read;
6615*2c23cb7cSEd Maste 
6616*2c23cb7cSEd Maste 	return (ret);
6617*2c23cb7cSEd Maste }
6618*2c23cb7cSEd Maste 
6619*2c23cb7cSEd Maste static int64_t
6620*2c23cb7cSEd Maste _decode_sleb128(uint8_t **dp)
6621*2c23cb7cSEd Maste {
6622*2c23cb7cSEd Maste 	int64_t ret = 0;
6623*2c23cb7cSEd Maste 	uint8_t b;
6624*2c23cb7cSEd Maste 	int shift = 0;
6625*2c23cb7cSEd Maste 
6626*2c23cb7cSEd Maste 	uint8_t *src = *dp;
6627*2c23cb7cSEd Maste 
6628*2c23cb7cSEd Maste 	do {
6629*2c23cb7cSEd Maste 		b = *src++;
6630*2c23cb7cSEd Maste 		ret |= ((b & 0x7f) << shift);
6631*2c23cb7cSEd Maste 		shift += 7;
6632*2c23cb7cSEd Maste 	} while ((b & 0x80) != 0);
6633*2c23cb7cSEd Maste 
6634*2c23cb7cSEd Maste 	if (shift < 32 && (b & 0x40) != 0)
6635*2c23cb7cSEd Maste 		ret |= (-1 << shift);
6636*2c23cb7cSEd Maste 
6637*2c23cb7cSEd Maste 	*dp = src;
6638*2c23cb7cSEd Maste 
6639*2c23cb7cSEd Maste 	return (ret);
6640*2c23cb7cSEd Maste }
6641*2c23cb7cSEd Maste 
6642*2c23cb7cSEd Maste static uint64_t
6643*2c23cb7cSEd Maste _decode_uleb128(uint8_t **dp)
6644*2c23cb7cSEd Maste {
6645*2c23cb7cSEd Maste 	uint64_t ret = 0;
6646*2c23cb7cSEd Maste 	uint8_t b;
6647*2c23cb7cSEd Maste 	int shift = 0;
6648*2c23cb7cSEd Maste 
6649*2c23cb7cSEd Maste 	uint8_t *src = *dp;
6650*2c23cb7cSEd Maste 
6651*2c23cb7cSEd Maste 	do {
6652*2c23cb7cSEd Maste 		b = *src++;
6653*2c23cb7cSEd Maste 		ret |= ((b & 0x7f) << shift);
6654*2c23cb7cSEd Maste 		shift += 7;
6655*2c23cb7cSEd Maste 	} while ((b & 0x80) != 0);
6656*2c23cb7cSEd Maste 
6657*2c23cb7cSEd Maste 	*dp = src;
6658*2c23cb7cSEd Maste 
6659*2c23cb7cSEd Maste 	return (ret);
6660*2c23cb7cSEd Maste }
6661*2c23cb7cSEd Maste 
6662*2c23cb7cSEd Maste static void
6663*2c23cb7cSEd Maste readelf_version(void)
6664*2c23cb7cSEd Maste {
6665*2c23cb7cSEd Maste 	(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(),
6666*2c23cb7cSEd Maste 	    elftc_version());
6667*2c23cb7cSEd Maste 	exit(EXIT_SUCCESS);
6668*2c23cb7cSEd Maste }
6669*2c23cb7cSEd Maste 
6670*2c23cb7cSEd Maste #define	USAGE_MESSAGE	"\
6671*2c23cb7cSEd Maste Usage: %s [options] file...\n\
6672*2c23cb7cSEd Maste   Display information about ELF objects and ar(1) archives.\n\n\
6673*2c23cb7cSEd Maste   Options:\n\
6674*2c23cb7cSEd Maste   -a | --all               Equivalent to specifying options '-dhIlrsASV'.\n\
6675*2c23cb7cSEd Maste   -c | --archive-index     Print the archive symbol table for archives.\n\
6676*2c23cb7cSEd Maste   -d | --dynamic           Print the contents of SHT_DYNAMIC sections.\n\
6677*2c23cb7cSEd Maste   -e | --headers           Print all headers in the object.\n\
6678*2c23cb7cSEd Maste   -g | --section-groups    (accepted, but ignored)\n\
6679*2c23cb7cSEd Maste   -h | --file-header       Print the file header for the object.\n\
6680*2c23cb7cSEd Maste   -l | --program-headers   Print the PHDR table for the object.\n\
6681*2c23cb7cSEd Maste   -n | --notes             Print the contents of SHT_NOTE sections.\n\
6682*2c23cb7cSEd Maste   -p INDEX | --string-dump=INDEX\n\
6683*2c23cb7cSEd Maste                            Print the contents of section at index INDEX.\n\
6684*2c23cb7cSEd Maste   -r | --relocs            Print relocation information.\n\
6685*2c23cb7cSEd Maste   -s | --syms | --symbols  Print symbol tables.\n\
6686*2c23cb7cSEd Maste   -t | --section-details   Print additional information about sections.\n\
6687*2c23cb7cSEd Maste   -v | --version           Print a version identifier and exit.\n\
6688*2c23cb7cSEd Maste   -x INDEX | --hex-dump=INDEX\n\
6689*2c23cb7cSEd Maste                            Display contents of a section as hexadecimal.\n\
6690*2c23cb7cSEd Maste   -A | --arch-specific     (accepted, but ignored)\n\
6691*2c23cb7cSEd Maste   -D | --use-dynamic       Print the symbol table specified by the DT_SYMTAB\n\
6692*2c23cb7cSEd Maste                            entry in the \".dynamic\" section.\n\
6693*2c23cb7cSEd Maste   -H | --help              Print a help message.\n\
6694*2c23cb7cSEd Maste   -I | --histogram         Print information on bucket list lengths for \n\
6695*2c23cb7cSEd Maste                            hash sections.\n\
6696*2c23cb7cSEd Maste   -N | --full-section-name (accepted, but ignored)\n\
6697*2c23cb7cSEd Maste   -S | --sections | --section-headers\n\
6698*2c23cb7cSEd Maste                            Print information about section headers.\n\
6699*2c23cb7cSEd Maste   -V | --version-info      Print symbol versoning information.\n\
6700*2c23cb7cSEd Maste   -W | --wide              Print information without wrapping long lines.\n"
6701*2c23cb7cSEd Maste 
6702*2c23cb7cSEd Maste 
6703*2c23cb7cSEd Maste static void
6704*2c23cb7cSEd Maste readelf_usage(void)
6705*2c23cb7cSEd Maste {
6706*2c23cb7cSEd Maste 	fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
6707*2c23cb7cSEd Maste 	exit(EXIT_FAILURE);
6708*2c23cb7cSEd Maste }
6709*2c23cb7cSEd Maste 
6710*2c23cb7cSEd Maste int
6711*2c23cb7cSEd Maste main(int argc, char **argv)
6712*2c23cb7cSEd Maste {
6713*2c23cb7cSEd Maste 	struct readelf	*re, re_storage;
6714*2c23cb7cSEd Maste 	unsigned long	 si;
6715*2c23cb7cSEd Maste 	int		 opt, i;
6716*2c23cb7cSEd Maste 	char		*ep;
6717*2c23cb7cSEd Maste 
6718*2c23cb7cSEd Maste 	re = &re_storage;
6719*2c23cb7cSEd Maste 	memset(re, 0, sizeof(*re));
6720*2c23cb7cSEd Maste 	STAILQ_INIT(&re->v_dumpop);
6721*2c23cb7cSEd Maste 
6722*2c23cb7cSEd Maste 	while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:",
6723*2c23cb7cSEd Maste 	    longopts, NULL)) != -1) {
6724*2c23cb7cSEd Maste 		switch(opt) {
6725*2c23cb7cSEd Maste 		case '?':
6726*2c23cb7cSEd Maste 			readelf_usage();
6727*2c23cb7cSEd Maste 			break;
6728*2c23cb7cSEd Maste 		case 'A':
6729*2c23cb7cSEd Maste 			re->options |= RE_AA;
6730*2c23cb7cSEd Maste 			break;
6731*2c23cb7cSEd Maste 		case 'a':
6732*2c23cb7cSEd Maste 			re->options |= RE_AA | RE_D | RE_H | RE_II | RE_L |
6733*2c23cb7cSEd Maste 			    RE_R | RE_SS | RE_S | RE_VV;
6734*2c23cb7cSEd Maste 			break;
6735*2c23cb7cSEd Maste 		case 'c':
6736*2c23cb7cSEd Maste 			re->options |= RE_C;
6737*2c23cb7cSEd Maste 			break;
6738*2c23cb7cSEd Maste 		case 'D':
6739*2c23cb7cSEd Maste 			re->options |= RE_DD;
6740*2c23cb7cSEd Maste 			break;
6741*2c23cb7cSEd Maste 		case 'd':
6742*2c23cb7cSEd Maste 			re->options |= RE_D;
6743*2c23cb7cSEd Maste 			break;
6744*2c23cb7cSEd Maste 		case 'e':
6745*2c23cb7cSEd Maste 			re->options |= RE_H | RE_L | RE_SS;
6746*2c23cb7cSEd Maste 			break;
6747*2c23cb7cSEd Maste 		case 'g':
6748*2c23cb7cSEd Maste 			re->options |= RE_G;
6749*2c23cb7cSEd Maste 			break;
6750*2c23cb7cSEd Maste 		case 'H':
6751*2c23cb7cSEd Maste 			readelf_usage();
6752*2c23cb7cSEd Maste 			break;
6753*2c23cb7cSEd Maste 		case 'h':
6754*2c23cb7cSEd Maste 			re->options |= RE_H;
6755*2c23cb7cSEd Maste 			break;
6756*2c23cb7cSEd Maste 		case 'I':
6757*2c23cb7cSEd Maste 			re->options |= RE_II;
6758*2c23cb7cSEd Maste 			break;
6759*2c23cb7cSEd Maste 		case 'i':
6760*2c23cb7cSEd Maste 			/* Not implemented yet. */
6761*2c23cb7cSEd Maste 			break;
6762*2c23cb7cSEd Maste 		case 'l':
6763*2c23cb7cSEd Maste 			re->options |= RE_L;
6764*2c23cb7cSEd Maste 			break;
6765*2c23cb7cSEd Maste 		case 'N':
6766*2c23cb7cSEd Maste 			re->options |= RE_NN;
6767*2c23cb7cSEd Maste 			break;
6768*2c23cb7cSEd Maste 		case 'n':
6769*2c23cb7cSEd Maste 			re->options |= RE_N;
6770*2c23cb7cSEd Maste 			break;
6771*2c23cb7cSEd Maste 		case 'p':
6772*2c23cb7cSEd Maste 			re->options |= RE_P;
6773*2c23cb7cSEd Maste 			si = strtoul(optarg, &ep, 10);
6774*2c23cb7cSEd Maste 			if (*ep == '\0')
6775*2c23cb7cSEd Maste 				add_dumpop(re, (size_t) si, NULL, STR_DUMP,
6776*2c23cb7cSEd Maste 				    DUMP_BY_INDEX);
6777*2c23cb7cSEd Maste 			else
6778*2c23cb7cSEd Maste 				add_dumpop(re, 0, optarg, STR_DUMP,
6779*2c23cb7cSEd Maste 				    DUMP_BY_NAME);
6780*2c23cb7cSEd Maste 			break;
6781*2c23cb7cSEd Maste 		case 'r':
6782*2c23cb7cSEd Maste 			re->options |= RE_R;
6783*2c23cb7cSEd Maste 			break;
6784*2c23cb7cSEd Maste 		case 'S':
6785*2c23cb7cSEd Maste 			re->options |= RE_SS;
6786*2c23cb7cSEd Maste 			break;
6787*2c23cb7cSEd Maste 		case 's':
6788*2c23cb7cSEd Maste 			re->options |= RE_S;
6789*2c23cb7cSEd Maste 			break;
6790*2c23cb7cSEd Maste 		case 't':
6791*2c23cb7cSEd Maste 			re->options |= RE_T;
6792*2c23cb7cSEd Maste 			break;
6793*2c23cb7cSEd Maste 		case 'u':
6794*2c23cb7cSEd Maste 			re->options |= RE_U;
6795*2c23cb7cSEd Maste 			break;
6796*2c23cb7cSEd Maste 		case 'V':
6797*2c23cb7cSEd Maste 			re->options |= RE_VV;
6798*2c23cb7cSEd Maste 			break;
6799*2c23cb7cSEd Maste 		case 'v':
6800*2c23cb7cSEd Maste 			readelf_version();
6801*2c23cb7cSEd Maste 			break;
6802*2c23cb7cSEd Maste 		case 'W':
6803*2c23cb7cSEd Maste 			re->options |= RE_WW;
6804*2c23cb7cSEd Maste 			break;
6805*2c23cb7cSEd Maste 		case 'w':
6806*2c23cb7cSEd Maste 			re->options |= RE_W;
6807*2c23cb7cSEd Maste 			parse_dwarf_op_short(re, optarg);
6808*2c23cb7cSEd Maste 			break;
6809*2c23cb7cSEd Maste 		case 'x':
6810*2c23cb7cSEd Maste 			re->options |= RE_X;
6811*2c23cb7cSEd Maste 			si = strtoul(optarg, &ep, 10);
6812*2c23cb7cSEd Maste 			if (*ep == '\0')
6813*2c23cb7cSEd Maste 				add_dumpop(re, (size_t) si, NULL, HEX_DUMP,
6814*2c23cb7cSEd Maste 				    DUMP_BY_INDEX);
6815*2c23cb7cSEd Maste 			else
6816*2c23cb7cSEd Maste 				add_dumpop(re, 0, optarg, HEX_DUMP,
6817*2c23cb7cSEd Maste 				    DUMP_BY_NAME);
6818*2c23cb7cSEd Maste 			break;
6819*2c23cb7cSEd Maste 		case OPTION_DEBUG_DUMP:
6820*2c23cb7cSEd Maste 			re->options |= RE_W;
6821*2c23cb7cSEd Maste 			parse_dwarf_op_long(re, optarg);
6822*2c23cb7cSEd Maste 		}
6823*2c23cb7cSEd Maste 	}
6824*2c23cb7cSEd Maste 
6825*2c23cb7cSEd Maste 	argv += optind;
6826*2c23cb7cSEd Maste 	argc -= optind;
6827*2c23cb7cSEd Maste 
6828*2c23cb7cSEd Maste 	if (argc == 0 || re->options == 0)
6829*2c23cb7cSEd Maste 		readelf_usage();
6830*2c23cb7cSEd Maste 
6831*2c23cb7cSEd Maste 	if (argc > 1)
6832*2c23cb7cSEd Maste 		re->flags |= DISPLAY_FILENAME;
6833*2c23cb7cSEd Maste 
6834*2c23cb7cSEd Maste 	if (elf_version(EV_CURRENT) == EV_NONE)
6835*2c23cb7cSEd Maste 		errx(EXIT_FAILURE, "ELF library initialization failed: %s",
6836*2c23cb7cSEd Maste 		    elf_errmsg(-1));
6837*2c23cb7cSEd Maste 
6838*2c23cb7cSEd Maste 	for (i = 0; i < argc; i++)
6839*2c23cb7cSEd Maste 		if (argv[i] != NULL) {
6840*2c23cb7cSEd Maste 			re->filename = argv[i];
6841*2c23cb7cSEd Maste 			dump_object(re);
6842*2c23cb7cSEd Maste 		}
6843*2c23cb7cSEd Maste 
6844*2c23cb7cSEd Maste 	exit(EXIT_SUCCESS);
6845*2c23cb7cSEd Maste }
6846