Path: blob/main/contrib/elftoolchain/addr2line/addr2line.c
39507 views
/*-1* Copyright (c) 2009 Kai Wang2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <sys/tree.h>2829#include <capsicum_helpers.h>30#include <dwarf.h>31#include <err.h>32#include <fcntl.h>33#include <gelf.h>34#include <getopt.h>35#include <libdwarf.h>36#include <libelftc.h>37#include <libgen.h>38#include <stdbool.h>39#include <stdio.h>40#include <stdlib.h>41#include <string.h>4243#include "_elftc.h"4445ELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $");4647struct Func {48char *name;49Dwarf_Unsigned lopc;50Dwarf_Unsigned hipc;51Dwarf_Unsigned call_file;52Dwarf_Unsigned call_line;53Dwarf_Ranges *ranges;54Dwarf_Signed ranges_cnt;55struct Func *inlined_caller;56STAILQ_ENTRY(Func) next;57};5859struct range {60RB_ENTRY(range) entry;61Dwarf_Off off;62Dwarf_Unsigned lopc;63Dwarf_Unsigned hipc;64char **srcfiles;65Dwarf_Signed nsrcfiles;66STAILQ_HEAD(, Func) funclist;67Dwarf_Die die;68Dwarf_Debug dbg;69};7071static struct option longopts[] = {72{"addresses", no_argument, NULL, 'a'},73{"target" , required_argument, NULL, 'b'},74{"demangle", no_argument, NULL, 'C'},75{"exe", required_argument, NULL, 'e'},76{"functions", no_argument, NULL, 'f'},77{"inlines", no_argument, NULL, 'i'},78{"section", required_argument, NULL, 'j'},79{"pretty-print", no_argument, NULL, 'p'},80{"basename", no_argument, NULL, 's'},81{"help", no_argument, NULL, 'H'},82{"version", no_argument, NULL, 'V'},83{NULL, 0, NULL, 0}84};8586static int demangle, func, base, inlines, print_addr, pretty_print;87static char unknown[] = { '?', '?', '\0' };88static Dwarf_Addr section_base;89/* Need a new curlopc that stores last lopc value. */90static Dwarf_Unsigned curlopc = ~0ULL;91static RB_HEAD(cutree, range) cuhead = RB_INITIALIZER(&cuhead);9293static int94lopccmp(struct range *e1, struct range *e2)95{96return (e1->lopc < e2->lopc ? -1 : e1->lopc > e2->lopc);97}9899RB_PROTOTYPE(cutree, range, entry, lopccmp);100RB_GENERATE(cutree, range, entry, lopccmp)101102#define USAGE_MESSAGE "\103Usage: %s [options] hexaddress...\n\104Map program addresses to source file names and line numbers.\n\n\105Options:\n\106-a | --addresses Display address prior to line number info.\n\107-b TGT | --target=TGT (Accepted but ignored).\n\108-e EXE | --exe=EXE Use program \"EXE\" to translate addresses.\n\109-f | --functions Display function names.\n\110-i | --inlines Display caller info for inlined functions.\n\111-j NAME | --section=NAME Values are offsets into section \"NAME\".\n\112-p | --pretty-print Display line number info and function name\n\113in human readable manner.\n\114-s | --basename Only show the base name for each file name.\n\115-C | --demangle Demangle C++ names.\n\116-H | --help Print a help message.\n\117-V | --version Print a version identifier and exit.\n"118119static void120usage(void)121{122(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());123exit(1);124}125126static void127version(void)128{129130fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());131exit(0);132}133134/*135* Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't136* fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1)137* generate DW_AT_high_pc as an offset from DW_AT_low_pc.138*139* "If the value of the DW_AT_high_pc is of class address, it is the140* relocated address of the first location past the last instruction141* associated with the entity; if it is of class constant, the value142* is an unsigned integer offset which when added to the low PC gives143* the address of the first location past the last instruction144* associated with the entity."145*146* DWARF4 spec, section 2.17.2.147*/148static int149handle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc)150{151Dwarf_Error de;152Dwarf_Half form;153Dwarf_Attribute at;154int ret;155156ret = dwarf_attr(die, DW_AT_high_pc, &at, &de);157if (ret == DW_DLV_ERROR) {158warnx("dwarf_attr failed: %s", dwarf_errmsg(de));159return (ret);160}161ret = dwarf_whatform(at, &form, &de);162if (ret == DW_DLV_ERROR) {163warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));164return (ret);165}166if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT)167*hipc += lopc;168169return (DW_DLV_OK);170}171172static struct Func *173search_func(struct range *range, Dwarf_Unsigned addr)174{175struct Func *f, *f0;176Dwarf_Unsigned lopc, hipc, addr_base;177int i;178179f0 = NULL;180181STAILQ_FOREACH(f, &range->funclist, next) {182if (f->ranges != NULL) {183addr_base = 0;184for (i = 0; i < f->ranges_cnt; i++) {185if (f->ranges[i].dwr_type == DW_RANGES_END)186break;187if (f->ranges[i].dwr_type ==188DW_RANGES_ADDRESS_SELECTION) {189addr_base = f->ranges[i].dwr_addr2;190continue;191}192193/* DW_RANGES_ENTRY */194lopc = f->ranges[i].dwr_addr1 + addr_base;195hipc = f->ranges[i].dwr_addr2 + addr_base;196if (addr >= lopc && addr < hipc) {197if (f0 == NULL ||198(lopc >= f0->lopc &&199hipc <= f0->hipc)) {200f0 = f;201f0->lopc = lopc;202f0->hipc = hipc;203break;204}205}206}207} else if (addr >= f->lopc && addr < f->hipc) {208if (f0 == NULL ||209(f->lopc >= f0->lopc && f->hipc <= f0->hipc))210f0 = f;211}212}213214return (f0);215}216217static void218collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent,219struct range *range)220{221Dwarf_Die ret_die, abst_die, spec_die;222Dwarf_Error de;223Dwarf_Half tag;224Dwarf_Unsigned lopc, hipc, ranges_off;225Dwarf_Signed ranges_cnt;226Dwarf_Off ref;227Dwarf_Attribute abst_at, spec_at;228Dwarf_Ranges *ranges;229const char *funcname;230struct Func *f;231int found_ranges, ret;232233f = NULL;234abst_die = spec_die = NULL;235236if (dwarf_tag(die, &tag, &de)) {237warnx("dwarf_tag: %s", dwarf_errmsg(de));238goto cont_search;239}240if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point ||241tag == DW_TAG_inlined_subroutine || tag == DW_TAG_label) {242/*243* Function address range can be specified by either244* a DW_AT_ranges attribute which points to a range list or245* by a pair of DW_AT_low_pc and DW_AT_high_pc attributes.246*/247ranges = NULL;248ranges_cnt = 0;249found_ranges = 0;250if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off,251&de) == DW_DLV_OK &&252dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges,253&ranges_cnt, NULL, &de) == DW_DLV_OK) {254if (ranges != NULL && ranges_cnt > 0) {255found_ranges = 1;256goto get_func_name;257}258}259260/*261* Ranges pointer not found. Search for DW_AT_low_pc, and262* DW_AT_high_pc iff die is not a label. Labels doesn't have263* hipc attr. */264if (tag == DW_TAG_label) {265if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc,266&de) != DW_DLV_OK)267goto cont_search;268} else {269if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc,270&de) || dwarf_attrval_unsigned(die, DW_AT_high_pc,271&hipc, &de))272goto cont_search;273if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK)274goto cont_search;275}276277get_func_name:278/*279* Most common case the function name is stored in DW_AT_name280* attribute.281*/282if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) ==283DW_DLV_OK)284goto add_func;285286/*287* For inlined function, the actual name is probably in the DIE288* referenced by DW_AT_abstract_origin. (if present)289*/290if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) ==291DW_DLV_OK &&292dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK &&293dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK &&294dwarf_attrval_string(abst_die, DW_AT_name, &funcname,295&de) == DW_DLV_OK)296goto add_func;297298/*299* If DW_AT_name is not present, but DW_AT_specification is300* present, then probably the actual name is in the DIE301* referenced by DW_AT_specification.302*/303if (dwarf_attr(die, DW_AT_specification, &spec_at, &de) ==304DW_DLV_OK &&305dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK &&306dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK &&307dwarf_attrval_string(spec_die, DW_AT_name, &funcname,308&de) == DW_DLV_OK)309goto add_func;310311/* Skip if no name associated with this DIE. */312goto cont_search;313314add_func:315if ((f = calloc(1, sizeof(*f))) == NULL)316err(EXIT_FAILURE, "calloc");317if ((f->name = strdup(funcname)) == NULL)318err(EXIT_FAILURE, "strdup");319if (found_ranges) {320f->ranges = ranges;321f->ranges_cnt = ranges_cnt;322} else {323f->lopc = lopc;324f->hipc = hipc;325}326if (tag == DW_TAG_inlined_subroutine) {327f->inlined_caller = parent;328dwarf_attrval_unsigned(die, DW_AT_call_file,329&f->call_file, &de);330dwarf_attrval_unsigned(die, DW_AT_call_line,331&f->call_line, &de);332}333STAILQ_INSERT_TAIL(&range->funclist, f, next);334}335336cont_search:337338/* Search children. */339ret = dwarf_child(die, &ret_die, &de);340if (ret == DW_DLV_ERROR)341warnx("dwarf_child: %s", dwarf_errmsg(de));342else if (ret == DW_DLV_OK) {343if (f != NULL)344collect_func(dbg, ret_die, f, range);345else346collect_func(dbg, ret_die, parent, range);347}348349/* Search sibling. */350ret = dwarf_siblingof(dbg, die, &ret_die, &de);351if (ret == DW_DLV_ERROR)352warnx("dwarf_siblingof: %s", dwarf_errmsg(de));353else if (ret == DW_DLV_OK)354collect_func(dbg, ret_die, parent, range);355356/* Cleanup */357if (die != range->die)358dwarf_dealloc(dbg, die, DW_DLA_DIE);359360if (abst_die != NULL)361dwarf_dealloc(dbg, abst_die, DW_DLA_DIE);362363if (spec_die != NULL)364dwarf_dealloc(dbg, spec_die, DW_DLA_DIE);365}366367static void368print_inlines(struct range *range, struct Func *f, Dwarf_Unsigned call_file,369Dwarf_Unsigned call_line)370{371char demangled[1024];372char *file;373374if (call_file > 0 && (Dwarf_Signed) call_file <= range->nsrcfiles)375file = range->srcfiles[call_file - 1];376else377file = unknown;378379if (pretty_print)380printf(" (inlined by) ");381382if (func) {383if (demangle && !elftc_demangle(f->name, demangled,384sizeof(demangled), 0)) {385if (pretty_print)386printf("%s at ", demangled);387else388printf("%s\n", demangled);389} else {390if (pretty_print)391printf("%s at ", f->name);392else393printf("%s\n", f->name);394}395}396(void) printf("%s:%ju\n", base ? basename(file) : file,397(uintmax_t) call_line);398399if (f->inlined_caller != NULL)400print_inlines(range, f->inlined_caller, f->call_file,401f->call_line);402}403404static struct range *405culookup(Dwarf_Unsigned addr)406{407struct range find, *res;408409find.lopc = addr;410res = RB_NFIND(cutree, &cuhead, &find);411if (res != NULL) {412if (res->lopc != addr)413res = RB_PREV(cutree, &cuhead, res);414if (res != NULL && addr >= res->lopc && addr < res->hipc)415return (res);416} else {417res = RB_MAX(cutree, &cuhead);418if (res != NULL && addr >= res->lopc && addr < res->hipc)419return (res);420}421return (NULL);422}423424/*425* When DW_AT_ranges, DW_AT_low_pc/DW_AT_high_pc are all absent, we check the426* children of cu die for labels. If the address falls into one of the labels427* ranges(aranges), return the label DIE.428*/429static int430check_labels(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,431struct range **range) {432Dwarf_Addr start;433Dwarf_Arange *aranges;434Dwarf_Die prev_die, ret_die;435Dwarf_Error de;436Dwarf_Half tag;437Dwarf_Off die_off;438Dwarf_Unsigned lopc, length;439Dwarf_Signed arcnt;440struct range *labelp, **labels;441int i, j, label_cnt, ret;442443prev_die = ret_die = NULL;444labels = NULL;445i = label_cnt = 0;446447/* Find aranges. */448ret = dwarf_get_aranges(dbg, &aranges, &arcnt, &de);449if (ret != DW_DLV_OK && ret != DW_DLV_NO_ENTRY)450warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de));451452/* Child of current CU. */453ret = dwarf_child(die, &prev_die, &de);454if (ret == DW_DLV_ERROR)455warnx("dwarf_child: %s", dwarf_errmsg(de));456457/* Count labels. */458while (1) {459if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) {460warnx("dwarf_tag failed: %s",461dwarf_errmsg(de));462return DW_DLV_ERROR;463}464if (tag == DW_TAG_label) {465if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc,466&lopc, &de) == DW_DLV_OK)467label_cnt++;468}469470if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK)471break;472473if (prev_die != NULL)474dwarf_dealloc(dbg, prev_die, DW_DLA_DIE);475prev_die = ret_die;476}477478if (label_cnt == 0)479return (DW_DLV_NO_ENTRY);480481/* Allocate space for labels. */482if ((labels = calloc(label_cnt, sizeof(struct range *))) == NULL)483err(EXIT_FAILURE, "calloc");484485/* Add labels to list. */486ret = dwarf_child(die, &prev_die, &de);487if (ret == DW_DLV_ERROR)488warnx("dwarf_child: %s", dwarf_errmsg(de));489while (1) {490if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) {491warnx("dwarf_tag failed: %s",492dwarf_errmsg(de));493free(labels);494return DW_DLV_ERROR;495}496if (tag == DW_TAG_label) {497if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc,498&lopc, &de) == DW_DLV_OK) {499if (curlopc == lopc) {500for (i = 0; i < label_cnt - 1; i++) {501if (labels[i] != *range)502free(labels[i]);503}504free(labels);505return DW_DLV_ERROR;506}507labelp = calloc(1, sizeof(struct range));508if (labelp == NULL)509err(EXIT_FAILURE, "calloc");510labelp->lopc = lopc;511labelp->die = prev_die;512labelp->dbg = dbg;513STAILQ_INIT(&labelp->funclist);514labels[i++] = labelp;515}516}517if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK)518break;519if (prev_die != NULL && tag != DW_TAG_label)520dwarf_dealloc(dbg, prev_die, DW_DLA_DIE);521prev_die = ret_die;522}523524/* Set hipc for each label using aranges */525for (i = 0; i < label_cnt; i++) {526for (j = 0; j < arcnt; j++) {527if (dwarf_get_arange_info(aranges[j], &start, &length,528&die_off, &de) != DW_DLV_OK) {529warnx("dwarf_get_arange_info failed: %s",530dwarf_errmsg(de));531continue;532}533if (labels[i]->lopc == (Dwarf_Unsigned)start) {534labels[i]->hipc = start + length;535break;536}537}538}539540/* If addr in label's range, we have found the range for this label. */541for (i = 0; i < label_cnt; i++) {542if (addr >= labels[i]->lopc && addr < labels[i]->hipc) {543*range = labels[i];544RB_INSERT(cutree, &cuhead, (*range));545curlopc = (*range)->lopc;546break;547}548}549550for (i = 0; i < label_cnt - 1; i++) {551if (labels[i] != *range)552free(labels[i]);553}554free(labels);555556if (*range != NULL)557return (DW_DLV_OK);558else559return (DW_DLV_NO_ENTRY);560}561562/*563* Check whether addr falls into range(s) of current CU.564* If so, save current CU to lookup tree.565*/566static int567check_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,568struct range **range)569{570Dwarf_Error de;571Dwarf_Unsigned addr_base, lopc, hipc;572Dwarf_Off ranges_off;573Dwarf_Signed ranges_cnt;574Dwarf_Ranges *ranges;575int i, ret;576bool in_cu;577578addr_base = 0;579ranges = NULL;580ranges_cnt = 0;581in_cu = false;582583if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de) ==584DW_DLV_OK) {585ret = dwarf_get_ranges(dbg, ranges_off, &ranges,586&ranges_cnt, NULL, &de);587if (ret != DW_DLV_OK)588return (ret);589590if (!ranges || ranges_cnt <= 0)591return (DW_DLV_ERROR);592593for (i = 0; i < ranges_cnt; i++) {594if (ranges[i].dwr_type == DW_RANGES_END)595return (DW_DLV_NO_ENTRY);596597if (ranges[i].dwr_type ==598DW_RANGES_ADDRESS_SELECTION) {599addr_base = ranges[i].dwr_addr2;600continue;601}602603/* DW_RANGES_ENTRY */604lopc = ranges[i].dwr_addr1 + addr_base;605hipc = ranges[i].dwr_addr2 + addr_base;606607if (lopc == curlopc)608return (DW_DLV_ERROR);609610if (addr >= lopc && addr < hipc){611in_cu = true;612break;613}614}615} else if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ==616DW_DLV_OK) {617if (lopc == curlopc)618return (DW_DLV_ERROR);619if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de) ==620DW_DLV_OK) {621/*622* Check if the address falls into the PC623* range of this CU.624*/625if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK)626return (DW_DLV_ERROR);627} else {628/* Assume ~0ULL if DW_AT_high_pc not present. */629hipc = ~0ULL;630}631632if (addr >= lopc && addr < hipc) {633in_cu = true;634}635} else {636/* Addr not found above, try labels. */637ret = check_labels(dbg, die, addr, range);638return ret;639}640641if (in_cu) {642if ((*range = calloc(1, sizeof(struct range))) == NULL)643err(EXIT_FAILURE, "calloc");644(*range)->lopc = lopc;645(*range)->hipc = hipc;646(*range)->die = die;647(*range)->dbg = dbg;648STAILQ_INIT(&(*range)->funclist);649RB_INSERT(cutree, &cuhead, *range);650curlopc = lopc;651return (DW_DLV_OK);652} else {653return (DW_DLV_NO_ENTRY);654}655}656657static void658translate(Dwarf_Debug dbg, Elf *e, const char* addrstr)659{660Dwarf_Die die, ret_die;661Dwarf_Line *lbuf;662Dwarf_Error de;663Dwarf_Half tag;664Dwarf_Unsigned addr, lineno, plineno;665Dwarf_Signed lcount;666Dwarf_Addr lineaddr, plineaddr;667struct range *range;668struct Func *f;669const char *funcname;670char *file, *file0, *pfile;671char demangled[1024];672int ec, i, ret;673674addr = strtoull(addrstr, NULL, 16);675addr += section_base;676lineno = 0;677file = unknown;678die = NULL;679ret = DW_DLV_OK;680681range = culookup(addr);682if (range != NULL) {683die = range->die;684dbg = range->dbg;685goto status_ok;686}687688while (true) {689/*690* We resume the CU scan from the last place we found a match.691* Because when we have 2 sequential addresses, and the second692* one is of the next CU, it is faster to just go to the next CU693* instead of starting from the beginning.694*/695ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,696&de);697if (ret == DW_DLV_NO_ENTRY) {698if (curlopc == ~0ULL)699goto out;700ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL,701NULL, &de);702}703die = NULL;704while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) {705if (die != NULL)706dwarf_dealloc(dbg, die, DW_DLA_DIE);707die = ret_die;708if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {709warnx("dwarf_tag failed: %s",710dwarf_errmsg(de));711goto next_cu;712}713714/* XXX: What about DW_TAG_partial_unit? */715if (tag == DW_TAG_compile_unit)716break;717}718719if (ret_die == NULL) {720warnx("could not find DW_TAG_compile_unit die");721goto next_cu;722}723ret = check_range(dbg, die, addr, &range);724if (ret == DW_DLV_OK)725break;726if (ret == DW_DLV_ERROR)727goto out;728next_cu:729if (die != NULL) {730dwarf_dealloc(dbg, die, DW_DLA_DIE);731die = NULL;732}733}734735if (ret != DW_DLV_OK || die == NULL)736goto out;737738status_ok:739switch (dwarf_srclines(die, &lbuf, &lcount, &de)) {740case DW_DLV_OK:741break;742case DW_DLV_NO_ENTRY:743/* If a CU lacks debug info, just skip it. */744goto out;745default:746warnx("dwarf_srclines: %s", dwarf_errmsg(de));747goto out;748}749750plineaddr = ~0ULL;751plineno = 0;752pfile = unknown;753for (i = 0; i < lcount; i++) {754if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {755warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));756goto out;757}758if (dwarf_lineno(lbuf[i], &lineno, &de)) {759warnx("dwarf_lineno: %s", dwarf_errmsg(de));760goto out;761}762if (dwarf_linesrc(lbuf[i], &file0, &de)) {763warnx("dwarf_linesrc: %s", dwarf_errmsg(de));764} else765file = file0;766if (addr == lineaddr)767goto out;768else if (addr < lineaddr && addr > plineaddr) {769lineno = plineno;770file = pfile;771goto out;772}773plineaddr = lineaddr;774plineno = lineno;775pfile = file;776}777778out:779f = NULL;780funcname = NULL;781if (ret == DW_DLV_OK && (func || inlines) && range != NULL) {782if (range->srcfiles == NULL)783if (dwarf_srcfiles(die, &range->srcfiles,784&range->nsrcfiles, &de))785warnx("dwarf_srcfiles: %s", dwarf_errmsg(de));786if (STAILQ_EMPTY(&range->funclist)) {787collect_func(dbg, range->die, NULL, range);788die = NULL;789}790f = search_func(range, addr);791if (f != NULL)792funcname = f->name;793}794795if (print_addr) {796if ((ec = gelf_getclass(e)) == ELFCLASSNONE) {797warnx("gelf_getclass failed: %s", elf_errmsg(-1));798ec = ELFCLASS64;799}800if (ec == ELFCLASS32) {801if (pretty_print)802printf("0x%08jx: ", (uintmax_t) addr);803else804printf("0x%08jx\n", (uintmax_t) addr);805} else {806if (pretty_print)807printf("0x%016jx: ", (uintmax_t) addr);808else809printf("0x%016jx\n", (uintmax_t) addr);810}811}812813if (func) {814if (funcname == NULL)815funcname = unknown;816if (demangle && !elftc_demangle(funcname, demangled,817sizeof(demangled), 0)) {818if (pretty_print)819printf("%s at ", demangled);820else821printf("%s\n", demangled);822} else {823if (pretty_print)824printf("%s at ", funcname);825else826printf("%s\n", funcname);827}828}829830(void) printf("%s:%ju\n", base ? basename(file) : file,831(uintmax_t) lineno);832833if (ret == DW_DLV_OK && inlines && range != NULL &&834range->srcfiles != NULL && f != NULL && f->inlined_caller != NULL)835print_inlines(range, f->inlined_caller, f->call_file,836f->call_line);837}838839static void840find_section_base(const char *exe, Elf *e, const char *section)841{842Dwarf_Addr off;843Elf_Scn *scn;844GElf_Ehdr eh;845GElf_Shdr sh;846size_t shstrndx;847int elferr;848const char *name;849850if (gelf_getehdr(e, &eh) != &eh) {851warnx("gelf_getehdr failed: %s", elf_errmsg(-1));852return;853}854855if (!elf_getshstrndx(e, &shstrndx)) {856warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));857return;858}859860(void) elf_errno();861off = 0;862scn = NULL;863while ((scn = elf_nextscn(e, scn)) != NULL) {864if (gelf_getshdr(scn, &sh) == NULL) {865warnx("gelf_getshdr failed: %s", elf_errmsg(-1));866continue;867}868if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)869goto next;870if (!strcmp(section, name)) {871if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {872/*873* For executables, section base is the virtual874* address of the specified section.875*/876section_base = sh.sh_addr;877} else if (eh.e_type == ET_REL) {878/*879* For relocatables, section base is the880* relative offset of the specified section881* to the start of the first section.882*/883section_base = off;884} else885warnx("unknown e_type %u", eh.e_type);886return;887}888next:889off += sh.sh_size;890}891elferr = elf_errno();892if (elferr != 0)893warnx("elf_nextscn failed: %s", elf_errmsg(elferr));894895errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);896}897898int899main(int argc, char **argv)900{901cap_rights_t rights;902Elf *e;903Dwarf_Debug dbg;904Dwarf_Error de;905const char *exe, *section;906char line[1024];907int fd, i, opt;908909exe = NULL;910section = NULL;911while ((opt = getopt_long(argc, argv, "ab:Ce:fij:psHV", longopts,912NULL)) != -1) {913switch (opt) {914case 'a':915print_addr = 1;916break;917case 'b':918/* ignored */919break;920case 'C':921demangle = 1;922break;923case 'e':924exe = optarg;925break;926case 'f':927func = 1;928break;929case 'i':930inlines = 1;931break;932case 'j':933section = optarg;934break;935case 'p':936pretty_print = 1;937break;938case 's':939base = 1;940break;941case 'H':942usage();943case 'V':944version();945default:946usage();947}948}949950argv += optind;951argc -= optind;952953if (exe == NULL)954exe = "a.out";955956if ((fd = open(exe, O_RDONLY)) < 0)957err(EXIT_FAILURE, "%s", exe);958959if (caph_rights_limit(fd, cap_rights_init(&rights, CAP_FSTAT,960CAP_MMAP_R)) < 0)961errx(EXIT_FAILURE, "caph_rights_limit");962963caph_cache_catpages();964if (caph_limit_stdio() < 0)965errx(EXIT_FAILURE, "failed to limit stdio rights");966if (caph_enter() < 0)967errx(EXIT_FAILURE, "failed to enter capability mode");968969if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))970errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));971972if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)973errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));974975if (section)976find_section_base(exe, e, section);977else978section_base = 0;979980if (argc > 0)981for (i = 0; i < argc; i++)982translate(dbg, e, argv[i]);983else {984setvbuf(stdout, NULL, _IOLBF, 0);985while (fgets(line, sizeof(line), stdin) != NULL)986translate(dbg, e, line);987}988989dwarf_finish(dbg, &de);990991(void) elf_end(e);992993exit(0);994}995996997