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