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>
28367466Sdim#include <sys/tree.h>
29367466Sdim
30260684Skaiw#include <dwarf.h>
31260684Skaiw#include <err.h>
32260684Skaiw#include <fcntl.h>
33260684Skaiw#include <gelf.h>
34260684Skaiw#include <getopt.h>
35260684Skaiw#include <libdwarf.h>
36260684Skaiw#include <libelftc.h>
37260684Skaiw#include <libgen.h>
38367466Sdim#include <stdbool.h>
39260684Skaiw#include <stdio.h>
40260684Skaiw#include <stdlib.h>
41260684Skaiw#include <string.h>
42260684Skaiw
43260684Skaiw#include "_elftc.h"
44260684Skaiw
45317623SemasteELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $");
46260684Skaiw
47292120Semastestruct Func {
48292120Semaste	char *name;
49292120Semaste	Dwarf_Unsigned lopc;
50292120Semaste	Dwarf_Unsigned hipc;
51292120Semaste	Dwarf_Unsigned call_file;
52292120Semaste	Dwarf_Unsigned call_line;
53292120Semaste	Dwarf_Ranges *ranges;
54292120Semaste	Dwarf_Signed ranges_cnt;
55292120Semaste	struct Func *inlined_caller;
56292120Semaste	STAILQ_ENTRY(Func) next;
57292120Semaste};
58292120Semaste
59292120Semastestruct CU {
60367466Sdim	RB_ENTRY(CU) entry;
61292120Semaste	Dwarf_Off off;
62292120Semaste	Dwarf_Unsigned lopc;
63292120Semaste	Dwarf_Unsigned hipc;
64292120Semaste	char **srcfiles;
65292120Semaste	Dwarf_Signed nsrcfiles;
66292120Semaste	STAILQ_HEAD(, Func) funclist;
67367466Sdim	Dwarf_Die die;
68367466Sdim	Dwarf_Debug dbg;
69292120Semaste};
70292120Semaste
71260684Skaiwstatic struct option longopts[] = {
72292120Semaste	{"addresses", no_argument, NULL, 'a'},
73260684Skaiw	{"target" , required_argument, NULL, 'b'},
74260684Skaiw	{"demangle", no_argument, NULL, 'C'},
75260684Skaiw	{"exe", required_argument, NULL, 'e'},
76260684Skaiw	{"functions", no_argument, NULL, 'f'},
77292120Semaste	{"inlines", no_argument, NULL, 'i'},
78260684Skaiw	{"section", required_argument, NULL, 'j'},
79292120Semaste	{"pretty-print", no_argument, NULL, 'p'},
80260684Skaiw	{"basename", no_argument, NULL, 's'},
81260684Skaiw	{"help", no_argument, NULL, 'H'},
82260684Skaiw	{"version", no_argument, NULL, 'V'},
83260684Skaiw	{NULL, 0, NULL, 0}
84260684Skaiw};
85367466Sdim
86292120Semastestatic int demangle, func, base, inlines, print_addr, pretty_print;
87260684Skaiwstatic char unknown[] = { '?', '?', '\0' };
88260684Skaiwstatic Dwarf_Addr section_base;
89367466Sdim/* Need a new curlopc that stores last lopc value. */
90367466Sdimstatic Dwarf_Unsigned curlopc = ~0ULL;
91367466Sdimstatic RB_HEAD(cutree, CU) cuhead = RB_INITIALIZER(&cuhead);
92260684Skaiw
93367466Sdimstatic int
94367466Sdimlopccmp(struct CU *e1, struct CU *e2)
95367466Sdim{
96367466Sdim	return (e1->lopc < e2->lopc ? -1 : e1->lopc > e2->lopc);
97367466Sdim}
98367466Sdim
99367466SdimRB_PROTOTYPE(cutree, CU, entry, lopccmp);
100367466SdimRB_GENERATE(cutree, CU, entry, lopccmp)
101367466Sdim
102260684Skaiw#define	USAGE_MESSAGE	"\
103260684SkaiwUsage: %s [options] hexaddress...\n\
104260684Skaiw  Map program addresses to source file names and line numbers.\n\n\
105260684Skaiw  Options:\n\
106292120Semaste  -a      | --addresses       Display address prior to line number info.\n\
107260684Skaiw  -b TGT  | --target=TGT      (Accepted but ignored).\n\
108289071Semaste  -e EXE  | --exe=EXE         Use program \"EXE\" to translate addresses.\n\
109260684Skaiw  -f      | --functions       Display function names.\n\
110292120Semaste  -i      | --inlines         Display caller info for inlined functions.\n\
111260684Skaiw  -j NAME | --section=NAME    Values are offsets into section \"NAME\".\n\
112292120Semaste  -p      | --pretty-print    Display line number info and function name\n\
113292120Semaste                              in human readable manner.\n\
114260684Skaiw  -s      | --basename        Only show the base name for each file name.\n\
115260684Skaiw  -C      | --demangle        Demangle C++ names.\n\
116260684Skaiw  -H      | --help            Print a help message.\n\
117260684Skaiw  -V      | --version         Print a version identifier and exit.\n"
118260684Skaiw
119260684Skaiwstatic void
120260684Skaiwusage(void)
121260684Skaiw{
122260684Skaiw	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
123260684Skaiw	exit(1);
124260684Skaiw}
125260684Skaiw
126260684Skaiwstatic void
127260684Skaiwversion(void)
128260684Skaiw{
129260684Skaiw
130260684Skaiw	fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
131260684Skaiw	exit(0);
132260684Skaiw}
133260684Skaiw
134282918Semaste/*
135282918Semaste * Handle DWARF 4 'offset from' DW_AT_high_pc.  Although we don't
136282918Semaste * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1)
137282918Semaste * generate DW_AT_high_pc as an offset from DW_AT_low_pc.
138282918Semaste *
139282918Semaste * "If the value of the DW_AT_high_pc is of class address, it is the
140282918Semaste * relocated address of the first location past the last instruction
141282918Semaste * associated with the entity; if it is of class constant, the value
142282918Semaste * is an unsigned integer offset which when added to the low PC gives
143282918Semaste * the address of the first location past the last instruction
144282918Semaste * associated with the entity."
145282918Semaste *
146282918Semaste * DWARF4 spec, section 2.17.2.
147282918Semaste */
148282918Semastestatic int
149282918Semastehandle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc)
150282918Semaste{
151282918Semaste	Dwarf_Error de;
152282918Semaste	Dwarf_Half form;
153282918Semaste	Dwarf_Attribute at;
154282918Semaste	int ret;
155282918Semaste
156282918Semaste	ret = dwarf_attr(die, DW_AT_high_pc, &at, &de);
157282918Semaste	if (ret == DW_DLV_ERROR) {
158282918Semaste		warnx("dwarf_attr failed: %s", dwarf_errmsg(de));
159282918Semaste		return (ret);
160282918Semaste	}
161282918Semaste	ret = dwarf_whatform(at, &form, &de);
162282918Semaste	if (ret == DW_DLV_ERROR) {
163282918Semaste		warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));
164282918Semaste		return (ret);
165282918Semaste	}
166282918Semaste	if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT)
167282918Semaste		*hipc += lopc;
168282918Semaste
169282918Semaste	return (DW_DLV_OK);
170282918Semaste}
171282918Semaste
172292120Semastestatic struct Func *
173292120Semastesearch_func(struct CU *cu, Dwarf_Unsigned addr)
174292120Semaste{
175292120Semaste	struct Func *f, *f0;
176292120Semaste	Dwarf_Unsigned lopc, hipc, addr_base;
177292120Semaste	int i;
178292120Semaste
179292120Semaste	f0 = NULL;
180292120Semaste
181292120Semaste	STAILQ_FOREACH(f, &cu->funclist, next) {
182292120Semaste		if (f->ranges != NULL) {
183292120Semaste			addr_base = 0;
184292120Semaste			for (i = 0; i < f->ranges_cnt; i++) {
185292120Semaste				if (f->ranges[i].dwr_type == DW_RANGES_END)
186292120Semaste					break;
187292120Semaste				if (f->ranges[i].dwr_type ==
188292120Semaste				    DW_RANGES_ADDRESS_SELECTION) {
189292120Semaste					addr_base = f->ranges[i].dwr_addr2;
190292120Semaste					continue;
191292120Semaste				}
192292120Semaste
193292120Semaste				/* DW_RANGES_ENTRY */
194292120Semaste				lopc = f->ranges[i].dwr_addr1 + addr_base;
195292120Semaste				hipc = f->ranges[i].dwr_addr2 + addr_base;
196292120Semaste				if (addr >= lopc && addr < hipc) {
197292120Semaste					if (f0 == NULL ||
198292120Semaste					    (lopc >= f0->lopc &&
199292120Semaste					    hipc <= f0->hipc)) {
200292120Semaste						f0 = f;
201292120Semaste						f0->lopc = lopc;
202292120Semaste						f0->hipc = hipc;
203292120Semaste						break;
204292120Semaste					}
205292120Semaste				}
206292120Semaste			}
207292120Semaste		} else if (addr >= f->lopc && addr < f->hipc) {
208292120Semaste			if (f0 == NULL ||
209292120Semaste			    (f->lopc >= f0->lopc && f->hipc <= f0->hipc))
210292120Semaste				f0 = f;
211292120Semaste		}
212292120Semaste	}
213292120Semaste
214292120Semaste	return (f0);
215292120Semaste}
216292120Semaste
217260684Skaiwstatic void
218292120Semastecollect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu)
219260684Skaiw{
220292120Semaste	Dwarf_Die ret_die, abst_die, spec_die;
221260684Skaiw	Dwarf_Error de;
222260684Skaiw	Dwarf_Half tag;
223292120Semaste	Dwarf_Unsigned lopc, hipc, ranges_off;
224292120Semaste	Dwarf_Signed ranges_cnt;
225260684Skaiw	Dwarf_Off ref;
226292120Semaste	Dwarf_Attribute abst_at, spec_at;
227292120Semaste	Dwarf_Ranges *ranges;
228292120Semaste	const char *funcname;
229292120Semaste	struct Func *f;
230292120Semaste	int found_ranges, ret;
231260684Skaiw
232292120Semaste	f = NULL;
233292120Semaste	abst_die = spec_die = NULL;
234260684Skaiw
235260684Skaiw	if (dwarf_tag(die, &tag, &de)) {
236260684Skaiw		warnx("dwarf_tag: %s", dwarf_errmsg(de));
237260684Skaiw		goto cont_search;
238260684Skaiw	}
239292120Semaste	if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point ||
240292120Semaste	    tag == DW_TAG_inlined_subroutine) {
241292120Semaste		/*
242292120Semaste		 * Function address range can be specified by either
243292120Semaste		 * a DW_AT_ranges attribute which points to a range list or
244292120Semaste		 * by a pair of DW_AT_low_pc and DW_AT_high_pc attributes.
245292120Semaste		 */
246292120Semaste		ranges = NULL;
247292120Semaste		ranges_cnt = 0;
248292120Semaste		found_ranges = 0;
249292120Semaste		if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off,
250292120Semaste		    &de) == DW_DLV_OK &&
251292120Semaste		    dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges,
252292120Semaste		    &ranges_cnt, NULL, &de) == DW_DLV_OK) {
253292120Semaste			if (ranges != NULL && ranges_cnt > 0) {
254292120Semaste				found_ranges = 1;
255292120Semaste				goto get_func_name;
256292120Semaste			}
257292120Semaste		}
258292120Semaste
259292120Semaste		/*
260292120Semaste		 * Search for DW_AT_low_pc/DW_AT_high_pc if ranges pointer
261292120Semaste		 * not found.
262292120Semaste		 */
263260684Skaiw		if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
264260684Skaiw		    dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
265260684Skaiw			goto cont_search;
266282918Semaste		if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK)
267282918Semaste			goto cont_search;
268260684Skaiw
269292120Semaste	get_func_name:
270292120Semaste		/*
271292120Semaste		 * Most common case the function name is stored in DW_AT_name
272292120Semaste		 * attribute.
273292120Semaste		 */
274292120Semaste		if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) ==
275292120Semaste		    DW_DLV_OK)
276292120Semaste			goto add_func;
277260684Skaiw
278292120Semaste		/*
279292120Semaste		 * For inlined function, the actual name is probably in the DIE
280292120Semaste		 * referenced by DW_AT_abstract_origin. (if present)
281292120Semaste		 */
282292120Semaste		if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) ==
283292120Semaste		    DW_DLV_OK &&
284292120Semaste		    dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK &&
285292120Semaste		    dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK &&
286292120Semaste		    dwarf_attrval_string(abst_die, DW_AT_name, &funcname,
287292120Semaste		    &de) == DW_DLV_OK)
288292120Semaste			goto add_func;
289260684Skaiw
290260684Skaiw		/*
291260684Skaiw		 * If DW_AT_name is not present, but DW_AT_specification is
292260684Skaiw		 * present, then probably the actual name is in the DIE
293260684Skaiw		 * referenced by DW_AT_specification.
294260684Skaiw		 */
295292120Semaste		if (dwarf_attr(die, DW_AT_specification, &spec_at, &de) ==
296292120Semaste		    DW_DLV_OK &&
297292120Semaste		    dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK &&
298292120Semaste		    dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK &&
299292120Semaste		    dwarf_attrval_string(spec_die, DW_AT_name, &funcname,
300292120Semaste		    &de) == DW_DLV_OK)
301292120Semaste			goto add_func;
302292120Semaste
303300311Semaste		/* Skip if no name associated with this DIE. */
304292120Semaste		goto cont_search;
305292120Semaste
306292120Semaste	add_func:
307292120Semaste		if ((f = calloc(1, sizeof(*f))) == NULL)
308292120Semaste			err(EXIT_FAILURE, "calloc");
309292120Semaste		if ((f->name = strdup(funcname)) == NULL)
310292120Semaste			err(EXIT_FAILURE, "strdup");
311292120Semaste		if (found_ranges) {
312292120Semaste			f->ranges = ranges;
313292120Semaste			f->ranges_cnt = ranges_cnt;
314292120Semaste		} else {
315292120Semaste			f->lopc = lopc;
316292120Semaste			f->hipc = hipc;
317289071Semaste		}
318292120Semaste		if (tag == DW_TAG_inlined_subroutine) {
319292120Semaste			f->inlined_caller = parent;
320292120Semaste			dwarf_attrval_unsigned(die, DW_AT_call_file,
321292120Semaste			    &f->call_file, &de);
322292120Semaste			dwarf_attrval_unsigned(die, DW_AT_call_line,
323292120Semaste			    &f->call_line, &de);
324292120Semaste		}
325292120Semaste		STAILQ_INSERT_TAIL(&cu->funclist, f, next);
326260684Skaiw	}
327260684Skaiw
328260684Skaiwcont_search:
329260684Skaiw
330260684Skaiw	/* Search children. */
331260684Skaiw	ret = dwarf_child(die, &ret_die, &de);
332260684Skaiw	if (ret == DW_DLV_ERROR)
333292120Semaste		warnx("dwarf_child: %s", dwarf_errmsg(de));
334292120Semaste	else if (ret == DW_DLV_OK) {
335292120Semaste		if (f != NULL)
336292120Semaste			collect_func(dbg, ret_die, f, cu);
337292120Semaste		else
338292120Semaste			collect_func(dbg, ret_die, parent, cu);
339292120Semaste	}
340260684Skaiw
341260684Skaiw	/* Search sibling. */
342260684Skaiw	ret = dwarf_siblingof(dbg, die, &ret_die, &de);
343260684Skaiw	if (ret == DW_DLV_ERROR)
344292120Semaste		warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
345260684Skaiw	else if (ret == DW_DLV_OK)
346292120Semaste		collect_func(dbg, ret_die, parent, cu);
347289071Semaste
348292120Semaste	/* Cleanup */
349367466Sdim	if (die != cu->die)
350367466Sdim		dwarf_dealloc(dbg, die, DW_DLA_DIE);
351292120Semaste
352292120Semaste	if (abst_die != NULL)
353292120Semaste		dwarf_dealloc(dbg, abst_die, DW_DLA_DIE);
354292120Semaste
355292120Semaste	if (spec_die != NULL)
356292120Semaste		dwarf_dealloc(dbg, spec_die, DW_DLA_DIE);
357260684Skaiw}
358260684Skaiw
359260684Skaiwstatic void
360292120Semasteprint_inlines(struct CU *cu, struct Func *f, Dwarf_Unsigned call_file,
361292120Semaste    Dwarf_Unsigned call_line)
362260684Skaiw{
363292120Semaste	char demangled[1024];
364292120Semaste	char *file;
365292120Semaste
366292120Semaste	if (call_file > 0 && (Dwarf_Signed) call_file <= cu->nsrcfiles)
367292120Semaste		file = cu->srcfiles[call_file - 1];
368292120Semaste	else
369292120Semaste		file = unknown;
370292120Semaste
371292120Semaste	if (pretty_print)
372292120Semaste		printf(" (inlined by) ");
373292120Semaste
374292120Semaste	if (func) {
375292120Semaste		if (demangle && !elftc_demangle(f->name, demangled,
376292120Semaste		    sizeof(demangled), 0)) {
377292120Semaste			if (pretty_print)
378292120Semaste				printf("%s at ", demangled);
379292120Semaste			else
380292120Semaste				printf("%s\n", demangled);
381292120Semaste		} else {
382292120Semaste			if (pretty_print)
383292120Semaste				printf("%s at ", f->name);
384292120Semaste			else
385292120Semaste				printf("%s\n", f->name);
386292120Semaste		}
387292120Semaste	}
388295577Semaste	(void) printf("%s:%ju\n", base ? basename(file) : file,
389295577Semaste	    (uintmax_t) call_line);
390292120Semaste
391292120Semaste	if (f->inlined_caller != NULL)
392292120Semaste		print_inlines(cu, f->inlined_caller, f->call_file,
393292120Semaste		    f->call_line);
394292120Semaste}
395292120Semaste
396367466Sdimstatic struct CU *
397367466Sdimculookup(Dwarf_Unsigned addr)
398367466Sdim{
399367466Sdim	struct CU find, *res;
400367466Sdim
401367466Sdim	find.lopc = addr;
402367466Sdim	res = RB_NFIND(cutree, &cuhead, &find);
403367466Sdim	if (res != NULL) {
404367466Sdim		if (res->lopc != addr)
405367466Sdim			res = RB_PREV(cutree, &cuhead, res);
406367466Sdim		if (res != NULL && addr >= res->lopc && addr < res->hipc)
407367466Sdim			return (res);
408367466Sdim	} else {
409367466Sdim		res = RB_MAX(cutree, &cuhead);
410367466Sdim		if (res != NULL && addr >= res->lopc && addr < res->hipc)
411367466Sdim			return (res);
412367466Sdim	}
413367466Sdim	return (NULL);
414367466Sdim}
415367466Sdim
416367466Sdim/*
417367466Sdim * Check whether addr falls into range(s) of current CU, and save current CU
418367466Sdim * to lookup tree if so.
419367466Sdim */
420367466Sdimstatic int
421367466Sdimcheck_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,
422367466Sdim    struct CU **cu)
423367466Sdim{
424367466Sdim	Dwarf_Error de;
425367466Sdim	Dwarf_Unsigned addr_base, lopc, hipc;
426367466Sdim	Dwarf_Off ranges_off;
427367466Sdim	Dwarf_Signed ranges_cnt;
428367466Sdim	Dwarf_Ranges *ranges;
429367466Sdim	int i, ret;
430367466Sdim	bool in_range;
431367466Sdim
432367466Sdim	addr_base = 0;
433367466Sdim	ranges = NULL;
434367466Sdim	ranges_cnt = 0;
435367466Sdim	in_range = false;
436367466Sdim
437367466Sdim	ret = dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de);
438367466Sdim	if (ret == DW_DLV_NO_ENTRY) {
439367466Sdim		if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ==
440367466Sdim		    DW_DLV_OK) {
441367466Sdim			if (lopc == curlopc)
442367466Sdim				return (DW_DLV_ERROR);
443367466Sdim			if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc,
444367466Sdim				&de) == DW_DLV_OK) {
445367466Sdim				/*
446367466Sdim				 * Check if the address falls into the PC
447367466Sdim				 * range of this CU.
448367466Sdim				 */
449367466Sdim				if (handle_high_pc(die, lopc, &hipc) !=
450367466Sdim					DW_DLV_OK)
451367466Sdim					return (DW_DLV_ERROR);
452367466Sdim			} else {
453367466Sdim				/* Assume ~0ULL if DW_AT_high_pc not present */
454367466Sdim				hipc = ~0ULL;
455367466Sdim			}
456367466Sdim
457367466Sdim			if (addr >= lopc && addr < hipc) {
458367466Sdim				in_range = true;
459367466Sdim			}
460367466Sdim		}
461367466Sdim	} else if (ret == DW_DLV_OK) {
462367466Sdim		ret = dwarf_get_ranges(dbg, ranges_off, &ranges,
463367466Sdim			&ranges_cnt, NULL, &de);
464367466Sdim		if (ret != DW_DLV_OK)
465367466Sdim			return (ret);
466367466Sdim
467367466Sdim		if (!ranges || ranges_cnt <= 0)
468367466Sdim			return (DW_DLV_ERROR);
469367466Sdim
470367466Sdim		for (i = 0; i < ranges_cnt; i++) {
471367466Sdim			if (ranges[i].dwr_type == DW_RANGES_END)
472367466Sdim				return (DW_DLV_NO_ENTRY);
473367466Sdim
474367466Sdim			if (ranges[i].dwr_type ==
475367466Sdim				DW_RANGES_ADDRESS_SELECTION) {
476367466Sdim				addr_base = ranges[i].dwr_addr2;
477367466Sdim				continue;
478367466Sdim			}
479367466Sdim
480367466Sdim			/* DW_RANGES_ENTRY */
481367466Sdim			lopc = ranges[i].dwr_addr1 + addr_base;
482367466Sdim			hipc = ranges[i].dwr_addr2 + addr_base;
483367466Sdim
484367466Sdim			if (lopc == curlopc)
485367466Sdim				return (DW_DLV_ERROR);
486367466Sdim
487367466Sdim			if (addr >= lopc && addr < hipc){
488367466Sdim				in_range = true;
489367466Sdim				break;
490367466Sdim			}
491367466Sdim		}
492367466Sdim	} else {
493367466Sdim		return (DW_DLV_ERROR);
494367466Sdim	}
495367466Sdim
496367466Sdim	if (in_range) {
497367466Sdim		if ((*cu = calloc(1, sizeof(struct CU))) == NULL)
498367466Sdim			err(EXIT_FAILURE, "calloc");
499367466Sdim		(*cu)->lopc = lopc;
500367466Sdim		(*cu)->hipc = hipc;
501367466Sdim		(*cu)->die = die;
502367466Sdim		(*cu)->dbg = dbg;
503367466Sdim		STAILQ_INIT(&(*cu)->funclist);
504367466Sdim		RB_INSERT(cutree, &cuhead, *cu);
505367466Sdim		curlopc = lopc;
506367466Sdim		return (DW_DLV_OK);
507367466Sdim	} else {
508367466Sdim		return (DW_DLV_NO_ENTRY);
509367466Sdim	}
510367466Sdim}
511367466Sdim
512292120Semastestatic void
513292120Semastetranslate(Dwarf_Debug dbg, Elf *e, const char* addrstr)
514292120Semaste{
515289071Semaste	Dwarf_Die die, ret_die;
516260684Skaiw	Dwarf_Line *lbuf;
517260684Skaiw	Dwarf_Error de;
518260684Skaiw	Dwarf_Half tag;
519367466Sdim	Dwarf_Unsigned addr, lineno, plineno;
520260684Skaiw	Dwarf_Signed lcount;
521260684Skaiw	Dwarf_Addr lineaddr, plineaddr;
522292120Semaste	struct CU *cu;
523292120Semaste	struct Func *f;
524292120Semaste	const char *funcname;
525260684Skaiw	char *file, *file0, *pfile;
526260684Skaiw	char demangled[1024];
527292120Semaste	int ec, i, ret;
528260684Skaiw
529260684Skaiw	addr = strtoull(addrstr, NULL, 16);
530260684Skaiw	addr += section_base;
531260684Skaiw	lineno = 0;
532260684Skaiw	file = unknown;
533289074Semaste	die = NULL;
534367466Sdim	ret = DW_DLV_OK;
535260684Skaiw
536367466Sdim	cu = culookup(addr);
537367466Sdim	if (cu != NULL) {
538367466Sdim		die = cu->die;
539367466Sdim		dbg = cu->dbg;
540367466Sdim		goto status_ok;
541367466Sdim	}
542367466Sdim
543367466Sdim	while (true) {
544367466Sdim		/*
545367466Sdim		 * We resume the CU scan from the last place we found a match.
546367466Sdim		 * Because when we have 2 sequential addresses, and the second
547367466Sdim		 * one is of the next CU, it is faster to just go to the next CU
548367466Sdim		 * instead of starting from the beginning.
549367466Sdim		 */
550367466Sdim		ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
551367466Sdim		    &de);
552367466Sdim		if (ret == DW_DLV_NO_ENTRY) {
553367466Sdim			if (curlopc == ~0ULL)
554367466Sdim				goto out;
555367466Sdim			ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL,
556367466Sdim			    NULL, &de);
557367466Sdim		}
558260684Skaiw		die = NULL;
559289071Semaste		while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) {
560289071Semaste			if (die != NULL)
561289071Semaste				dwarf_dealloc(dbg, die, DW_DLA_DIE);
562289071Semaste			die = ret_die;
563260684Skaiw			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
564260684Skaiw				warnx("dwarf_tag failed: %s",
565260684Skaiw				    dwarf_errmsg(de));
566289071Semaste				goto next_cu;
567260684Skaiw			}
568289071Semaste
569260684Skaiw			/* XXX: What about DW_TAG_partial_unit? */
570260684Skaiw			if (tag == DW_TAG_compile_unit)
571260684Skaiw				break;
572260684Skaiw		}
573367466Sdim
574289071Semaste		if (ret_die == NULL) {
575260684Skaiw			warnx("could not find DW_TAG_compile_unit die");
576289071Semaste			goto next_cu;
577260684Skaiw		}
578367466Sdim		ret = check_range(dbg, die, addr, &cu);
579367466Sdim		if (ret == DW_DLV_OK)
580367466Sdim			break;
581367466Sdim		if (ret == DW_DLV_ERROR)
582367466Sdim			goto out;
583367466Sdimnext_cu:
584289071Semaste		if (die != NULL) {
585289071Semaste			dwarf_dealloc(dbg, die, DW_DLA_DIE);
586289071Semaste			die = NULL;
587289071Semaste		}
588260684Skaiw	}
589260684Skaiw
590292120Semaste	if (ret != DW_DLV_OK || die == NULL)
591292120Semaste		goto out;
592292120Semaste
593367466Sdimstatus_ok:
594292120Semaste	switch (dwarf_srclines(die, &lbuf, &lcount, &de)) {
595292120Semaste	case DW_DLV_OK:
596292120Semaste		break;
597292120Semaste	case DW_DLV_NO_ENTRY:
598292120Semaste		/* If a CU lacks debug info, just skip it. */
599292120Semaste		goto out;
600292120Semaste	default:
601292120Semaste		warnx("dwarf_srclines: %s", dwarf_errmsg(de));
602292120Semaste		goto out;
603292120Semaste	}
604292120Semaste
605292120Semaste	plineaddr = ~0ULL;
606292120Semaste	plineno = 0;
607292120Semaste	pfile = unknown;
608292120Semaste	for (i = 0; i < lcount; i++) {
609292120Semaste		if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
610292120Semaste			warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));
611292120Semaste			goto out;
612292120Semaste		}
613292120Semaste		if (dwarf_lineno(lbuf[i], &lineno, &de)) {
614292120Semaste			warnx("dwarf_lineno: %s", dwarf_errmsg(de));
615292120Semaste			goto out;
616292120Semaste		}
617292120Semaste		if (dwarf_linesrc(lbuf[i], &file0, &de)) {
618292120Semaste			warnx("dwarf_linesrc: %s", dwarf_errmsg(de));
619292120Semaste		} else
620292120Semaste			file = file0;
621292120Semaste		if (addr == lineaddr)
622292120Semaste			goto out;
623292120Semaste		else if (addr < lineaddr && addr > plineaddr) {
624292120Semaste			lineno = plineno;
625292120Semaste			file = pfile;
626292120Semaste			goto out;
627292120Semaste		}
628292120Semaste		plineaddr = lineaddr;
629292120Semaste		plineno = lineno;
630292120Semaste		pfile = file;
631292120Semaste	}
632292120Semaste
633260684Skaiwout:
634292120Semaste	f = NULL;
635260684Skaiw	funcname = NULL;
636292120Semaste	if (ret == DW_DLV_OK && (func || inlines) && cu != NULL) {
637292120Semaste		if (cu->srcfiles == NULL)
638292120Semaste			if (dwarf_srcfiles(die, &cu->srcfiles, &cu->nsrcfiles,
639292120Semaste			    &de))
640292120Semaste				warnx("dwarf_srcfiles: %s", dwarf_errmsg(de));
641292120Semaste		if (STAILQ_EMPTY(&cu->funclist)) {
642292120Semaste			collect_func(dbg, die, NULL, cu);
643292120Semaste			die = NULL;
644292120Semaste		}
645292120Semaste		f = search_func(cu, addr);
646292120Semaste		if (f != NULL)
647292120Semaste			funcname = f->name;
648289071Semaste	}
649260684Skaiw
650292120Semaste	if (print_addr) {
651292120Semaste		if ((ec = gelf_getclass(e)) == ELFCLASSNONE) {
652292120Semaste			warnx("gelf_getclass failed: %s", elf_errmsg(-1));
653292120Semaste			ec = ELFCLASS64;
654292120Semaste		}
655292120Semaste		if (ec == ELFCLASS32) {
656292120Semaste			if (pretty_print)
657292120Semaste				printf("0x%08jx: ", (uintmax_t) addr);
658292120Semaste			else
659292120Semaste				printf("0x%08jx\n", (uintmax_t) addr);
660292120Semaste		} else {
661292120Semaste			if (pretty_print)
662292120Semaste				printf("0x%016jx: ", (uintmax_t) addr);
663292120Semaste			else
664292120Semaste				printf("0x%016jx\n", (uintmax_t) addr);
665292120Semaste		}
666292120Semaste	}
667292120Semaste
668260684Skaiw	if (func) {
669260684Skaiw		if (funcname == NULL)
670292120Semaste			funcname = unknown;
671292120Semaste		if (demangle && !elftc_demangle(funcname, demangled,
672292120Semaste		    sizeof(demangled), 0)) {
673292120Semaste			if (pretty_print)
674292120Semaste				printf("%s at ", demangled);
675292120Semaste			else
676292120Semaste				printf("%s\n", demangled);
677292120Semaste		} else {
678292120Semaste			if (pretty_print)
679292120Semaste				printf("%s at ", funcname);
680292120Semaste			else
681292120Semaste				printf("%s\n", funcname);
682292120Semaste		}
683260684Skaiw	}
684260684Skaiw
685295577Semaste	(void) printf("%s:%ju\n", base ? basename(file) : file,
686295577Semaste	    (uintmax_t) lineno);
687260684Skaiw
688292120Semaste	if (ret == DW_DLV_OK && inlines && cu != NULL &&
689292120Semaste	    cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL)
690292120Semaste		print_inlines(cu, f->inlined_caller, f->call_file,
691292120Semaste		    f->call_line);
692260684Skaiw}
693260684Skaiw
694260684Skaiwstatic void
695260684Skaiwfind_section_base(const char *exe, Elf *e, const char *section)
696260684Skaiw{
697260684Skaiw	Dwarf_Addr off;
698260684Skaiw	Elf_Scn *scn;
699260684Skaiw	GElf_Ehdr eh;
700260684Skaiw	GElf_Shdr sh;
701260684Skaiw	size_t shstrndx;
702260684Skaiw	int elferr;
703260684Skaiw	const char *name;
704260684Skaiw
705260684Skaiw	if (gelf_getehdr(e, &eh) != &eh) {
706260684Skaiw		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
707260684Skaiw		return;
708260684Skaiw	}
709260684Skaiw
710260684Skaiw	if (!elf_getshstrndx(e, &shstrndx)) {
711260684Skaiw		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
712260684Skaiw		return;
713260684Skaiw	}
714260684Skaiw
715260684Skaiw	(void) elf_errno();
716260684Skaiw	off = 0;
717260684Skaiw	scn = NULL;
718260684Skaiw	while ((scn = elf_nextscn(e, scn)) != NULL) {
719260684Skaiw		if (gelf_getshdr(scn, &sh) == NULL) {
720260684Skaiw			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
721260684Skaiw			continue;
722260684Skaiw		}
723260684Skaiw		if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
724260684Skaiw			goto next;
725260684Skaiw		if (!strcmp(section, name)) {
726260684Skaiw			if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
727260684Skaiw				/*
728260684Skaiw				 * For executables, section base is the virtual
729260684Skaiw				 * address of the specified section.
730260684Skaiw				 */
731260684Skaiw				section_base = sh.sh_addr;
732260684Skaiw			} else if (eh.e_type == ET_REL) {
733260684Skaiw				/*
734260684Skaiw				 * For relocatables, section base is the
735260684Skaiw				 * relative offset of the specified section
736260684Skaiw				 * to the start of the first section.
737260684Skaiw				 */
738260684Skaiw				section_base = off;
739260684Skaiw			} else
740260684Skaiw				warnx("unknown e_type %u", eh.e_type);
741260684Skaiw			return;
742260684Skaiw		}
743260684Skaiw	next:
744260684Skaiw		off += sh.sh_size;
745260684Skaiw	}
746260684Skaiw	elferr = elf_errno();
747260684Skaiw	if (elferr != 0)
748260684Skaiw		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
749260684Skaiw
750260684Skaiw	errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
751260684Skaiw}
752260684Skaiw
753260684Skaiwint
754260684Skaiwmain(int argc, char **argv)
755260684Skaiw{
756260684Skaiw	Elf *e;
757260684Skaiw	Dwarf_Debug dbg;
758260684Skaiw	Dwarf_Error de;
759260684Skaiw	const char *exe, *section;
760260684Skaiw	char line[1024];
761260684Skaiw	int fd, i, opt;
762260684Skaiw
763260684Skaiw	exe = NULL;
764260684Skaiw	section = NULL;
765292120Semaste	while ((opt = getopt_long(argc, argv, "ab:Ce:fij:psHV", longopts,
766292120Semaste	    NULL)) != -1) {
767260684Skaiw		switch (opt) {
768292120Semaste		case 'a':
769292120Semaste			print_addr = 1;
770292120Semaste			break;
771260684Skaiw		case 'b':
772260684Skaiw			/* ignored */
773260684Skaiw			break;
774260684Skaiw		case 'C':
775260684Skaiw			demangle = 1;
776260684Skaiw			break;
777260684Skaiw		case 'e':
778260684Skaiw			exe = optarg;
779260684Skaiw			break;
780260684Skaiw		case 'f':
781260684Skaiw			func = 1;
782260684Skaiw			break;
783292120Semaste		case 'i':
784292120Semaste			inlines = 1;
785292120Semaste			break;
786260684Skaiw		case 'j':
787260684Skaiw			section = optarg;
788260684Skaiw			break;
789292120Semaste		case 'p':
790292120Semaste			pretty_print = 1;
791292120Semaste			break;
792260684Skaiw		case 's':
793260684Skaiw			base = 1;
794260684Skaiw			break;
795260684Skaiw		case 'H':
796260684Skaiw			usage();
797260684Skaiw		case 'V':
798260684Skaiw			version();
799260684Skaiw		default:
800260684Skaiw			usage();
801260684Skaiw		}
802260684Skaiw	}
803260684Skaiw
804260684Skaiw	argv += optind;
805260684Skaiw	argc -= optind;
806260684Skaiw
807260684Skaiw	if (exe == NULL)
808260684Skaiw		exe = "a.out";
809260684Skaiw
810260684Skaiw	if ((fd = open(exe, O_RDONLY)) < 0)
811260684Skaiw		err(EXIT_FAILURE, "%s", exe);
812260684Skaiw
813260684Skaiw	if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
814260684Skaiw		errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
815260684Skaiw
816260684Skaiw	if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
817260684Skaiw		errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
818260684Skaiw
819260684Skaiw	if (section)
820260684Skaiw		find_section_base(exe, e, section);
821260684Skaiw	else
822260684Skaiw		section_base = 0;
823260684Skaiw
824260684Skaiw	if (argc > 0)
825260684Skaiw		for (i = 0; i < argc; i++)
826292120Semaste			translate(dbg, e, argv[i]);
827317623Semaste	else {
828317623Semaste		setvbuf(stdout, NULL, _IOLBF, 0);
829317623Semaste		while (fgets(line, sizeof(line), stdin) != NULL)
830292120Semaste			translate(dbg, e, line);
831317623Semaste	}
832260684Skaiw
833260684Skaiw	dwarf_finish(dbg, &de);
834260684Skaiw
835260684Skaiw	(void) elf_end(e);
836260684Skaiw
837260684Skaiw	exit(0);
838260684Skaiw}
839