xref: /freebsd/contrib/elftoolchain/addr2line/addr2line.c (revision a85fe12e361c14018a24f0f7714663b490206c7f)
1*a85fe12eSEd Maste /*-
2*a85fe12eSEd Maste  * Copyright (c) 2009 Kai Wang
3*a85fe12eSEd Maste  * All rights reserved.
4*a85fe12eSEd Maste  *
5*a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6*a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7*a85fe12eSEd Maste  * are met:
8*a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9*a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer.
10*a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11*a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12*a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
13*a85fe12eSEd Maste  *
14*a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*a85fe12eSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*a85fe12eSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*a85fe12eSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*a85fe12eSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*a85fe12eSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*a85fe12eSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*a85fe12eSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*a85fe12eSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*a85fe12eSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*a85fe12eSEd Maste  * SUCH DAMAGE.
25*a85fe12eSEd Maste  */
26*a85fe12eSEd Maste 
27*a85fe12eSEd Maste #include <sys/cdefs.h>
28*a85fe12eSEd Maste #include <sys/param.h>
29*a85fe12eSEd Maste #include <dwarf.h>
30*a85fe12eSEd Maste #include <err.h>
31*a85fe12eSEd Maste #include <fcntl.h>
32*a85fe12eSEd Maste #include <gelf.h>
33*a85fe12eSEd Maste #include <getopt.h>
34*a85fe12eSEd Maste #include <libdwarf.h>
35*a85fe12eSEd Maste #include <libelftc.h>
36*a85fe12eSEd Maste #include <libgen.h>
37*a85fe12eSEd Maste #include <stdio.h>
38*a85fe12eSEd Maste #include <stdlib.h>
39*a85fe12eSEd Maste #include <string.h>
40*a85fe12eSEd Maste 
41*a85fe12eSEd Maste #include "_elftc.h"
42*a85fe12eSEd Maste 
43*a85fe12eSEd Maste ELFTC_VCSID("$Id: addr2line.c 2185 2011-11-19 16:07:16Z jkoshy $");
44*a85fe12eSEd Maste 
45*a85fe12eSEd Maste static struct option longopts[] = {
46*a85fe12eSEd Maste 	{"target" , required_argument, NULL, 'b'},
47*a85fe12eSEd Maste 	{"demangle", no_argument, NULL, 'C'},
48*a85fe12eSEd Maste 	{"exe", required_argument, NULL, 'e'},
49*a85fe12eSEd Maste 	{"functions", no_argument, NULL, 'f'},
50*a85fe12eSEd Maste 	{"section", required_argument, NULL, 'j'},
51*a85fe12eSEd Maste 	{"basename", no_argument, NULL, 's'},
52*a85fe12eSEd Maste 	{"help", no_argument, NULL, 'H'},
53*a85fe12eSEd Maste 	{"version", no_argument, NULL, 'V'},
54*a85fe12eSEd Maste 	{NULL, 0, NULL, 0}
55*a85fe12eSEd Maste };
56*a85fe12eSEd Maste static int demangle, func, base;
57*a85fe12eSEd Maste static char unknown[] = { '?', '?', '\0' };
58*a85fe12eSEd Maste static Dwarf_Addr section_base;
59*a85fe12eSEd Maste 
60*a85fe12eSEd Maste #define	USAGE_MESSAGE	"\
61*a85fe12eSEd Maste Usage: %s [options] hexaddress...\n\
62*a85fe12eSEd Maste   Map program addresses to source file names and line numbers.\n\n\
63*a85fe12eSEd Maste   Options:\n\
64*a85fe12eSEd Maste   -b TGT  | --target=TGT      (Accepted but ignored).\n\
65*a85fe12eSEd Maste   -e EXE  | --exec=EXE        Use program \"EXE\" to translate addresses.\n\
66*a85fe12eSEd Maste   -f      | --functions       Display function names.\n\
67*a85fe12eSEd Maste   -j NAME | --section=NAME    Values are offsets into section \"NAME\".\n\
68*a85fe12eSEd Maste   -s      | --basename        Only show the base name for each file name.\n\
69*a85fe12eSEd Maste   -C      | --demangle        Demangle C++ names.\n\
70*a85fe12eSEd Maste   -H      | --help            Print a help message.\n\
71*a85fe12eSEd Maste   -V      | --version         Print a version identifier and exit.\n"
72*a85fe12eSEd Maste 
73*a85fe12eSEd Maste static void
74*a85fe12eSEd Maste usage(void)
75*a85fe12eSEd Maste {
76*a85fe12eSEd Maste 	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
77*a85fe12eSEd Maste 	exit(1);
78*a85fe12eSEd Maste }
79*a85fe12eSEd Maste 
80*a85fe12eSEd Maste static void
81*a85fe12eSEd Maste version(void)
82*a85fe12eSEd Maste {
83*a85fe12eSEd Maste 
84*a85fe12eSEd Maste 	fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
85*a85fe12eSEd Maste 	exit(0);
86*a85fe12eSEd Maste }
87*a85fe12eSEd Maste 
88*a85fe12eSEd Maste static void
89*a85fe12eSEd Maste search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr,
90*a85fe12eSEd Maste     const char **rlt_func)
91*a85fe12eSEd Maste {
92*a85fe12eSEd Maste 	Dwarf_Die ret_die, spec_die;
93*a85fe12eSEd Maste 	Dwarf_Error de;
94*a85fe12eSEd Maste 	Dwarf_Half tag;
95*a85fe12eSEd Maste 	Dwarf_Unsigned lopc, hipc;
96*a85fe12eSEd Maste 	Dwarf_Off ref;
97*a85fe12eSEd Maste 	Dwarf_Attribute sub_at, spec_at;
98*a85fe12eSEd Maste 	char *func0;
99*a85fe12eSEd Maste 	int ret;
100*a85fe12eSEd Maste 
101*a85fe12eSEd Maste 	if (*rlt_func != NULL)
102*a85fe12eSEd Maste 		return;
103*a85fe12eSEd Maste 
104*a85fe12eSEd Maste 	if (dwarf_tag(die, &tag, &de)) {
105*a85fe12eSEd Maste 		warnx("dwarf_tag: %s", dwarf_errmsg(de));
106*a85fe12eSEd Maste 		goto cont_search;
107*a85fe12eSEd Maste 	}
108*a85fe12eSEd Maste 	if (tag == DW_TAG_subprogram) {
109*a85fe12eSEd Maste 		if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
110*a85fe12eSEd Maste 		    dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
111*a85fe12eSEd Maste 			goto cont_search;
112*a85fe12eSEd Maste 		if (addr < lopc || addr >= hipc)
113*a85fe12eSEd Maste 			goto cont_search;
114*a85fe12eSEd Maste 
115*a85fe12eSEd Maste 		/* Found it! */
116*a85fe12eSEd Maste 
117*a85fe12eSEd Maste 		*rlt_func = unknown;
118*a85fe12eSEd Maste 		ret = dwarf_attr(die, DW_AT_name, &sub_at, &de);
119*a85fe12eSEd Maste 		if (ret == DW_DLV_ERROR)
120*a85fe12eSEd Maste 			return;
121*a85fe12eSEd Maste 		if (ret == DW_DLV_OK) {
122*a85fe12eSEd Maste 			if (dwarf_formstring(sub_at, &func0, &de))
123*a85fe12eSEd Maste 				*rlt_func = unknown;
124*a85fe12eSEd Maste 			else
125*a85fe12eSEd Maste 				*rlt_func = func0;
126*a85fe12eSEd Maste 			return;
127*a85fe12eSEd Maste 		}
128*a85fe12eSEd Maste 
129*a85fe12eSEd Maste 		/*
130*a85fe12eSEd Maste 		 * If DW_AT_name is not present, but DW_AT_specification is
131*a85fe12eSEd Maste 		 * present, then probably the actual name is in the DIE
132*a85fe12eSEd Maste 		 * referenced by DW_AT_specification.
133*a85fe12eSEd Maste 		 */
134*a85fe12eSEd Maste 		if (dwarf_attr(die, DW_AT_specification, &spec_at, &de))
135*a85fe12eSEd Maste 			return;
136*a85fe12eSEd Maste 		if (dwarf_global_formref(spec_at, &ref, &de))
137*a85fe12eSEd Maste 			return;
138*a85fe12eSEd Maste 		if (dwarf_offdie(dbg, ref, &spec_die, &de))
139*a85fe12eSEd Maste 			return;
140*a85fe12eSEd Maste 		if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de))
141*a85fe12eSEd Maste 			*rlt_func = unknown;
142*a85fe12eSEd Maste 
143*a85fe12eSEd Maste 		return;
144*a85fe12eSEd Maste 	}
145*a85fe12eSEd Maste 
146*a85fe12eSEd Maste cont_search:
147*a85fe12eSEd Maste 
148*a85fe12eSEd Maste 	/* Search children. */
149*a85fe12eSEd Maste 	ret = dwarf_child(die, &ret_die, &de);
150*a85fe12eSEd Maste 	if (ret == DW_DLV_ERROR)
151*a85fe12eSEd Maste 		errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de));
152*a85fe12eSEd Maste 	else if (ret == DW_DLV_OK)
153*a85fe12eSEd Maste 		search_func(dbg, ret_die, addr, rlt_func);
154*a85fe12eSEd Maste 
155*a85fe12eSEd Maste 	/* Search sibling. */
156*a85fe12eSEd Maste 	ret = dwarf_siblingof(dbg, die, &ret_die, &de);
157*a85fe12eSEd Maste 	if (ret == DW_DLV_ERROR)
158*a85fe12eSEd Maste 		errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de));
159*a85fe12eSEd Maste 	else if (ret == DW_DLV_OK)
160*a85fe12eSEd Maste 		search_func(dbg, ret_die, addr, rlt_func);
161*a85fe12eSEd Maste }
162*a85fe12eSEd Maste 
163*a85fe12eSEd Maste static void
164*a85fe12eSEd Maste translate(Dwarf_Debug dbg, const char* addrstr)
165*a85fe12eSEd Maste {
166*a85fe12eSEd Maste 	Dwarf_Die die;
167*a85fe12eSEd Maste 	Dwarf_Line *lbuf;
168*a85fe12eSEd Maste 	Dwarf_Error de;
169*a85fe12eSEd Maste 	Dwarf_Half tag;
170*a85fe12eSEd Maste 	Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
171*a85fe12eSEd Maste 	Dwarf_Signed lcount;
172*a85fe12eSEd Maste 	Dwarf_Addr lineaddr, plineaddr;
173*a85fe12eSEd Maste 	const char *funcname;
174*a85fe12eSEd Maste 	char *file, *file0, *pfile;
175*a85fe12eSEd Maste 	char demangled[1024];
176*a85fe12eSEd Maste 	int i, ret;
177*a85fe12eSEd Maste 
178*a85fe12eSEd Maste 	addr = strtoull(addrstr, NULL, 16);
179*a85fe12eSEd Maste 	addr += section_base;
180*a85fe12eSEd Maste 	lineno = 0;
181*a85fe12eSEd Maste 	file = unknown;
182*a85fe12eSEd Maste 
183*a85fe12eSEd Maste 	while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
184*a85fe12eSEd Maste 	    &de)) ==  DW_DLV_OK) {
185*a85fe12eSEd Maste 		die = NULL;
186*a85fe12eSEd Maste 		while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
187*a85fe12eSEd Maste 			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
188*a85fe12eSEd Maste 				warnx("dwarf_tag failed: %s",
189*a85fe12eSEd Maste 				    dwarf_errmsg(de));
190*a85fe12eSEd Maste 				goto out;
191*a85fe12eSEd Maste 			}
192*a85fe12eSEd Maste 			/* XXX: What about DW_TAG_partial_unit? */
193*a85fe12eSEd Maste 			if (tag == DW_TAG_compile_unit)
194*a85fe12eSEd Maste 				break;
195*a85fe12eSEd Maste 		}
196*a85fe12eSEd Maste 		if (die == NULL) {
197*a85fe12eSEd Maste 			warnx("could not find DW_TAG_compile_unit die");
198*a85fe12eSEd Maste 			goto out;
199*a85fe12eSEd Maste 		}
200*a85fe12eSEd Maste 		if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
201*a85fe12eSEd Maste 		    !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
202*a85fe12eSEd Maste 			/*
203*a85fe12eSEd Maste 			 * Check if the address falls into the PC range of
204*a85fe12eSEd Maste 			 * this CU.
205*a85fe12eSEd Maste 			 */
206*a85fe12eSEd Maste 			if (addr < lopc || addr >= hipc)
207*a85fe12eSEd Maste 				continue;
208*a85fe12eSEd Maste 		}
209*a85fe12eSEd Maste 
210*a85fe12eSEd Maste 		if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) {
211*a85fe12eSEd Maste 			warnx("dwarf_srclines: %s", dwarf_errmsg(de));
212*a85fe12eSEd Maste 			goto out;
213*a85fe12eSEd Maste 		}
214*a85fe12eSEd Maste 
215*a85fe12eSEd Maste 		plineaddr = ~0ULL;
216*a85fe12eSEd Maste 		plineno = 0;
217*a85fe12eSEd Maste 		pfile = unknown;
218*a85fe12eSEd Maste 		for (i = 0; i < lcount; i++) {
219*a85fe12eSEd Maste 			if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
220*a85fe12eSEd Maste 				warnx("dwarf_lineaddr: %s",
221*a85fe12eSEd Maste 				    dwarf_errmsg(de));
222*a85fe12eSEd Maste 				goto out;
223*a85fe12eSEd Maste 			}
224*a85fe12eSEd Maste 			if (dwarf_lineno(lbuf[i], &lineno, &de)) {
225*a85fe12eSEd Maste 				warnx("dwarf_lineno: %s",
226*a85fe12eSEd Maste 				    dwarf_errmsg(de));
227*a85fe12eSEd Maste 				goto out;
228*a85fe12eSEd Maste 			}
229*a85fe12eSEd Maste 			if (dwarf_linesrc(lbuf[i], &file0, &de)) {
230*a85fe12eSEd Maste 				warnx("dwarf_linesrc: %s",
231*a85fe12eSEd Maste 				    dwarf_errmsg(de));
232*a85fe12eSEd Maste 			} else
233*a85fe12eSEd Maste 				file = file0;
234*a85fe12eSEd Maste 			if (addr == lineaddr)
235*a85fe12eSEd Maste 				goto out;
236*a85fe12eSEd Maste 			else if (addr < lineaddr && addr > plineaddr) {
237*a85fe12eSEd Maste 				lineno = plineno;
238*a85fe12eSEd Maste 				file = pfile;
239*a85fe12eSEd Maste 				goto out;
240*a85fe12eSEd Maste 			}
241*a85fe12eSEd Maste 			plineaddr = lineaddr;
242*a85fe12eSEd Maste 			plineno = lineno;
243*a85fe12eSEd Maste 			pfile = file;
244*a85fe12eSEd Maste 		}
245*a85fe12eSEd Maste 	}
246*a85fe12eSEd Maste 
247*a85fe12eSEd Maste out:
248*a85fe12eSEd Maste 	funcname = NULL;
249*a85fe12eSEd Maste 	if (ret == DW_DLV_OK && func)
250*a85fe12eSEd Maste 		search_func(dbg, die, addr, &funcname);
251*a85fe12eSEd Maste 
252*a85fe12eSEd Maste 	if (func) {
253*a85fe12eSEd Maste 		if (funcname == NULL)
254*a85fe12eSEd Maste 			funcname = unknown;
255*a85fe12eSEd Maste 		if (demangle &&
256*a85fe12eSEd Maste 		    !elftc_demangle(funcname, demangled, sizeof(demangled), 0))
257*a85fe12eSEd Maste 			printf("%s\n", demangled);
258*a85fe12eSEd Maste 		else
259*a85fe12eSEd Maste 			printf("%s\n", funcname);
260*a85fe12eSEd Maste 	}
261*a85fe12eSEd Maste 
262*a85fe12eSEd Maste 	(void) printf("%s:%ju\n", base ? basename(file) : file, lineno);
263*a85fe12eSEd Maste 
264*a85fe12eSEd Maste 	/*
265*a85fe12eSEd Maste 	 * Reset internal CU pointer, so we will start from the first CU
266*a85fe12eSEd Maste 	 * next round.
267*a85fe12eSEd Maste 	 */
268*a85fe12eSEd Maste 	while (ret != DW_DLV_NO_ENTRY) {
269*a85fe12eSEd Maste 		if (ret == DW_DLV_ERROR)
270*a85fe12eSEd Maste 			errx(EXIT_FAILURE, "dwarf_next_cu_header: %s",
271*a85fe12eSEd Maste 			    dwarf_errmsg(de));
272*a85fe12eSEd Maste 		ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
273*a85fe12eSEd Maste 		    &de);
274*a85fe12eSEd Maste 	}
275*a85fe12eSEd Maste }
276*a85fe12eSEd Maste 
277*a85fe12eSEd Maste static void
278*a85fe12eSEd Maste find_section_base(const char *exe, Elf *e, const char *section)
279*a85fe12eSEd Maste {
280*a85fe12eSEd Maste 	Dwarf_Addr off;
281*a85fe12eSEd Maste 	Elf_Scn *scn;
282*a85fe12eSEd Maste 	GElf_Ehdr eh;
283*a85fe12eSEd Maste 	GElf_Shdr sh;
284*a85fe12eSEd Maste 	size_t shstrndx;
285*a85fe12eSEd Maste 	int elferr;
286*a85fe12eSEd Maste 	const char *name;
287*a85fe12eSEd Maste 
288*a85fe12eSEd Maste 	if (gelf_getehdr(e, &eh) != &eh) {
289*a85fe12eSEd Maste 		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
290*a85fe12eSEd Maste 		return;
291*a85fe12eSEd Maste 	}
292*a85fe12eSEd Maste 
293*a85fe12eSEd Maste 	if (!elf_getshstrndx(e, &shstrndx)) {
294*a85fe12eSEd Maste 		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
295*a85fe12eSEd Maste 		return;
296*a85fe12eSEd Maste 	}
297*a85fe12eSEd Maste 
298*a85fe12eSEd Maste 	(void) elf_errno();
299*a85fe12eSEd Maste 	off = 0;
300*a85fe12eSEd Maste 	scn = NULL;
301*a85fe12eSEd Maste 	while ((scn = elf_nextscn(e, scn)) != NULL) {
302*a85fe12eSEd Maste 		if (gelf_getshdr(scn, &sh) == NULL) {
303*a85fe12eSEd Maste 			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
304*a85fe12eSEd Maste 			continue;
305*a85fe12eSEd Maste 		}
306*a85fe12eSEd Maste 		if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
307*a85fe12eSEd Maste 			goto next;
308*a85fe12eSEd Maste 		if (!strcmp(section, name)) {
309*a85fe12eSEd Maste 			if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
310*a85fe12eSEd Maste 				/*
311*a85fe12eSEd Maste 				 * For executables, section base is the virtual
312*a85fe12eSEd Maste 				 * address of the specified section.
313*a85fe12eSEd Maste 				 */
314*a85fe12eSEd Maste 				section_base = sh.sh_addr;
315*a85fe12eSEd Maste 			} else if (eh.e_type == ET_REL) {
316*a85fe12eSEd Maste 				/*
317*a85fe12eSEd Maste 				 * For relocatables, section base is the
318*a85fe12eSEd Maste 				 * relative offset of the specified section
319*a85fe12eSEd Maste 				 * to the start of the first section.
320*a85fe12eSEd Maste 				 */
321*a85fe12eSEd Maste 				section_base = off;
322*a85fe12eSEd Maste 			} else
323*a85fe12eSEd Maste 				warnx("unknown e_type %u", eh.e_type);
324*a85fe12eSEd Maste 			return;
325*a85fe12eSEd Maste 		}
326*a85fe12eSEd Maste 	next:
327*a85fe12eSEd Maste 		off += sh.sh_size;
328*a85fe12eSEd Maste 	}
329*a85fe12eSEd Maste 	elferr = elf_errno();
330*a85fe12eSEd Maste 	if (elferr != 0)
331*a85fe12eSEd Maste 		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
332*a85fe12eSEd Maste 
333*a85fe12eSEd Maste 	errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
334*a85fe12eSEd Maste }
335*a85fe12eSEd Maste 
336*a85fe12eSEd Maste int
337*a85fe12eSEd Maste main(int argc, char **argv)
338*a85fe12eSEd Maste {
339*a85fe12eSEd Maste 	Elf *e;
340*a85fe12eSEd Maste 	Dwarf_Debug dbg;
341*a85fe12eSEd Maste 	Dwarf_Error de;
342*a85fe12eSEd Maste 	const char *exe, *section;
343*a85fe12eSEd Maste 	char line[1024];
344*a85fe12eSEd Maste 	int fd, i, opt;
345*a85fe12eSEd Maste 
346*a85fe12eSEd Maste 	exe = NULL;
347*a85fe12eSEd Maste 	section = NULL;
348*a85fe12eSEd Maste 	while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) !=
349*a85fe12eSEd Maste 	    -1) {
350*a85fe12eSEd Maste 		switch (opt) {
351*a85fe12eSEd Maste 		case 'b':
352*a85fe12eSEd Maste 			/* ignored */
353*a85fe12eSEd Maste 			break;
354*a85fe12eSEd Maste 		case 'C':
355*a85fe12eSEd Maste 			demangle = 1;
356*a85fe12eSEd Maste 			break;
357*a85fe12eSEd Maste 		case 'e':
358*a85fe12eSEd Maste 			exe = optarg;
359*a85fe12eSEd Maste 			break;
360*a85fe12eSEd Maste 		case 'f':
361*a85fe12eSEd Maste 			func = 1;
362*a85fe12eSEd Maste 			break;
363*a85fe12eSEd Maste 		case 'j':
364*a85fe12eSEd Maste 			section = optarg;
365*a85fe12eSEd Maste 			break;
366*a85fe12eSEd Maste 		case 's':
367*a85fe12eSEd Maste 			base = 1;
368*a85fe12eSEd Maste 			break;
369*a85fe12eSEd Maste 		case 'H':
370*a85fe12eSEd Maste 			usage();
371*a85fe12eSEd Maste 		case 'V':
372*a85fe12eSEd Maste 			version();
373*a85fe12eSEd Maste 		default:
374*a85fe12eSEd Maste 			usage();
375*a85fe12eSEd Maste 		}
376*a85fe12eSEd Maste 	}
377*a85fe12eSEd Maste 
378*a85fe12eSEd Maste 	argv += optind;
379*a85fe12eSEd Maste 	argc -= optind;
380*a85fe12eSEd Maste 
381*a85fe12eSEd Maste 	if (exe == NULL)
382*a85fe12eSEd Maste 		exe = "a.out";
383*a85fe12eSEd Maste 
384*a85fe12eSEd Maste 	if ((fd = open(exe, O_RDONLY)) < 0)
385*a85fe12eSEd Maste 		err(EXIT_FAILURE, "%s", exe);
386*a85fe12eSEd Maste 
387*a85fe12eSEd Maste 	if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
388*a85fe12eSEd Maste 		errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
389*a85fe12eSEd Maste 
390*a85fe12eSEd Maste 	if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
391*a85fe12eSEd Maste 		errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
392*a85fe12eSEd Maste 
393*a85fe12eSEd Maste 	if (section)
394*a85fe12eSEd Maste 		find_section_base(exe, e, section);
395*a85fe12eSEd Maste 	else
396*a85fe12eSEd Maste 		section_base = 0;
397*a85fe12eSEd Maste 
398*a85fe12eSEd Maste 	if (argc > 0)
399*a85fe12eSEd Maste 		for (i = 0; i < argc; i++)
400*a85fe12eSEd Maste 			translate(dbg, argv[i]);
401*a85fe12eSEd Maste 	else
402*a85fe12eSEd Maste 		while (fgets(line, sizeof(line), stdin) != NULL)
403*a85fe12eSEd Maste 			translate(dbg, line);
404*a85fe12eSEd Maste 
405*a85fe12eSEd Maste 	dwarf_finish(dbg, &de);
406*a85fe12eSEd Maste 
407*a85fe12eSEd Maste 	(void) elf_end(e);
408*a85fe12eSEd Maste 
409*a85fe12eSEd Maste 	exit(0);
410*a85fe12eSEd Maste }
411