addr2line.c revision 260684
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/cdefs.h>
28260684Skaiw#include <sys/param.h>
29260684Skaiw#include <dwarf.h>
30260684Skaiw#include <err.h>
31260684Skaiw#include <fcntl.h>
32260684Skaiw#include <gelf.h>
33260684Skaiw#include <getopt.h>
34260684Skaiw#include <libdwarf.h>
35260684Skaiw#include <libelftc.h>
36260684Skaiw#include <libgen.h>
37260684Skaiw#include <stdio.h>
38260684Skaiw#include <stdlib.h>
39260684Skaiw#include <string.h>
40260684Skaiw
41260684Skaiw#include "_elftc.h"
42260684Skaiw
43260684SkaiwELFTC_VCSID("$Id: addr2line.c 2185 2011-11-19 16:07:16Z jkoshy $");
44260684Skaiw
45260684Skaiwstatic struct option longopts[] = {
46260684Skaiw	{"target" , required_argument, NULL, 'b'},
47260684Skaiw	{"demangle", no_argument, NULL, 'C'},
48260684Skaiw	{"exe", required_argument, NULL, 'e'},
49260684Skaiw	{"functions", no_argument, NULL, 'f'},
50260684Skaiw	{"section", required_argument, NULL, 'j'},
51260684Skaiw	{"basename", no_argument, NULL, 's'},
52260684Skaiw	{"help", no_argument, NULL, 'H'},
53260684Skaiw	{"version", no_argument, NULL, 'V'},
54260684Skaiw	{NULL, 0, NULL, 0}
55260684Skaiw};
56260684Skaiwstatic int demangle, func, base;
57260684Skaiwstatic char unknown[] = { '?', '?', '\0' };
58260684Skaiwstatic Dwarf_Addr section_base;
59260684Skaiw
60260684Skaiw#define	USAGE_MESSAGE	"\
61260684SkaiwUsage: %s [options] hexaddress...\n\
62260684Skaiw  Map program addresses to source file names and line numbers.\n\n\
63260684Skaiw  Options:\n\
64260684Skaiw  -b TGT  | --target=TGT      (Accepted but ignored).\n\
65260684Skaiw  -e EXE  | --exec=EXE        Use program \"EXE\" to translate addresses.\n\
66260684Skaiw  -f      | --functions       Display function names.\n\
67260684Skaiw  -j NAME | --section=NAME    Values are offsets into section \"NAME\".\n\
68260684Skaiw  -s      | --basename        Only show the base name for each file name.\n\
69260684Skaiw  -C      | --demangle        Demangle C++ names.\n\
70260684Skaiw  -H      | --help            Print a help message.\n\
71260684Skaiw  -V      | --version         Print a version identifier and exit.\n"
72260684Skaiw
73260684Skaiwstatic void
74260684Skaiwusage(void)
75260684Skaiw{
76260684Skaiw	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
77260684Skaiw	exit(1);
78260684Skaiw}
79260684Skaiw
80260684Skaiwstatic void
81260684Skaiwversion(void)
82260684Skaiw{
83260684Skaiw
84260684Skaiw	fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
85260684Skaiw	exit(0);
86260684Skaiw}
87260684Skaiw
88260684Skaiwstatic void
89260684Skaiwsearch_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr,
90260684Skaiw    const char **rlt_func)
91260684Skaiw{
92260684Skaiw	Dwarf_Die ret_die, spec_die;
93260684Skaiw	Dwarf_Error de;
94260684Skaiw	Dwarf_Half tag;
95260684Skaiw	Dwarf_Unsigned lopc, hipc;
96260684Skaiw	Dwarf_Off ref;
97260684Skaiw	Dwarf_Attribute sub_at, spec_at;
98260684Skaiw	char *func0;
99260684Skaiw	int ret;
100260684Skaiw
101260684Skaiw	if (*rlt_func != NULL)
102260684Skaiw		return;
103260684Skaiw
104260684Skaiw	if (dwarf_tag(die, &tag, &de)) {
105260684Skaiw		warnx("dwarf_tag: %s", dwarf_errmsg(de));
106260684Skaiw		goto cont_search;
107260684Skaiw	}
108260684Skaiw	if (tag == DW_TAG_subprogram) {
109260684Skaiw		if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
110260684Skaiw		    dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
111260684Skaiw			goto cont_search;
112260684Skaiw		if (addr < lopc || addr >= hipc)
113260684Skaiw			goto cont_search;
114260684Skaiw
115260684Skaiw		/* Found it! */
116260684Skaiw
117260684Skaiw		*rlt_func = unknown;
118260684Skaiw		ret = dwarf_attr(die, DW_AT_name, &sub_at, &de);
119260684Skaiw		if (ret == DW_DLV_ERROR)
120260684Skaiw			return;
121260684Skaiw		if (ret == DW_DLV_OK) {
122260684Skaiw			if (dwarf_formstring(sub_at, &func0, &de))
123260684Skaiw				*rlt_func = unknown;
124260684Skaiw			else
125260684Skaiw				*rlt_func = func0;
126260684Skaiw			return;
127260684Skaiw		}
128260684Skaiw
129260684Skaiw		/*
130260684Skaiw		 * If DW_AT_name is not present, but DW_AT_specification is
131260684Skaiw		 * present, then probably the actual name is in the DIE
132260684Skaiw		 * referenced by DW_AT_specification.
133260684Skaiw		 */
134260684Skaiw		if (dwarf_attr(die, DW_AT_specification, &spec_at, &de))
135260684Skaiw			return;
136260684Skaiw		if (dwarf_global_formref(spec_at, &ref, &de))
137260684Skaiw			return;
138260684Skaiw		if (dwarf_offdie(dbg, ref, &spec_die, &de))
139260684Skaiw			return;
140260684Skaiw		if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de))
141260684Skaiw			*rlt_func = unknown;
142260684Skaiw
143260684Skaiw		return;
144260684Skaiw	}
145260684Skaiw
146260684Skaiwcont_search:
147260684Skaiw
148260684Skaiw	/* Search children. */
149260684Skaiw	ret = dwarf_child(die, &ret_die, &de);
150260684Skaiw	if (ret == DW_DLV_ERROR)
151260684Skaiw		errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de));
152260684Skaiw	else if (ret == DW_DLV_OK)
153260684Skaiw		search_func(dbg, ret_die, addr, rlt_func);
154260684Skaiw
155260684Skaiw	/* Search sibling. */
156260684Skaiw	ret = dwarf_siblingof(dbg, die, &ret_die, &de);
157260684Skaiw	if (ret == DW_DLV_ERROR)
158260684Skaiw		errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de));
159260684Skaiw	else if (ret == DW_DLV_OK)
160260684Skaiw		search_func(dbg, ret_die, addr, rlt_func);
161260684Skaiw}
162260684Skaiw
163260684Skaiwstatic void
164260684Skaiwtranslate(Dwarf_Debug dbg, const char* addrstr)
165260684Skaiw{
166260684Skaiw	Dwarf_Die die;
167260684Skaiw	Dwarf_Line *lbuf;
168260684Skaiw	Dwarf_Error de;
169260684Skaiw	Dwarf_Half tag;
170260684Skaiw	Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
171260684Skaiw	Dwarf_Signed lcount;
172260684Skaiw	Dwarf_Addr lineaddr, plineaddr;
173260684Skaiw	const char *funcname;
174260684Skaiw	char *file, *file0, *pfile;
175260684Skaiw	char demangled[1024];
176260684Skaiw	int i, ret;
177260684Skaiw
178260684Skaiw	addr = strtoull(addrstr, NULL, 16);
179260684Skaiw	addr += section_base;
180260684Skaiw	lineno = 0;
181260684Skaiw	file = unknown;
182260684Skaiw
183260684Skaiw	while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
184260684Skaiw	    &de)) ==  DW_DLV_OK) {
185260684Skaiw		die = NULL;
186260684Skaiw		while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
187260684Skaiw			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
188260684Skaiw				warnx("dwarf_tag failed: %s",
189260684Skaiw				    dwarf_errmsg(de));
190260684Skaiw				goto out;
191260684Skaiw			}
192260684Skaiw			/* XXX: What about DW_TAG_partial_unit? */
193260684Skaiw			if (tag == DW_TAG_compile_unit)
194260684Skaiw				break;
195260684Skaiw		}
196260684Skaiw		if (die == NULL) {
197260684Skaiw			warnx("could not find DW_TAG_compile_unit die");
198260684Skaiw			goto out;
199260684Skaiw		}
200260684Skaiw		if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
201260684Skaiw		    !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
202260684Skaiw			/*
203260684Skaiw			 * Check if the address falls into the PC range of
204260684Skaiw			 * this CU.
205260684Skaiw			 */
206260684Skaiw			if (addr < lopc || addr >= hipc)
207260684Skaiw				continue;
208260684Skaiw		}
209260684Skaiw
210260684Skaiw		if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) {
211260684Skaiw			warnx("dwarf_srclines: %s", dwarf_errmsg(de));
212260684Skaiw			goto out;
213260684Skaiw		}
214260684Skaiw
215260684Skaiw		plineaddr = ~0ULL;
216260684Skaiw		plineno = 0;
217260684Skaiw		pfile = unknown;
218260684Skaiw		for (i = 0; i < lcount; i++) {
219260684Skaiw			if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
220260684Skaiw				warnx("dwarf_lineaddr: %s",
221260684Skaiw				    dwarf_errmsg(de));
222260684Skaiw				goto out;
223260684Skaiw			}
224260684Skaiw			if (dwarf_lineno(lbuf[i], &lineno, &de)) {
225260684Skaiw				warnx("dwarf_lineno: %s",
226260684Skaiw				    dwarf_errmsg(de));
227260684Skaiw				goto out;
228260684Skaiw			}
229260684Skaiw			if (dwarf_linesrc(lbuf[i], &file0, &de)) {
230260684Skaiw				warnx("dwarf_linesrc: %s",
231260684Skaiw				    dwarf_errmsg(de));
232260684Skaiw			} else
233260684Skaiw				file = file0;
234260684Skaiw			if (addr == lineaddr)
235260684Skaiw				goto out;
236260684Skaiw			else if (addr < lineaddr && addr > plineaddr) {
237260684Skaiw				lineno = plineno;
238260684Skaiw				file = pfile;
239260684Skaiw				goto out;
240260684Skaiw			}
241260684Skaiw			plineaddr = lineaddr;
242260684Skaiw			plineno = lineno;
243260684Skaiw			pfile = file;
244260684Skaiw		}
245260684Skaiw	}
246260684Skaiw
247260684Skaiwout:
248260684Skaiw	funcname = NULL;
249260684Skaiw	if (ret == DW_DLV_OK && func)
250260684Skaiw		search_func(dbg, die, addr, &funcname);
251260684Skaiw
252260684Skaiw	if (func) {
253260684Skaiw		if (funcname == NULL)
254260684Skaiw			funcname = unknown;
255260684Skaiw		if (demangle &&
256260684Skaiw		    !elftc_demangle(funcname, demangled, sizeof(demangled), 0))
257260684Skaiw			printf("%s\n", demangled);
258260684Skaiw		else
259260684Skaiw			printf("%s\n", funcname);
260260684Skaiw	}
261260684Skaiw
262260684Skaiw	(void) printf("%s:%ju\n", base ? basename(file) : file, lineno);
263260684Skaiw
264260684Skaiw	/*
265260684Skaiw	 * Reset internal CU pointer, so we will start from the first CU
266260684Skaiw	 * next round.
267260684Skaiw	 */
268260684Skaiw	while (ret != DW_DLV_NO_ENTRY) {
269260684Skaiw		if (ret == DW_DLV_ERROR)
270260684Skaiw			errx(EXIT_FAILURE, "dwarf_next_cu_header: %s",
271260684Skaiw			    dwarf_errmsg(de));
272260684Skaiw		ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
273260684Skaiw		    &de);
274260684Skaiw	}
275260684Skaiw}
276260684Skaiw
277260684Skaiwstatic void
278260684Skaiwfind_section_base(const char *exe, Elf *e, const char *section)
279260684Skaiw{
280260684Skaiw	Dwarf_Addr off;
281260684Skaiw	Elf_Scn *scn;
282260684Skaiw	GElf_Ehdr eh;
283260684Skaiw	GElf_Shdr sh;
284260684Skaiw	size_t shstrndx;
285260684Skaiw	int elferr;
286260684Skaiw	const char *name;
287260684Skaiw
288260684Skaiw	if (gelf_getehdr(e, &eh) != &eh) {
289260684Skaiw		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
290260684Skaiw		return;
291260684Skaiw	}
292260684Skaiw
293260684Skaiw	if (!elf_getshstrndx(e, &shstrndx)) {
294260684Skaiw		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
295260684Skaiw		return;
296260684Skaiw	}
297260684Skaiw
298260684Skaiw	(void) elf_errno();
299260684Skaiw	off = 0;
300260684Skaiw	scn = NULL;
301260684Skaiw	while ((scn = elf_nextscn(e, scn)) != NULL) {
302260684Skaiw		if (gelf_getshdr(scn, &sh) == NULL) {
303260684Skaiw			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
304260684Skaiw			continue;
305260684Skaiw		}
306260684Skaiw		if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
307260684Skaiw			goto next;
308260684Skaiw		if (!strcmp(section, name)) {
309260684Skaiw			if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
310260684Skaiw				/*
311260684Skaiw				 * For executables, section base is the virtual
312260684Skaiw				 * address of the specified section.
313260684Skaiw				 */
314260684Skaiw				section_base = sh.sh_addr;
315260684Skaiw			} else if (eh.e_type == ET_REL) {
316260684Skaiw				/*
317260684Skaiw				 * For relocatables, section base is the
318260684Skaiw				 * relative offset of the specified section
319260684Skaiw				 * to the start of the first section.
320260684Skaiw				 */
321260684Skaiw				section_base = off;
322260684Skaiw			} else
323260684Skaiw				warnx("unknown e_type %u", eh.e_type);
324260684Skaiw			return;
325260684Skaiw		}
326260684Skaiw	next:
327260684Skaiw		off += sh.sh_size;
328260684Skaiw	}
329260684Skaiw	elferr = elf_errno();
330260684Skaiw	if (elferr != 0)
331260684Skaiw		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
332260684Skaiw
333260684Skaiw	errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
334260684Skaiw}
335260684Skaiw
336260684Skaiwint
337260684Skaiwmain(int argc, char **argv)
338260684Skaiw{
339260684Skaiw	Elf *e;
340260684Skaiw	Dwarf_Debug dbg;
341260684Skaiw	Dwarf_Error de;
342260684Skaiw	const char *exe, *section;
343260684Skaiw	char line[1024];
344260684Skaiw	int fd, i, opt;
345260684Skaiw
346260684Skaiw	exe = NULL;
347260684Skaiw	section = NULL;
348260684Skaiw	while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) !=
349260684Skaiw	    -1) {
350260684Skaiw		switch (opt) {
351260684Skaiw		case 'b':
352260684Skaiw			/* ignored */
353260684Skaiw			break;
354260684Skaiw		case 'C':
355260684Skaiw			demangle = 1;
356260684Skaiw			break;
357260684Skaiw		case 'e':
358260684Skaiw			exe = optarg;
359260684Skaiw			break;
360260684Skaiw		case 'f':
361260684Skaiw			func = 1;
362260684Skaiw			break;
363260684Skaiw		case 'j':
364260684Skaiw			section = optarg;
365260684Skaiw			break;
366260684Skaiw		case 's':
367260684Skaiw			base = 1;
368260684Skaiw			break;
369260684Skaiw		case 'H':
370260684Skaiw			usage();
371260684Skaiw		case 'V':
372260684Skaiw			version();
373260684Skaiw		default:
374260684Skaiw			usage();
375260684Skaiw		}
376260684Skaiw	}
377260684Skaiw
378260684Skaiw	argv += optind;
379260684Skaiw	argc -= optind;
380260684Skaiw
381260684Skaiw	if (exe == NULL)
382260684Skaiw		exe = "a.out";
383260684Skaiw
384260684Skaiw	if ((fd = open(exe, O_RDONLY)) < 0)
385260684Skaiw		err(EXIT_FAILURE, "%s", exe);
386260684Skaiw
387260684Skaiw	if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
388260684Skaiw		errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
389260684Skaiw
390260684Skaiw	if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
391260684Skaiw		errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
392260684Skaiw
393260684Skaiw	if (section)
394260684Skaiw		find_section_base(exe, e, section);
395260684Skaiw	else
396260684Skaiw		section_base = 0;
397260684Skaiw
398260684Skaiw	if (argc > 0)
399260684Skaiw		for (i = 0; i < argc; i++)
400260684Skaiw			translate(dbg, argv[i]);
401260684Skaiw	else
402260684Skaiw		while (fgets(line, sizeof(line), stdin) != NULL)
403260684Skaiw			translate(dbg, line);
404260684Skaiw
405260684Skaiw	dwarf_finish(dbg, &de);
406260684Skaiw
407260684Skaiw	(void) elf_end(e);
408260684Skaiw
409260684Skaiw	exit(0);
410260684Skaiw}
411