addr2line.c revision 289074
1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2009 Kai Wang
3260684Skaiw * All rights reserved.
4260684Skaiw *
5260684Skaiw * Redistribution and use in source and binary forms, with or without
6260684Skaiw * modification, are permitted provided that the following conditions
7260684Skaiw * are met:
8260684Skaiw * 1. Redistributions of source code must retain the above copyright
9260684Skaiw *    notice, this list of conditions and the following disclaimer.
10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer in the
12260684Skaiw *    documentation and/or other materials provided with the distribution.
13260684Skaiw *
14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24260684Skaiw * SUCH DAMAGE.
25260684Skaiw */
26260684Skaiw
27260684Skaiw#include <sys/param.h>
28260684Skaiw#include <dwarf.h>
29260684Skaiw#include <err.h>
30260684Skaiw#include <fcntl.h>
31260684Skaiw#include <gelf.h>
32260684Skaiw#include <getopt.h>
33260684Skaiw#include <libdwarf.h>
34260684Skaiw#include <libelftc.h>
35260684Skaiw#include <libgen.h>
36260684Skaiw#include <stdio.h>
37260684Skaiw#include <stdlib.h>
38260684Skaiw#include <string.h>
39260684Skaiw
40260684Skaiw#include "_elftc.h"
41260684Skaiw
42289071SemasteELFTC_VCSID("$Id: addr2line.c 3249 2015-10-04 08:11:30Z kaiwang27 $");
43260684Skaiw
44260684Skaiwstatic struct option longopts[] = {
45260684Skaiw	{"target" , required_argument, NULL, 'b'},
46260684Skaiw	{"demangle", no_argument, NULL, 'C'},
47260684Skaiw	{"exe", required_argument, NULL, 'e'},
48260684Skaiw	{"functions", no_argument, NULL, 'f'},
49260684Skaiw	{"section", required_argument, NULL, 'j'},
50260684Skaiw	{"basename", no_argument, NULL, 's'},
51260684Skaiw	{"help", no_argument, NULL, 'H'},
52260684Skaiw	{"version", no_argument, NULL, 'V'},
53260684Skaiw	{NULL, 0, NULL, 0}
54260684Skaiw};
55260684Skaiwstatic int demangle, func, base;
56260684Skaiwstatic char unknown[] = { '?', '?', '\0' };
57260684Skaiwstatic Dwarf_Addr section_base;
58260684Skaiw
59260684Skaiw#define	USAGE_MESSAGE	"\
60260684SkaiwUsage: %s [options] hexaddress...\n\
61260684Skaiw  Map program addresses to source file names and line numbers.\n\n\
62260684Skaiw  Options:\n\
63260684Skaiw  -b TGT  | --target=TGT      (Accepted but ignored).\n\
64289071Semaste  -e EXE  | --exe=EXE         Use program \"EXE\" to translate addresses.\n\
65260684Skaiw  -f      | --functions       Display function names.\n\
66260684Skaiw  -j NAME | --section=NAME    Values are offsets into section \"NAME\".\n\
67260684Skaiw  -s      | --basename        Only show the base name for each file name.\n\
68260684Skaiw  -C      | --demangle        Demangle C++ names.\n\
69260684Skaiw  -H      | --help            Print a help message.\n\
70260684Skaiw  -V      | --version         Print a version identifier and exit.\n"
71260684Skaiw
72260684Skaiwstatic void
73260684Skaiwusage(void)
74260684Skaiw{
75260684Skaiw	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
76260684Skaiw	exit(1);
77260684Skaiw}
78260684Skaiw
79260684Skaiwstatic void
80260684Skaiwversion(void)
81260684Skaiw{
82260684Skaiw
83260684Skaiw	fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
84260684Skaiw	exit(0);
85260684Skaiw}
86260684Skaiw
87282918Semaste/*
88282918Semaste * Handle DWARF 4 'offset from' DW_AT_high_pc.  Although we don't
89282918Semaste * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1)
90282918Semaste * generate DW_AT_high_pc as an offset from DW_AT_low_pc.
91282918Semaste *
92282918Semaste * "If the value of the DW_AT_high_pc is of class address, it is the
93282918Semaste * relocated address of the first location past the last instruction
94282918Semaste * associated with the entity; if it is of class constant, the value
95282918Semaste * is an unsigned integer offset which when added to the low PC gives
96282918Semaste * the address of the first location past the last instruction
97282918Semaste * associated with the entity."
98282918Semaste *
99282918Semaste * DWARF4 spec, section 2.17.2.
100282918Semaste */
101282918Semastestatic int
102282918Semastehandle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc)
103282918Semaste{
104282918Semaste	Dwarf_Error de;
105282918Semaste	Dwarf_Half form;
106282918Semaste	Dwarf_Attribute at;
107282918Semaste	int ret;
108282918Semaste
109282918Semaste	ret = dwarf_attr(die, DW_AT_high_pc, &at, &de);
110282918Semaste	if (ret == DW_DLV_ERROR) {
111282918Semaste		warnx("dwarf_attr failed: %s", dwarf_errmsg(de));
112282918Semaste		return (ret);
113282918Semaste	}
114282918Semaste	ret = dwarf_whatform(at, &form, &de);
115282918Semaste	if (ret == DW_DLV_ERROR) {
116282918Semaste		warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));
117282918Semaste		return (ret);
118282918Semaste	}
119282918Semaste	if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT)
120282918Semaste		*hipc += lopc;
121282918Semaste
122282918Semaste	return (DW_DLV_OK);
123282918Semaste}
124282918Semaste
125260684Skaiwstatic void
126289071Semastesearch_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr, char **rlt_func)
127260684Skaiw{
128260684Skaiw	Dwarf_Die ret_die, spec_die;
129260684Skaiw	Dwarf_Error de;
130260684Skaiw	Dwarf_Half tag;
131260684Skaiw	Dwarf_Unsigned lopc, hipc;
132260684Skaiw	Dwarf_Off ref;
133260684Skaiw	Dwarf_Attribute sub_at, spec_at;
134260684Skaiw	char *func0;
135289071Semaste	const char *func1;
136260684Skaiw	int ret;
137260684Skaiw
138260684Skaiw	if (*rlt_func != NULL)
139289071Semaste		goto done;
140260684Skaiw
141260684Skaiw	if (dwarf_tag(die, &tag, &de)) {
142260684Skaiw		warnx("dwarf_tag: %s", dwarf_errmsg(de));
143260684Skaiw		goto cont_search;
144260684Skaiw	}
145260684Skaiw	if (tag == DW_TAG_subprogram) {
146260684Skaiw		if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
147260684Skaiw		    dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
148260684Skaiw			goto cont_search;
149282918Semaste		if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK)
150282918Semaste			goto cont_search;
151260684Skaiw		if (addr < lopc || addr >= hipc)
152260684Skaiw			goto cont_search;
153260684Skaiw
154260684Skaiw		/* Found it! */
155260684Skaiw
156289071Semaste		if ((*rlt_func = strdup(unknown)) == NULL)
157289071Semaste			err(EXIT_FAILURE, "strdup");
158260684Skaiw		ret = dwarf_attr(die, DW_AT_name, &sub_at, &de);
159260684Skaiw		if (ret == DW_DLV_ERROR)
160289071Semaste			goto done;
161260684Skaiw		if (ret == DW_DLV_OK) {
162289071Semaste			if (dwarf_formstring(sub_at, &func0, &de) ==
163289071Semaste			    DW_DLV_OK) {
164289071Semaste				free(*rlt_func);
165289071Semaste				if ((*rlt_func = strdup(func0)) == NULL)
166289071Semaste					err(EXIT_FAILURE, "strdup");
167289071Semaste			}
168289071Semaste			goto done;
169260684Skaiw		}
170260684Skaiw
171260684Skaiw		/*
172260684Skaiw		 * If DW_AT_name is not present, but DW_AT_specification is
173260684Skaiw		 * present, then probably the actual name is in the DIE
174260684Skaiw		 * referenced by DW_AT_specification.
175260684Skaiw		 */
176260684Skaiw		if (dwarf_attr(die, DW_AT_specification, &spec_at, &de))
177289071Semaste			goto done;
178260684Skaiw		if (dwarf_global_formref(spec_at, &ref, &de))
179289071Semaste			goto done;
180260684Skaiw		if (dwarf_offdie(dbg, ref, &spec_die, &de))
181289071Semaste			goto done;
182289071Semaste		if (dwarf_attrval_string(spec_die, DW_AT_name, &func1, &de) ==
183289071Semaste		    DW_DLV_OK) {
184289071Semaste			free(*rlt_func);
185289071Semaste			if ((*rlt_func = strdup(func1)) == NULL)
186289071Semaste			    err(EXIT_FAILURE, "strdup");
187289071Semaste		}
188260684Skaiw
189289071Semaste		goto done;
190260684Skaiw	}
191260684Skaiw
192260684Skaiwcont_search:
193260684Skaiw
194260684Skaiw	/* Search children. */
195260684Skaiw	ret = dwarf_child(die, &ret_die, &de);
196260684Skaiw	if (ret == DW_DLV_ERROR)
197260684Skaiw		errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de));
198260684Skaiw	else if (ret == DW_DLV_OK)
199260684Skaiw		search_func(dbg, ret_die, addr, rlt_func);
200260684Skaiw
201260684Skaiw	/* Search sibling. */
202260684Skaiw	ret = dwarf_siblingof(dbg, die, &ret_die, &de);
203260684Skaiw	if (ret == DW_DLV_ERROR)
204260684Skaiw		errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de));
205260684Skaiw	else if (ret == DW_DLV_OK)
206260684Skaiw		search_func(dbg, ret_die, addr, rlt_func);
207289071Semaste
208289071Semastedone:
209289071Semaste	dwarf_dealloc(dbg, die, DW_DLA_DIE);
210260684Skaiw}
211260684Skaiw
212260684Skaiwstatic void
213260684Skaiwtranslate(Dwarf_Debug dbg, const char* addrstr)
214260684Skaiw{
215289071Semaste	Dwarf_Die die, ret_die;
216260684Skaiw	Dwarf_Line *lbuf;
217260684Skaiw	Dwarf_Error de;
218260684Skaiw	Dwarf_Half tag;
219260684Skaiw	Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
220260684Skaiw	Dwarf_Signed lcount;
221260684Skaiw	Dwarf_Addr lineaddr, plineaddr;
222289071Semaste	char *funcname;
223260684Skaiw	char *file, *file0, *pfile;
224260684Skaiw	char demangled[1024];
225260684Skaiw	int i, ret;
226260684Skaiw
227260684Skaiw	addr = strtoull(addrstr, NULL, 16);
228260684Skaiw	addr += section_base;
229260684Skaiw	lineno = 0;
230260684Skaiw	file = unknown;
231289074Semaste	die = NULL;
232289071Semaste	lbuf = NULL;
233289071Semaste	lcount = 0;
234260684Skaiw
235260684Skaiw	while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
236260684Skaiw	    &de)) ==  DW_DLV_OK) {
237260684Skaiw		die = NULL;
238289071Semaste		while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) {
239289071Semaste			if (die != NULL)
240289071Semaste				dwarf_dealloc(dbg, die, DW_DLA_DIE);
241289071Semaste			die = ret_die;
242260684Skaiw			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
243260684Skaiw				warnx("dwarf_tag failed: %s",
244260684Skaiw				    dwarf_errmsg(de));
245289071Semaste				goto next_cu;
246260684Skaiw			}
247289071Semaste
248260684Skaiw			/* XXX: What about DW_TAG_partial_unit? */
249260684Skaiw			if (tag == DW_TAG_compile_unit)
250260684Skaiw				break;
251260684Skaiw		}
252289071Semaste		if (ret_die == NULL) {
253260684Skaiw			warnx("could not find DW_TAG_compile_unit die");
254289071Semaste			goto next_cu;
255260684Skaiw		}
256260684Skaiw		if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
257260684Skaiw		    !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
258260684Skaiw			/*
259260684Skaiw			 * Check if the address falls into the PC range of
260260684Skaiw			 * this CU.
261260684Skaiw			 */
262282918Semaste			if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK)
263289071Semaste				goto next_cu;
264260684Skaiw			if (addr < lopc || addr >= hipc)
265289071Semaste				goto next_cu;
266260684Skaiw		}
267260684Skaiw
268288119Semaste		switch (dwarf_srclines(die, &lbuf, &lcount, &de)) {
269288119Semaste		case DW_DLV_OK:
270288119Semaste			break;
271288119Semaste		case DW_DLV_NO_ENTRY:
272289071Semaste			/* If a CU lacks debug info, just skip it. */
273289071Semaste			goto next_cu;
274288119Semaste		default:
275260684Skaiw			warnx("dwarf_srclines: %s", dwarf_errmsg(de));
276260684Skaiw			goto out;
277260684Skaiw		}
278260684Skaiw
279260684Skaiw		plineaddr = ~0ULL;
280260684Skaiw		plineno = 0;
281260684Skaiw		pfile = unknown;
282260684Skaiw		for (i = 0; i < lcount; i++) {
283260684Skaiw			if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
284260684Skaiw				warnx("dwarf_lineaddr: %s",
285260684Skaiw				    dwarf_errmsg(de));
286260684Skaiw				goto out;
287260684Skaiw			}
288260684Skaiw			if (dwarf_lineno(lbuf[i], &lineno, &de)) {
289260684Skaiw				warnx("dwarf_lineno: %s",
290260684Skaiw				    dwarf_errmsg(de));
291260684Skaiw				goto out;
292260684Skaiw			}
293260684Skaiw			if (dwarf_linesrc(lbuf[i], &file0, &de)) {
294260684Skaiw				warnx("dwarf_linesrc: %s",
295260684Skaiw				    dwarf_errmsg(de));
296260684Skaiw			} else
297260684Skaiw				file = file0;
298260684Skaiw			if (addr == lineaddr)
299260684Skaiw				goto out;
300260684Skaiw			else if (addr < lineaddr && addr > plineaddr) {
301260684Skaiw				lineno = plineno;
302260684Skaiw				file = pfile;
303260684Skaiw				goto out;
304260684Skaiw			}
305260684Skaiw			plineaddr = lineaddr;
306260684Skaiw			plineno = lineno;
307260684Skaiw			pfile = file;
308260684Skaiw		}
309289071Semaste	next_cu:
310289071Semaste		if (die != NULL) {
311289071Semaste			dwarf_dealloc(dbg, die, DW_DLA_DIE);
312289071Semaste			die = NULL;
313289071Semaste		}
314260684Skaiw	}
315260684Skaiw
316260684Skaiwout:
317260684Skaiw	funcname = NULL;
318289071Semaste	if (ret == DW_DLV_OK && func) {
319260684Skaiw		search_func(dbg, die, addr, &funcname);
320289071Semaste		die = NULL;
321289071Semaste	}
322260684Skaiw
323260684Skaiw	if (func) {
324260684Skaiw		if (funcname == NULL)
325289071Semaste			if ((funcname = strdup(unknown)) == NULL)
326289071Semaste				err(EXIT_FAILURE, "strdup");
327260684Skaiw		if (demangle &&
328260684Skaiw		    !elftc_demangle(funcname, demangled, sizeof(demangled), 0))
329260684Skaiw			printf("%s\n", demangled);
330260684Skaiw		else
331260684Skaiw			printf("%s\n", funcname);
332289071Semaste		free(funcname);
333260684Skaiw	}
334260684Skaiw
335260684Skaiw	(void) printf("%s:%ju\n", base ? basename(file) : file, lineno);
336260684Skaiw
337289071Semaste	if (die != NULL)
338289071Semaste		dwarf_dealloc(dbg, die, DW_DLA_DIE);
339289071Semaste
340260684Skaiw	/*
341260684Skaiw	 * Reset internal CU pointer, so we will start from the first CU
342260684Skaiw	 * next round.
343260684Skaiw	 */
344260684Skaiw	while (ret != DW_DLV_NO_ENTRY) {
345260684Skaiw		if (ret == DW_DLV_ERROR)
346260684Skaiw			errx(EXIT_FAILURE, "dwarf_next_cu_header: %s",
347260684Skaiw			    dwarf_errmsg(de));
348260684Skaiw		ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
349260684Skaiw		    &de);
350260684Skaiw	}
351260684Skaiw}
352260684Skaiw
353260684Skaiwstatic void
354260684Skaiwfind_section_base(const char *exe, Elf *e, const char *section)
355260684Skaiw{
356260684Skaiw	Dwarf_Addr off;
357260684Skaiw	Elf_Scn *scn;
358260684Skaiw	GElf_Ehdr eh;
359260684Skaiw	GElf_Shdr sh;
360260684Skaiw	size_t shstrndx;
361260684Skaiw	int elferr;
362260684Skaiw	const char *name;
363260684Skaiw
364260684Skaiw	if (gelf_getehdr(e, &eh) != &eh) {
365260684Skaiw		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
366260684Skaiw		return;
367260684Skaiw	}
368260684Skaiw
369260684Skaiw	if (!elf_getshstrndx(e, &shstrndx)) {
370260684Skaiw		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
371260684Skaiw		return;
372260684Skaiw	}
373260684Skaiw
374260684Skaiw	(void) elf_errno();
375260684Skaiw	off = 0;
376260684Skaiw	scn = NULL;
377260684Skaiw	while ((scn = elf_nextscn(e, scn)) != NULL) {
378260684Skaiw		if (gelf_getshdr(scn, &sh) == NULL) {
379260684Skaiw			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
380260684Skaiw			continue;
381260684Skaiw		}
382260684Skaiw		if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
383260684Skaiw			goto next;
384260684Skaiw		if (!strcmp(section, name)) {
385260684Skaiw			if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
386260684Skaiw				/*
387260684Skaiw				 * For executables, section base is the virtual
388260684Skaiw				 * address of the specified section.
389260684Skaiw				 */
390260684Skaiw				section_base = sh.sh_addr;
391260684Skaiw			} else if (eh.e_type == ET_REL) {
392260684Skaiw				/*
393260684Skaiw				 * For relocatables, section base is the
394260684Skaiw				 * relative offset of the specified section
395260684Skaiw				 * to the start of the first section.
396260684Skaiw				 */
397260684Skaiw				section_base = off;
398260684Skaiw			} else
399260684Skaiw				warnx("unknown e_type %u", eh.e_type);
400260684Skaiw			return;
401260684Skaiw		}
402260684Skaiw	next:
403260684Skaiw		off += sh.sh_size;
404260684Skaiw	}
405260684Skaiw	elferr = elf_errno();
406260684Skaiw	if (elferr != 0)
407260684Skaiw		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
408260684Skaiw
409260684Skaiw	errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
410260684Skaiw}
411260684Skaiw
412260684Skaiwint
413260684Skaiwmain(int argc, char **argv)
414260684Skaiw{
415260684Skaiw	Elf *e;
416260684Skaiw	Dwarf_Debug dbg;
417260684Skaiw	Dwarf_Error de;
418260684Skaiw	const char *exe, *section;
419260684Skaiw	char line[1024];
420260684Skaiw	int fd, i, opt;
421260684Skaiw
422260684Skaiw	exe = NULL;
423260684Skaiw	section = NULL;
424260684Skaiw	while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) !=
425260684Skaiw	    -1) {
426260684Skaiw		switch (opt) {
427260684Skaiw		case 'b':
428260684Skaiw			/* ignored */
429260684Skaiw			break;
430260684Skaiw		case 'C':
431260684Skaiw			demangle = 1;
432260684Skaiw			break;
433260684Skaiw		case 'e':
434260684Skaiw			exe = optarg;
435260684Skaiw			break;
436260684Skaiw		case 'f':
437260684Skaiw			func = 1;
438260684Skaiw			break;
439260684Skaiw		case 'j':
440260684Skaiw			section = optarg;
441260684Skaiw			break;
442260684Skaiw		case 's':
443260684Skaiw			base = 1;
444260684Skaiw			break;
445260684Skaiw		case 'H':
446260684Skaiw			usage();
447260684Skaiw		case 'V':
448260684Skaiw			version();
449260684Skaiw		default:
450260684Skaiw			usage();
451260684Skaiw		}
452260684Skaiw	}
453260684Skaiw
454260684Skaiw	argv += optind;
455260684Skaiw	argc -= optind;
456260684Skaiw
457260684Skaiw	if (exe == NULL)
458260684Skaiw		exe = "a.out";
459260684Skaiw
460260684Skaiw	if ((fd = open(exe, O_RDONLY)) < 0)
461260684Skaiw		err(EXIT_FAILURE, "%s", exe);
462260684Skaiw
463260684Skaiw	if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
464260684Skaiw		errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
465260684Skaiw
466260684Skaiw	if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
467260684Skaiw		errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
468260684Skaiw
469260684Skaiw	if (section)
470260684Skaiw		find_section_base(exe, e, section);
471260684Skaiw	else
472260684Skaiw		section_base = 0;
473260684Skaiw
474260684Skaiw	if (argc > 0)
475260684Skaiw		for (i = 0; i < argc; i++)
476260684Skaiw			translate(dbg, argv[i]);
477260684Skaiw	else
478276689Semaste		while (fgets(line, sizeof(line), stdin) != NULL) {
479260684Skaiw			translate(dbg, line);
480276689Semaste			fflush(stdout);
481276689Semaste		}
482260684Skaiw
483260684Skaiw	dwarf_finish(dbg, &de);
484260684Skaiw
485260684Skaiw	(void) elf_end(e);
486260684Skaiw
487260684Skaiw	exit(0);
488260684Skaiw}
489