1a85fe12eSEd Maste /*- 2a85fe12eSEd Maste * Copyright (c) 2009 Kai Wang 3a85fe12eSEd Maste * All rights reserved. 4a85fe12eSEd Maste * 5a85fe12eSEd Maste * Redistribution and use in source and binary forms, with or without 6a85fe12eSEd Maste * modification, are permitted provided that the following conditions 7a85fe12eSEd Maste * are met: 8a85fe12eSEd Maste * 1. Redistributions of source code must retain the above copyright 9a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer. 10a85fe12eSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 11a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer in the 12a85fe12eSEd Maste * documentation and/or other materials provided with the distribution. 13a85fe12eSEd Maste * 14a85fe12eSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a85fe12eSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a85fe12eSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a85fe12eSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a85fe12eSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a85fe12eSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a85fe12eSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a85fe12eSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a85fe12eSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a85fe12eSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a85fe12eSEd Maste * SUCH DAMAGE. 25a85fe12eSEd Maste */ 26a85fe12eSEd Maste 27a85fe12eSEd Maste #include <sys/param.h> 28af843291SMark Johnston #include <sys/tree.h> 291d954fedSMark Johnston 301d954fedSMark Johnston #include <capsicum_helpers.h> 31a85fe12eSEd Maste #include <dwarf.h> 32a85fe12eSEd Maste #include <err.h> 33a85fe12eSEd Maste #include <fcntl.h> 34a85fe12eSEd Maste #include <gelf.h> 35a85fe12eSEd Maste #include <getopt.h> 36a85fe12eSEd Maste #include <libdwarf.h> 37a85fe12eSEd Maste #include <libelftc.h> 38a85fe12eSEd Maste #include <libgen.h> 39fe91dd01SEd Maste #include <stdbool.h> 40a85fe12eSEd Maste #include <stdio.h> 41a85fe12eSEd Maste #include <stdlib.h> 42a85fe12eSEd Maste #include <string.h> 43a85fe12eSEd Maste 44a85fe12eSEd Maste #include "_elftc.h" 45a85fe12eSEd Maste 46d003e0d7SEd Maste ELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $"); 4795fd7f26SEd Maste 4895fd7f26SEd Maste struct Func { 4995fd7f26SEd Maste char *name; 5095fd7f26SEd Maste Dwarf_Unsigned lopc; 5195fd7f26SEd Maste Dwarf_Unsigned hipc; 5295fd7f26SEd Maste Dwarf_Unsigned call_file; 5395fd7f26SEd Maste Dwarf_Unsigned call_line; 5495fd7f26SEd Maste Dwarf_Ranges *ranges; 5595fd7f26SEd Maste Dwarf_Signed ranges_cnt; 5695fd7f26SEd Maste struct Func *inlined_caller; 5795fd7f26SEd Maste STAILQ_ENTRY(Func) next; 5895fd7f26SEd Maste }; 5995fd7f26SEd Maste 60*a3617993SEd Maste struct range { 61*a3617993SEd Maste RB_ENTRY(range) entry; 6295fd7f26SEd Maste Dwarf_Off off; 6395fd7f26SEd Maste Dwarf_Unsigned lopc; 6495fd7f26SEd Maste Dwarf_Unsigned hipc; 6595fd7f26SEd Maste char **srcfiles; 6695fd7f26SEd Maste Dwarf_Signed nsrcfiles; 6795fd7f26SEd Maste STAILQ_HEAD(, Func) funclist; 68af843291SMark Johnston Dwarf_Die die; 696c4a4f1bSEd Maste Dwarf_Debug dbg; 7095fd7f26SEd Maste }; 71a85fe12eSEd Maste 72a85fe12eSEd Maste static struct option longopts[] = { 7395fd7f26SEd Maste {"addresses", no_argument, NULL, 'a'}, 74a85fe12eSEd Maste {"target" , required_argument, NULL, 'b'}, 75a85fe12eSEd Maste {"demangle", no_argument, NULL, 'C'}, 76a85fe12eSEd Maste {"exe", required_argument, NULL, 'e'}, 77a85fe12eSEd Maste {"functions", no_argument, NULL, 'f'}, 7895fd7f26SEd Maste {"inlines", no_argument, NULL, 'i'}, 79a85fe12eSEd Maste {"section", required_argument, NULL, 'j'}, 8095fd7f26SEd Maste {"pretty-print", no_argument, NULL, 'p'}, 81a85fe12eSEd Maste {"basename", no_argument, NULL, 's'}, 82a85fe12eSEd Maste {"help", no_argument, NULL, 'H'}, 83a85fe12eSEd Maste {"version", no_argument, NULL, 'V'}, 84a85fe12eSEd Maste {NULL, 0, NULL, 0} 85a85fe12eSEd Maste }; 86af843291SMark Johnston 8795fd7f26SEd Maste static int demangle, func, base, inlines, print_addr, pretty_print; 88a85fe12eSEd Maste static char unknown[] = { '?', '?', '\0' }; 89a85fe12eSEd Maste static Dwarf_Addr section_base; 90af843291SMark Johnston /* Need a new curlopc that stores last lopc value. */ 91af843291SMark Johnston static Dwarf_Unsigned curlopc = ~0ULL; 92*a3617993SEd Maste static RB_HEAD(cutree, range) cuhead = RB_INITIALIZER(&cuhead); 93af843291SMark Johnston 94af843291SMark Johnston static int 95*a3617993SEd Maste lopccmp(struct range *e1, struct range *e2) 96af843291SMark Johnston { 97af843291SMark Johnston return (e1->lopc < e2->lopc ? -1 : e1->lopc > e2->lopc); 98af843291SMark Johnston } 99af843291SMark Johnston 100*a3617993SEd Maste RB_PROTOTYPE(cutree, range, entry, lopccmp); 101*a3617993SEd Maste RB_GENERATE(cutree, range, entry, lopccmp) 102a85fe12eSEd Maste 103a85fe12eSEd Maste #define USAGE_MESSAGE "\ 104a85fe12eSEd Maste Usage: %s [options] hexaddress...\n\ 105a85fe12eSEd Maste Map program addresses to source file names and line numbers.\n\n\ 106a85fe12eSEd Maste Options:\n\ 10795fd7f26SEd Maste -a | --addresses Display address prior to line number info.\n\ 108a85fe12eSEd Maste -b TGT | --target=TGT (Accepted but ignored).\n\ 109656f49f8SEd Maste -e EXE | --exe=EXE Use program \"EXE\" to translate addresses.\n\ 110a85fe12eSEd Maste -f | --functions Display function names.\n\ 11195fd7f26SEd Maste -i | --inlines Display caller info for inlined functions.\n\ 112a85fe12eSEd Maste -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ 11395fd7f26SEd Maste -p | --pretty-print Display line number info and function name\n\ 11495fd7f26SEd Maste in human readable manner.\n\ 115a85fe12eSEd Maste -s | --basename Only show the base name for each file name.\n\ 116a85fe12eSEd Maste -C | --demangle Demangle C++ names.\n\ 117a85fe12eSEd Maste -H | --help Print a help message.\n\ 118a85fe12eSEd Maste -V | --version Print a version identifier and exit.\n" 119a85fe12eSEd Maste 120a85fe12eSEd Maste static void 121a85fe12eSEd Maste usage(void) 122a85fe12eSEd Maste { 123a85fe12eSEd Maste (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 124a85fe12eSEd Maste exit(1); 125a85fe12eSEd Maste } 126a85fe12eSEd Maste 127a85fe12eSEd Maste static void 128a85fe12eSEd Maste version(void) 129a85fe12eSEd Maste { 130a85fe12eSEd Maste 131a85fe12eSEd Maste fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 132a85fe12eSEd Maste exit(0); 133a85fe12eSEd Maste } 134a85fe12eSEd Maste 135b00fe64fSEd Maste /* 136b00fe64fSEd Maste * Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't 137b00fe64fSEd Maste * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1) 138b00fe64fSEd Maste * generate DW_AT_high_pc as an offset from DW_AT_low_pc. 139b00fe64fSEd Maste * 140b00fe64fSEd Maste * "If the value of the DW_AT_high_pc is of class address, it is the 141b00fe64fSEd Maste * relocated address of the first location past the last instruction 142b00fe64fSEd Maste * associated with the entity; if it is of class constant, the value 143b00fe64fSEd Maste * is an unsigned integer offset which when added to the low PC gives 144b00fe64fSEd Maste * the address of the first location past the last instruction 145b00fe64fSEd Maste * associated with the entity." 146b00fe64fSEd Maste * 147b00fe64fSEd Maste * DWARF4 spec, section 2.17.2. 148b00fe64fSEd Maste */ 149b00fe64fSEd Maste static int 150b00fe64fSEd Maste handle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc) 151b00fe64fSEd Maste { 152b00fe64fSEd Maste Dwarf_Error de; 153b00fe64fSEd Maste Dwarf_Half form; 154b00fe64fSEd Maste Dwarf_Attribute at; 155b00fe64fSEd Maste int ret; 156b00fe64fSEd Maste 157b00fe64fSEd Maste ret = dwarf_attr(die, DW_AT_high_pc, &at, &de); 158b00fe64fSEd Maste if (ret == DW_DLV_ERROR) { 159b00fe64fSEd Maste warnx("dwarf_attr failed: %s", dwarf_errmsg(de)); 160b00fe64fSEd Maste return (ret); 161b00fe64fSEd Maste } 162b00fe64fSEd Maste ret = dwarf_whatform(at, &form, &de); 163b00fe64fSEd Maste if (ret == DW_DLV_ERROR) { 164b00fe64fSEd Maste warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); 165b00fe64fSEd Maste return (ret); 166b00fe64fSEd Maste } 167b00fe64fSEd Maste if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT) 168b00fe64fSEd Maste *hipc += lopc; 169b00fe64fSEd Maste 170b00fe64fSEd Maste return (DW_DLV_OK); 171b00fe64fSEd Maste } 172b00fe64fSEd Maste 17395fd7f26SEd Maste static struct Func * 174*a3617993SEd Maste search_func(struct range *range, Dwarf_Unsigned addr) 175a85fe12eSEd Maste { 17695fd7f26SEd Maste struct Func *f, *f0; 17795fd7f26SEd Maste Dwarf_Unsigned lopc, hipc, addr_base; 17895fd7f26SEd Maste int i; 17995fd7f26SEd Maste 18095fd7f26SEd Maste f0 = NULL; 18195fd7f26SEd Maste 182*a3617993SEd Maste STAILQ_FOREACH(f, &range->funclist, next) { 18395fd7f26SEd Maste if (f->ranges != NULL) { 18495fd7f26SEd Maste addr_base = 0; 18595fd7f26SEd Maste for (i = 0; i < f->ranges_cnt; i++) { 18695fd7f26SEd Maste if (f->ranges[i].dwr_type == DW_RANGES_END) 18795fd7f26SEd Maste break; 18895fd7f26SEd Maste if (f->ranges[i].dwr_type == 18995fd7f26SEd Maste DW_RANGES_ADDRESS_SELECTION) { 19095fd7f26SEd Maste addr_base = f->ranges[i].dwr_addr2; 19195fd7f26SEd Maste continue; 19295fd7f26SEd Maste } 19395fd7f26SEd Maste 19495fd7f26SEd Maste /* DW_RANGES_ENTRY */ 19595fd7f26SEd Maste lopc = f->ranges[i].dwr_addr1 + addr_base; 19695fd7f26SEd Maste hipc = f->ranges[i].dwr_addr2 + addr_base; 19795fd7f26SEd Maste if (addr >= lopc && addr < hipc) { 19895fd7f26SEd Maste if (f0 == NULL || 19995fd7f26SEd Maste (lopc >= f0->lopc && 20095fd7f26SEd Maste hipc <= f0->hipc)) { 20195fd7f26SEd Maste f0 = f; 20295fd7f26SEd Maste f0->lopc = lopc; 20395fd7f26SEd Maste f0->hipc = hipc; 20495fd7f26SEd Maste break; 20595fd7f26SEd Maste } 20695fd7f26SEd Maste } 20795fd7f26SEd Maste } 20895fd7f26SEd Maste } else if (addr >= f->lopc && addr < f->hipc) { 20995fd7f26SEd Maste if (f0 == NULL || 21095fd7f26SEd Maste (f->lopc >= f0->lopc && f->hipc <= f0->hipc)) 21195fd7f26SEd Maste f0 = f; 21295fd7f26SEd Maste } 21395fd7f26SEd Maste } 21495fd7f26SEd Maste 21595fd7f26SEd Maste return (f0); 21695fd7f26SEd Maste } 21795fd7f26SEd Maste 21895fd7f26SEd Maste static void 219*a3617993SEd Maste collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, 220*a3617993SEd Maste struct range *range) 22195fd7f26SEd Maste { 22295fd7f26SEd Maste Dwarf_Die ret_die, abst_die, spec_die; 223a85fe12eSEd Maste Dwarf_Error de; 224a85fe12eSEd Maste Dwarf_Half tag; 22595fd7f26SEd Maste Dwarf_Unsigned lopc, hipc, ranges_off; 22695fd7f26SEd Maste Dwarf_Signed ranges_cnt; 227a85fe12eSEd Maste Dwarf_Off ref; 22895fd7f26SEd Maste Dwarf_Attribute abst_at, spec_at; 22995fd7f26SEd Maste Dwarf_Ranges *ranges; 23095fd7f26SEd Maste const char *funcname; 23195fd7f26SEd Maste struct Func *f; 23295fd7f26SEd Maste int found_ranges, ret; 233a85fe12eSEd Maste 23495fd7f26SEd Maste f = NULL; 23595fd7f26SEd Maste abst_die = spec_die = NULL; 236a85fe12eSEd Maste 237a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de)) { 238a85fe12eSEd Maste warnx("dwarf_tag: %s", dwarf_errmsg(de)); 239a85fe12eSEd Maste goto cont_search; 240a85fe12eSEd Maste } 24195fd7f26SEd Maste if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || 242*a3617993SEd Maste tag == DW_TAG_inlined_subroutine || tag == DW_TAG_label) { 24395fd7f26SEd Maste /* 24495fd7f26SEd Maste * Function address range can be specified by either 24595fd7f26SEd Maste * a DW_AT_ranges attribute which points to a range list or 24695fd7f26SEd Maste * by a pair of DW_AT_low_pc and DW_AT_high_pc attributes. 24795fd7f26SEd Maste */ 24895fd7f26SEd Maste ranges = NULL; 24995fd7f26SEd Maste ranges_cnt = 0; 25095fd7f26SEd Maste found_ranges = 0; 25195fd7f26SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, 25295fd7f26SEd Maste &de) == DW_DLV_OK && 25395fd7f26SEd Maste dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges, 25495fd7f26SEd Maste &ranges_cnt, NULL, &de) == DW_DLV_OK) { 25595fd7f26SEd Maste if (ranges != NULL && ranges_cnt > 0) { 25695fd7f26SEd Maste found_ranges = 1; 25795fd7f26SEd Maste goto get_func_name; 25895fd7f26SEd Maste } 25995fd7f26SEd Maste } 26095fd7f26SEd Maste 26195fd7f26SEd Maste /* 262*a3617993SEd Maste * Ranges pointer not found. Search for DW_AT_low_pc, and 263*a3617993SEd Maste * DW_AT_high_pc iff die is not a label. Labels doesn't have 264*a3617993SEd Maste * hipc attr. */ 265*a3617993SEd Maste if (tag == DW_TAG_label) { 266*a3617993SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, 267*a3617993SEd Maste &de) != DW_DLV_OK) 268*a3617993SEd Maste goto cont_search; 269*a3617993SEd Maste } else { 270*a3617993SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, 271*a3617993SEd Maste &de) || dwarf_attrval_unsigned(die, DW_AT_high_pc, 272*a3617993SEd Maste &hipc, &de)) 273a85fe12eSEd Maste goto cont_search; 274b00fe64fSEd Maste if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) 275b00fe64fSEd Maste goto cont_search; 276*a3617993SEd Maste } 277a85fe12eSEd Maste 27895fd7f26SEd Maste get_func_name: 27995fd7f26SEd Maste /* 28095fd7f26SEd Maste * Most common case the function name is stored in DW_AT_name 28195fd7f26SEd Maste * attribute. 28295fd7f26SEd Maste */ 28395fd7f26SEd Maste if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) == 28495fd7f26SEd Maste DW_DLV_OK) 28595fd7f26SEd Maste goto add_func; 286a85fe12eSEd Maste 28795fd7f26SEd Maste /* 28895fd7f26SEd Maste * For inlined function, the actual name is probably in the DIE 28995fd7f26SEd Maste * referenced by DW_AT_abstract_origin. (if present) 29095fd7f26SEd Maste */ 29195fd7f26SEd Maste if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) == 29295fd7f26SEd Maste DW_DLV_OK && 29395fd7f26SEd Maste dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK && 29495fd7f26SEd Maste dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK && 29595fd7f26SEd Maste dwarf_attrval_string(abst_die, DW_AT_name, &funcname, 29695fd7f26SEd Maste &de) == DW_DLV_OK) 29795fd7f26SEd Maste goto add_func; 298a85fe12eSEd Maste 299a85fe12eSEd Maste /* 300a85fe12eSEd Maste * If DW_AT_name is not present, but DW_AT_specification is 301a85fe12eSEd Maste * present, then probably the actual name is in the DIE 302a85fe12eSEd Maste * referenced by DW_AT_specification. 303a85fe12eSEd Maste */ 30495fd7f26SEd Maste if (dwarf_attr(die, DW_AT_specification, &spec_at, &de) == 30595fd7f26SEd Maste DW_DLV_OK && 30695fd7f26SEd Maste dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK && 30795fd7f26SEd Maste dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK && 30895fd7f26SEd Maste dwarf_attrval_string(spec_die, DW_AT_name, &funcname, 30995fd7f26SEd Maste &de) == DW_DLV_OK) 31095fd7f26SEd Maste goto add_func; 311a85fe12eSEd Maste 312b6b6f9ccSEd Maste /* Skip if no name associated with this DIE. */ 31395fd7f26SEd Maste goto cont_search; 31495fd7f26SEd Maste 31595fd7f26SEd Maste add_func: 31695fd7f26SEd Maste if ((f = calloc(1, sizeof(*f))) == NULL) 31795fd7f26SEd Maste err(EXIT_FAILURE, "calloc"); 31895fd7f26SEd Maste if ((f->name = strdup(funcname)) == NULL) 31995fd7f26SEd Maste err(EXIT_FAILURE, "strdup"); 32095fd7f26SEd Maste if (found_ranges) { 32195fd7f26SEd Maste f->ranges = ranges; 32295fd7f26SEd Maste f->ranges_cnt = ranges_cnt; 32395fd7f26SEd Maste } else { 32495fd7f26SEd Maste f->lopc = lopc; 32595fd7f26SEd Maste f->hipc = hipc; 32695fd7f26SEd Maste } 32795fd7f26SEd Maste if (tag == DW_TAG_inlined_subroutine) { 32895fd7f26SEd Maste f->inlined_caller = parent; 32995fd7f26SEd Maste dwarf_attrval_unsigned(die, DW_AT_call_file, 33095fd7f26SEd Maste &f->call_file, &de); 33195fd7f26SEd Maste dwarf_attrval_unsigned(die, DW_AT_call_line, 33295fd7f26SEd Maste &f->call_line, &de); 33395fd7f26SEd Maste } 334*a3617993SEd Maste STAILQ_INSERT_TAIL(&range->funclist, f, next); 335a85fe12eSEd Maste } 336a85fe12eSEd Maste 337a85fe12eSEd Maste cont_search: 338a85fe12eSEd Maste 339a85fe12eSEd Maste /* Search children. */ 340a85fe12eSEd Maste ret = dwarf_child(die, &ret_die, &de); 341a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 34295fd7f26SEd Maste warnx("dwarf_child: %s", dwarf_errmsg(de)); 34395fd7f26SEd Maste else if (ret == DW_DLV_OK) { 34495fd7f26SEd Maste if (f != NULL) 345*a3617993SEd Maste collect_func(dbg, ret_die, f, range); 34695fd7f26SEd Maste else 347*a3617993SEd Maste collect_func(dbg, ret_die, parent, range); 34895fd7f26SEd Maste } 349a85fe12eSEd Maste 350a85fe12eSEd Maste /* Search sibling. */ 351a85fe12eSEd Maste ret = dwarf_siblingof(dbg, die, &ret_die, &de); 352a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 35395fd7f26SEd Maste warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); 354a85fe12eSEd Maste else if (ret == DW_DLV_OK) 355*a3617993SEd Maste collect_func(dbg, ret_die, parent, range); 356656f49f8SEd Maste 35795fd7f26SEd Maste /* Cleanup */ 358*a3617993SEd Maste if (die != range->die) 359656f49f8SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 36095fd7f26SEd Maste 36195fd7f26SEd Maste if (abst_die != NULL) 36295fd7f26SEd Maste dwarf_dealloc(dbg, abst_die, DW_DLA_DIE); 36395fd7f26SEd Maste 36495fd7f26SEd Maste if (spec_die != NULL) 36595fd7f26SEd Maste dwarf_dealloc(dbg, spec_die, DW_DLA_DIE); 366a85fe12eSEd Maste } 367a85fe12eSEd Maste 368a85fe12eSEd Maste static void 369*a3617993SEd Maste print_inlines(struct range *range, struct Func *f, Dwarf_Unsigned call_file, 37095fd7f26SEd Maste Dwarf_Unsigned call_line) 37195fd7f26SEd Maste { 37295fd7f26SEd Maste char demangled[1024]; 37395fd7f26SEd Maste char *file; 37495fd7f26SEd Maste 375*a3617993SEd Maste if (call_file > 0 && (Dwarf_Signed) call_file <= range->nsrcfiles) 376*a3617993SEd Maste file = range->srcfiles[call_file - 1]; 37795fd7f26SEd Maste else 37895fd7f26SEd Maste file = unknown; 37995fd7f26SEd Maste 38095fd7f26SEd Maste if (pretty_print) 38195fd7f26SEd Maste printf(" (inlined by) "); 38295fd7f26SEd Maste 38395fd7f26SEd Maste if (func) { 38495fd7f26SEd Maste if (demangle && !elftc_demangle(f->name, demangled, 38595fd7f26SEd Maste sizeof(demangled), 0)) { 38695fd7f26SEd Maste if (pretty_print) 38795fd7f26SEd Maste printf("%s at ", demangled); 38895fd7f26SEd Maste else 38995fd7f26SEd Maste printf("%s\n", demangled); 39095fd7f26SEd Maste } else { 39195fd7f26SEd Maste if (pretty_print) 39295fd7f26SEd Maste printf("%s at ", f->name); 39395fd7f26SEd Maste else 39495fd7f26SEd Maste printf("%s\n", f->name); 39595fd7f26SEd Maste } 39695fd7f26SEd Maste } 397839529caSEd Maste (void) printf("%s:%ju\n", base ? basename(file) : file, 398839529caSEd Maste (uintmax_t) call_line); 39995fd7f26SEd Maste 40095fd7f26SEd Maste if (f->inlined_caller != NULL) 401*a3617993SEd Maste print_inlines(range, f->inlined_caller, f->call_file, 40295fd7f26SEd Maste f->call_line); 40395fd7f26SEd Maste } 40495fd7f26SEd Maste 405*a3617993SEd Maste static struct range * 406af843291SMark Johnston culookup(Dwarf_Unsigned addr) 407af843291SMark Johnston { 408*a3617993SEd Maste struct range find, *res; 409af843291SMark Johnston 410af843291SMark Johnston find.lopc = addr; 41135beedaeSMark Johnston res = RB_NFIND(cutree, &cuhead, &find); 412af843291SMark Johnston if (res != NULL) { 413af843291SMark Johnston if (res->lopc != addr) 41435beedaeSMark Johnston res = RB_PREV(cutree, &cuhead, res); 415af843291SMark Johnston if (res != NULL && addr >= res->lopc && addr < res->hipc) 416af843291SMark Johnston return (res); 417af843291SMark Johnston } else { 41835beedaeSMark Johnston res = RB_MAX(cutree, &cuhead); 419af843291SMark Johnston if (res != NULL && addr >= res->lopc && addr < res->hipc) 420af843291SMark Johnston return (res); 421af843291SMark Johnston } 422af843291SMark Johnston return (NULL); 423af843291SMark Johnston } 424af843291SMark Johnston 4256c4a4f1bSEd Maste /* 426*a3617993SEd Maste * When DW_AT_ranges, DW_AT_low_pc/DW_AT_high_pc are all absent, we check the 427*a3617993SEd Maste * children of cu die for labels. If the address falls into one of the labels 428*a3617993SEd Maste * ranges(aranges), return the label DIE. 429*a3617993SEd Maste */ 430*a3617993SEd Maste static int 431*a3617993SEd Maste check_labels(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr, 432*a3617993SEd Maste struct range **range) { 433*a3617993SEd Maste Dwarf_Addr start; 434*a3617993SEd Maste Dwarf_Arange *aranges; 435*a3617993SEd Maste Dwarf_Die prev_die, ret_die; 436*a3617993SEd Maste Dwarf_Error de; 437*a3617993SEd Maste Dwarf_Half tag; 438*a3617993SEd Maste Dwarf_Off die_off; 439*a3617993SEd Maste Dwarf_Unsigned lopc, length; 440*a3617993SEd Maste Dwarf_Signed arcnt; 441*a3617993SEd Maste struct range *labelp, **labels; 442*a3617993SEd Maste int i, j, label_cnt, ret; 443*a3617993SEd Maste 444*a3617993SEd Maste prev_die = ret_die = NULL; 445*a3617993SEd Maste labels = NULL; 446*a3617993SEd Maste i = label_cnt = 0; 447*a3617993SEd Maste 448*a3617993SEd Maste /* Find aranges. */ 449*a3617993SEd Maste ret = dwarf_get_aranges(dbg, &aranges, &arcnt, &de); 450*a3617993SEd Maste if (ret != DW_DLV_OK && ret != DW_DLV_NO_ENTRY) 451*a3617993SEd Maste warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de)); 452*a3617993SEd Maste 453*a3617993SEd Maste /* Child of current CU. */ 454*a3617993SEd Maste ret = dwarf_child(die, &prev_die, &de); 455*a3617993SEd Maste if (ret == DW_DLV_ERROR) 456*a3617993SEd Maste warnx("dwarf_child: %s", dwarf_errmsg(de)); 457*a3617993SEd Maste 458*a3617993SEd Maste /* Count labels. */ 459*a3617993SEd Maste while (1) { 460*a3617993SEd Maste if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) { 461*a3617993SEd Maste warnx("dwarf_tag failed: %s", 462*a3617993SEd Maste dwarf_errmsg(de)); 463*a3617993SEd Maste return DW_DLV_ERROR; 464*a3617993SEd Maste } 465*a3617993SEd Maste if (tag == DW_TAG_label) { 466*a3617993SEd Maste if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc, 467*a3617993SEd Maste &lopc, &de) == DW_DLV_OK) 468*a3617993SEd Maste label_cnt++; 469*a3617993SEd Maste } 470*a3617993SEd Maste 471*a3617993SEd Maste if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK) 472*a3617993SEd Maste break; 473*a3617993SEd Maste 474*a3617993SEd Maste if (prev_die != NULL) 475*a3617993SEd Maste dwarf_dealloc(dbg, prev_die, DW_DLA_DIE); 476*a3617993SEd Maste prev_die = ret_die; 477*a3617993SEd Maste } 478*a3617993SEd Maste 479*a3617993SEd Maste if (label_cnt == 0) 480*a3617993SEd Maste return (DW_DLV_NO_ENTRY); 481*a3617993SEd Maste 482*a3617993SEd Maste /* Allocate space for labels. */ 483*a3617993SEd Maste if ((labels = calloc(label_cnt, sizeof(struct range *))) == NULL) 484*a3617993SEd Maste err(EXIT_FAILURE, "calloc"); 485*a3617993SEd Maste 486*a3617993SEd Maste /* Add labels to list. */ 487*a3617993SEd Maste ret = dwarf_child(die, &prev_die, &de); 488*a3617993SEd Maste if (ret == DW_DLV_ERROR) 489*a3617993SEd Maste warnx("dwarf_child: %s", dwarf_errmsg(de)); 490*a3617993SEd Maste while (1) { 491*a3617993SEd Maste if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) { 492*a3617993SEd Maste warnx("dwarf_tag failed: %s", 493*a3617993SEd Maste dwarf_errmsg(de)); 494*a3617993SEd Maste return DW_DLV_ERROR; 495*a3617993SEd Maste } 496*a3617993SEd Maste if (tag == DW_TAG_label) { 497*a3617993SEd Maste if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc, 498*a3617993SEd Maste &lopc, &de) == DW_DLV_OK) { 499*a3617993SEd Maste if (curlopc == lopc) { 500*a3617993SEd Maste for (i = 0; i < label_cnt - 1; i++) { 501*a3617993SEd Maste if (labels[i] != *range) 502*a3617993SEd Maste free(labels[i]); 503*a3617993SEd Maste } 504*a3617993SEd Maste free(labels); 505*a3617993SEd Maste return DW_DLV_ERROR; 506*a3617993SEd Maste } 507*a3617993SEd Maste labelp = calloc(1, sizeof(struct range)); 508*a3617993SEd Maste if (labelp == NULL) 509*a3617993SEd Maste err(EXIT_FAILURE, "calloc"); 510*a3617993SEd Maste labelp->lopc = lopc; 511*a3617993SEd Maste labelp->die = prev_die; 512*a3617993SEd Maste labelp->dbg = dbg; 513*a3617993SEd Maste STAILQ_INIT(&labelp->funclist); 514*a3617993SEd Maste labels[i++] = labelp; 515*a3617993SEd Maste } 516*a3617993SEd Maste } 517*a3617993SEd Maste if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK) 518*a3617993SEd Maste break; 519*a3617993SEd Maste if (prev_die != NULL && tag != DW_TAG_label) 520*a3617993SEd Maste dwarf_dealloc(dbg, prev_die, DW_DLA_DIE); 521*a3617993SEd Maste prev_die = ret_die; 522*a3617993SEd Maste } 523*a3617993SEd Maste 524*a3617993SEd Maste /* Set hipc for each label using aranges */ 525*a3617993SEd Maste for (i = 0; i < label_cnt; i++) { 526*a3617993SEd Maste for (j = 0; j < arcnt; j++) { 527*a3617993SEd Maste if (dwarf_get_arange_info(aranges[j], &start, &length, 528*a3617993SEd Maste &die_off, &de) != DW_DLV_OK) { 529*a3617993SEd Maste warnx("dwarf_get_arange_info failed: %s", 530*a3617993SEd Maste dwarf_errmsg(de)); 531*a3617993SEd Maste continue; 532*a3617993SEd Maste } 533*a3617993SEd Maste if (labels[i]->lopc == (Dwarf_Unsigned)start) { 534*a3617993SEd Maste labels[i]->hipc = start + length; 535*a3617993SEd Maste break; 536*a3617993SEd Maste } 537*a3617993SEd Maste } 538*a3617993SEd Maste } 539*a3617993SEd Maste 540*a3617993SEd Maste /* If addr in label's range, we have found the range for this label. */ 541*a3617993SEd Maste for (i = 0; i < label_cnt; i++) { 542*a3617993SEd Maste if (addr >= labels[i]->lopc && addr < labels[i]->hipc) { 543*a3617993SEd Maste *range = labels[i]; 544*a3617993SEd Maste RB_INSERT(cutree, &cuhead, (*range)); 545*a3617993SEd Maste curlopc = (*range)->lopc; 546*a3617993SEd Maste break; 547*a3617993SEd Maste } 548*a3617993SEd Maste } 549*a3617993SEd Maste 550*a3617993SEd Maste for (i = 0; i < label_cnt - 1; i++) { 551*a3617993SEd Maste if (labels[i] != *range) 552*a3617993SEd Maste free(labels[i]); 553*a3617993SEd Maste } 554*a3617993SEd Maste free(labels); 555*a3617993SEd Maste 556*a3617993SEd Maste if (*range != NULL) 557*a3617993SEd Maste return (DW_DLV_OK); 558*a3617993SEd Maste else 559*a3617993SEd Maste return (DW_DLV_NO_ENTRY); 560*a3617993SEd Maste } 561*a3617993SEd Maste 562*a3617993SEd Maste /* 563*a3617993SEd Maste * Check whether addr falls into range(s) of current CU. 564*a3617993SEd Maste * If so, save current CU to lookup tree. 5656c4a4f1bSEd Maste */ 5666c4a4f1bSEd Maste static int 5676c4a4f1bSEd Maste check_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr, 568*a3617993SEd Maste struct range **range) 5696c4a4f1bSEd Maste { 5706c4a4f1bSEd Maste Dwarf_Error de; 5716c4a4f1bSEd Maste Dwarf_Unsigned addr_base, lopc, hipc; 5726c4a4f1bSEd Maste Dwarf_Off ranges_off; 5736c4a4f1bSEd Maste Dwarf_Signed ranges_cnt; 5746c4a4f1bSEd Maste Dwarf_Ranges *ranges; 5756c4a4f1bSEd Maste int i, ret; 576*a3617993SEd Maste bool in_cu; 5776c4a4f1bSEd Maste 5786c4a4f1bSEd Maste addr_base = 0; 5796c4a4f1bSEd Maste ranges = NULL; 5806c4a4f1bSEd Maste ranges_cnt = 0; 581*a3617993SEd Maste in_cu = false; 5826c4a4f1bSEd Maste 5836c4a4f1bSEd Maste ret = dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de); 58465c20775SEd Maste if (ret == DW_DLV_OK) { 5856c4a4f1bSEd Maste ret = dwarf_get_ranges(dbg, ranges_off, &ranges, 5866c4a4f1bSEd Maste &ranges_cnt, NULL, &de); 5876c4a4f1bSEd Maste if (ret != DW_DLV_OK) 5886c4a4f1bSEd Maste return (ret); 5896c4a4f1bSEd Maste 5906c4a4f1bSEd Maste if (!ranges || ranges_cnt <= 0) 5916c4a4f1bSEd Maste return (DW_DLV_ERROR); 5926c4a4f1bSEd Maste 5936c4a4f1bSEd Maste for (i = 0; i < ranges_cnt; i++) { 5946c4a4f1bSEd Maste if (ranges[i].dwr_type == DW_RANGES_END) 5956c4a4f1bSEd Maste return (DW_DLV_NO_ENTRY); 5966c4a4f1bSEd Maste 5976c4a4f1bSEd Maste if (ranges[i].dwr_type == 5986c4a4f1bSEd Maste DW_RANGES_ADDRESS_SELECTION) { 5996c4a4f1bSEd Maste addr_base = ranges[i].dwr_addr2; 6006c4a4f1bSEd Maste continue; 6016c4a4f1bSEd Maste } 6026c4a4f1bSEd Maste 6036c4a4f1bSEd Maste /* DW_RANGES_ENTRY */ 6046c4a4f1bSEd Maste lopc = ranges[i].dwr_addr1 + addr_base; 6056c4a4f1bSEd Maste hipc = ranges[i].dwr_addr2 + addr_base; 6066c4a4f1bSEd Maste 6076c4a4f1bSEd Maste if (lopc == curlopc) 6086c4a4f1bSEd Maste return (DW_DLV_ERROR); 6096c4a4f1bSEd Maste 6106c4a4f1bSEd Maste if (addr >= lopc && addr < hipc){ 611*a3617993SEd Maste in_cu = true; 6126c4a4f1bSEd Maste break; 6136c4a4f1bSEd Maste } 6146c4a4f1bSEd Maste } 615*a3617993SEd Maste } else { 61665c20775SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) == 61765c20775SEd Maste DW_DLV_OK) { 61865c20775SEd Maste if (lopc == curlopc) 61965c20775SEd Maste return (DW_DLV_ERROR); 62065c20775SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, 62165c20775SEd Maste &de) == DW_DLV_OK) { 62265c20775SEd Maste /* 62365c20775SEd Maste * Check if the address falls into the PC 62465c20775SEd Maste * range of this CU. 62565c20775SEd Maste */ 62665c20775SEd Maste if (handle_high_pc(die, lopc, &hipc) != 62765c20775SEd Maste DW_DLV_OK) 62865c20775SEd Maste return (DW_DLV_ERROR); 62965c20775SEd Maste } else { 630*a3617993SEd Maste /* Assume ~0ULL if DW_AT_high_pc not present. */ 63165c20775SEd Maste hipc = ~0ULL; 63265c20775SEd Maste } 63365c20775SEd Maste 63465c20775SEd Maste if (addr >= lopc && addr < hipc) { 635*a3617993SEd Maste in_cu = true; 63665c20775SEd Maste } 6376c4a4f1bSEd Maste } else { 638*a3617993SEd Maste /* Addr not in range die, try labels. */ 639*a3617993SEd Maste ret = check_labels(dbg, die, addr, range); 640*a3617993SEd Maste return ret; 641*a3617993SEd Maste } 6426c4a4f1bSEd Maste } 6436c4a4f1bSEd Maste 644*a3617993SEd Maste if (in_cu) { 645*a3617993SEd Maste if ((*range = calloc(1, sizeof(struct range))) == NULL) 6466c4a4f1bSEd Maste err(EXIT_FAILURE, "calloc"); 647*a3617993SEd Maste (*range)->lopc = lopc; 648*a3617993SEd Maste (*range)->hipc = hipc; 649*a3617993SEd Maste (*range)->die = die; 650*a3617993SEd Maste (*range)->dbg = dbg; 651*a3617993SEd Maste STAILQ_INIT(&(*range)->funclist); 652*a3617993SEd Maste RB_INSERT(cutree, &cuhead, *range); 6536c4a4f1bSEd Maste curlopc = lopc; 6546c4a4f1bSEd Maste return (DW_DLV_OK); 6556c4a4f1bSEd Maste } else { 6566c4a4f1bSEd Maste return (DW_DLV_NO_ENTRY); 6576c4a4f1bSEd Maste } 6586c4a4f1bSEd Maste } 6596c4a4f1bSEd Maste 66095fd7f26SEd Maste static void 66195fd7f26SEd Maste translate(Dwarf_Debug dbg, Elf *e, const char* addrstr) 662a85fe12eSEd Maste { 663656f49f8SEd Maste Dwarf_Die die, ret_die; 664a85fe12eSEd Maste Dwarf_Line *lbuf; 665a85fe12eSEd Maste Dwarf_Error de; 666a85fe12eSEd Maste Dwarf_Half tag; 6676c4a4f1bSEd Maste Dwarf_Unsigned addr, lineno, plineno; 668a85fe12eSEd Maste Dwarf_Signed lcount; 669a85fe12eSEd Maste Dwarf_Addr lineaddr, plineaddr; 670*a3617993SEd Maste struct range *range; 67195fd7f26SEd Maste struct Func *f; 67295fd7f26SEd Maste const char *funcname; 673a85fe12eSEd Maste char *file, *file0, *pfile; 674a85fe12eSEd Maste char demangled[1024]; 67595fd7f26SEd Maste int ec, i, ret; 676a85fe12eSEd Maste 677a85fe12eSEd Maste addr = strtoull(addrstr, NULL, 16); 678a85fe12eSEd Maste addr += section_base; 679a85fe12eSEd Maste lineno = 0; 680a85fe12eSEd Maste file = unknown; 6817a2e729bSEd Maste die = NULL; 682af843291SMark Johnston ret = DW_DLV_OK; 683a85fe12eSEd Maste 684*a3617993SEd Maste range = culookup(addr); 685*a3617993SEd Maste if (range != NULL) { 686*a3617993SEd Maste die = range->die; 687*a3617993SEd Maste dbg = range->dbg; 688af843291SMark Johnston goto status_ok; 689af843291SMark Johnston } 690af843291SMark Johnston 691af843291SMark Johnston while (true) { 692af843291SMark Johnston /* 693af843291SMark Johnston * We resume the CU scan from the last place we found a match. 694af843291SMark Johnston * Because when we have 2 sequential addresses, and the second 695af843291SMark Johnston * one is of the next CU, it is faster to just go to the next CU 696af843291SMark Johnston * instead of starting from the beginning. 697af843291SMark Johnston */ 698af843291SMark Johnston ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 699af843291SMark Johnston &de); 700af843291SMark Johnston if (ret == DW_DLV_NO_ENTRY) { 701af843291SMark Johnston if (curlopc == ~0ULL) 702af843291SMark Johnston goto out; 703af843291SMark Johnston ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, 704af843291SMark Johnston NULL, &de); 705af843291SMark Johnston } 706a85fe12eSEd Maste die = NULL; 707656f49f8SEd Maste while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { 708656f49f8SEd Maste if (die != NULL) 709656f49f8SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 710656f49f8SEd Maste die = ret_die; 711a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 712a85fe12eSEd Maste warnx("dwarf_tag failed: %s", 713a85fe12eSEd Maste dwarf_errmsg(de)); 714656f49f8SEd Maste goto next_cu; 715a85fe12eSEd Maste } 716656f49f8SEd Maste 717a85fe12eSEd Maste /* XXX: What about DW_TAG_partial_unit? */ 718a85fe12eSEd Maste if (tag == DW_TAG_compile_unit) 719a85fe12eSEd Maste break; 720a85fe12eSEd Maste } 721af843291SMark Johnston 722656f49f8SEd Maste if (ret_die == NULL) { 723a85fe12eSEd Maste warnx("could not find DW_TAG_compile_unit die"); 724656f49f8SEd Maste goto next_cu; 725a85fe12eSEd Maste } 726*a3617993SEd Maste ret = check_range(dbg, die, addr, &range); 7276c4a4f1bSEd Maste if (ret == DW_DLV_OK) 72895fd7f26SEd Maste break; 7296c4a4f1bSEd Maste if (ret == DW_DLV_ERROR) 7306c4a4f1bSEd Maste goto out; 73195fd7f26SEd Maste next_cu: 73295fd7f26SEd Maste if (die != NULL) { 73395fd7f26SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 73495fd7f26SEd Maste die = NULL; 73595fd7f26SEd Maste } 73695fd7f26SEd Maste } 73795fd7f26SEd Maste 73895fd7f26SEd Maste if (ret != DW_DLV_OK || die == NULL) 73995fd7f26SEd Maste goto out; 74095fd7f26SEd Maste 741af843291SMark Johnston status_ok: 742c9dbb1ccSEd Maste switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { 743c9dbb1ccSEd Maste case DW_DLV_OK: 744c9dbb1ccSEd Maste break; 745c9dbb1ccSEd Maste case DW_DLV_NO_ENTRY: 746656f49f8SEd Maste /* If a CU lacks debug info, just skip it. */ 74795fd7f26SEd Maste goto out; 748c9dbb1ccSEd Maste default: 749a85fe12eSEd Maste warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 750a85fe12eSEd Maste goto out; 751a85fe12eSEd Maste } 752a85fe12eSEd Maste 753a85fe12eSEd Maste plineaddr = ~0ULL; 754a85fe12eSEd Maste plineno = 0; 755a85fe12eSEd Maste pfile = unknown; 756a85fe12eSEd Maste for (i = 0; i < lcount; i++) { 757a85fe12eSEd Maste if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 75895fd7f26SEd Maste warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); 759a85fe12eSEd Maste goto out; 760a85fe12eSEd Maste } 761a85fe12eSEd Maste if (dwarf_lineno(lbuf[i], &lineno, &de)) { 76295fd7f26SEd Maste warnx("dwarf_lineno: %s", dwarf_errmsg(de)); 763a85fe12eSEd Maste goto out; 764a85fe12eSEd Maste } 765a85fe12eSEd Maste if (dwarf_linesrc(lbuf[i], &file0, &de)) { 76695fd7f26SEd Maste warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); 767a85fe12eSEd Maste } else 768a85fe12eSEd Maste file = file0; 769a85fe12eSEd Maste if (addr == lineaddr) 770a85fe12eSEd Maste goto out; 771a85fe12eSEd Maste else if (addr < lineaddr && addr > plineaddr) { 772a85fe12eSEd Maste lineno = plineno; 773a85fe12eSEd Maste file = pfile; 774a85fe12eSEd Maste goto out; 775a85fe12eSEd Maste } 776a85fe12eSEd Maste plineaddr = lineaddr; 777a85fe12eSEd Maste plineno = lineno; 778a85fe12eSEd Maste pfile = file; 779a85fe12eSEd Maste } 780a85fe12eSEd Maste 781a85fe12eSEd Maste out: 78295fd7f26SEd Maste f = NULL; 783a85fe12eSEd Maste funcname = NULL; 784*a3617993SEd Maste if (ret == DW_DLV_OK && (func || inlines) && range != NULL) { 785*a3617993SEd Maste if (range->srcfiles == NULL) 786*a3617993SEd Maste if (dwarf_srcfiles(die, &range->srcfiles, 787*a3617993SEd Maste &range->nsrcfiles, &de)) 78895fd7f26SEd Maste warnx("dwarf_srcfiles: %s", dwarf_errmsg(de)); 789*a3617993SEd Maste if (STAILQ_EMPTY(&range->funclist)) { 790*a3617993SEd Maste collect_func(dbg, range->die, NULL, range); 791656f49f8SEd Maste die = NULL; 792656f49f8SEd Maste } 793*a3617993SEd Maste f = search_func(range, addr); 79495fd7f26SEd Maste if (f != NULL) 79595fd7f26SEd Maste funcname = f->name; 79695fd7f26SEd Maste } 79795fd7f26SEd Maste 79895fd7f26SEd Maste if (print_addr) { 79995fd7f26SEd Maste if ((ec = gelf_getclass(e)) == ELFCLASSNONE) { 80095fd7f26SEd Maste warnx("gelf_getclass failed: %s", elf_errmsg(-1)); 80195fd7f26SEd Maste ec = ELFCLASS64; 80295fd7f26SEd Maste } 80395fd7f26SEd Maste if (ec == ELFCLASS32) { 80495fd7f26SEd Maste if (pretty_print) 80595fd7f26SEd Maste printf("0x%08jx: ", (uintmax_t) addr); 80695fd7f26SEd Maste else 80795fd7f26SEd Maste printf("0x%08jx\n", (uintmax_t) addr); 80895fd7f26SEd Maste } else { 80995fd7f26SEd Maste if (pretty_print) 81095fd7f26SEd Maste printf("0x%016jx: ", (uintmax_t) addr); 81195fd7f26SEd Maste else 81295fd7f26SEd Maste printf("0x%016jx\n", (uintmax_t) addr); 81395fd7f26SEd Maste } 81495fd7f26SEd Maste } 815a85fe12eSEd Maste 816a85fe12eSEd Maste if (func) { 817a85fe12eSEd Maste if (funcname == NULL) 81895fd7f26SEd Maste funcname = unknown; 81995fd7f26SEd Maste if (demangle && !elftc_demangle(funcname, demangled, 82095fd7f26SEd Maste sizeof(demangled), 0)) { 82195fd7f26SEd Maste if (pretty_print) 82295fd7f26SEd Maste printf("%s at ", demangled); 82395fd7f26SEd Maste else 824a85fe12eSEd Maste printf("%s\n", demangled); 82595fd7f26SEd Maste } else { 82695fd7f26SEd Maste if (pretty_print) 82795fd7f26SEd Maste printf("%s at ", funcname); 828a85fe12eSEd Maste else 829a85fe12eSEd Maste printf("%s\n", funcname); 83095fd7f26SEd Maste } 831a85fe12eSEd Maste } 832a85fe12eSEd Maste 833839529caSEd Maste (void) printf("%s:%ju\n", base ? basename(file) : file, 834839529caSEd Maste (uintmax_t) lineno); 835a85fe12eSEd Maste 836*a3617993SEd Maste if (ret == DW_DLV_OK && inlines && range != NULL && 837*a3617993SEd Maste range->srcfiles != NULL && f != NULL && f->inlined_caller != NULL) 838*a3617993SEd Maste print_inlines(range, f->inlined_caller, f->call_file, 83995fd7f26SEd Maste f->call_line); 840a85fe12eSEd Maste } 841a85fe12eSEd Maste 842a85fe12eSEd Maste static void 843a85fe12eSEd Maste find_section_base(const char *exe, Elf *e, const char *section) 844a85fe12eSEd Maste { 845a85fe12eSEd Maste Dwarf_Addr off; 846a85fe12eSEd Maste Elf_Scn *scn; 847a85fe12eSEd Maste GElf_Ehdr eh; 848a85fe12eSEd Maste GElf_Shdr sh; 849a85fe12eSEd Maste size_t shstrndx; 850a85fe12eSEd Maste int elferr; 851a85fe12eSEd Maste const char *name; 852a85fe12eSEd Maste 853a85fe12eSEd Maste if (gelf_getehdr(e, &eh) != &eh) { 854a85fe12eSEd Maste warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 855a85fe12eSEd Maste return; 856a85fe12eSEd Maste } 857a85fe12eSEd Maste 858a85fe12eSEd Maste if (!elf_getshstrndx(e, &shstrndx)) { 859a85fe12eSEd Maste warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 860a85fe12eSEd Maste return; 861a85fe12eSEd Maste } 862a85fe12eSEd Maste 863a85fe12eSEd Maste (void) elf_errno(); 864a85fe12eSEd Maste off = 0; 865a85fe12eSEd Maste scn = NULL; 866a85fe12eSEd Maste while ((scn = elf_nextscn(e, scn)) != NULL) { 867a85fe12eSEd Maste if (gelf_getshdr(scn, &sh) == NULL) { 868a85fe12eSEd Maste warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 869a85fe12eSEd Maste continue; 870a85fe12eSEd Maste } 871a85fe12eSEd Maste if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) 872a85fe12eSEd Maste goto next; 873a85fe12eSEd Maste if (!strcmp(section, name)) { 874a85fe12eSEd Maste if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { 875a85fe12eSEd Maste /* 876a85fe12eSEd Maste * For executables, section base is the virtual 877a85fe12eSEd Maste * address of the specified section. 878a85fe12eSEd Maste */ 879a85fe12eSEd Maste section_base = sh.sh_addr; 880a85fe12eSEd Maste } else if (eh.e_type == ET_REL) { 881a85fe12eSEd Maste /* 882a85fe12eSEd Maste * For relocatables, section base is the 883a85fe12eSEd Maste * relative offset of the specified section 884a85fe12eSEd Maste * to the start of the first section. 885a85fe12eSEd Maste */ 886a85fe12eSEd Maste section_base = off; 887a85fe12eSEd Maste } else 888a85fe12eSEd Maste warnx("unknown e_type %u", eh.e_type); 889a85fe12eSEd Maste return; 890a85fe12eSEd Maste } 891a85fe12eSEd Maste next: 892a85fe12eSEd Maste off += sh.sh_size; 893a85fe12eSEd Maste } 894a85fe12eSEd Maste elferr = elf_errno(); 895a85fe12eSEd Maste if (elferr != 0) 896a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 897a85fe12eSEd Maste 898a85fe12eSEd Maste errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); 899a85fe12eSEd Maste } 900a85fe12eSEd Maste 901a85fe12eSEd Maste int 902a85fe12eSEd Maste main(int argc, char **argv) 903a85fe12eSEd Maste { 9041d954fedSMark Johnston cap_rights_t rights; 905a85fe12eSEd Maste Elf *e; 906a85fe12eSEd Maste Dwarf_Debug dbg; 907a85fe12eSEd Maste Dwarf_Error de; 908a85fe12eSEd Maste const char *exe, *section; 909a85fe12eSEd Maste char line[1024]; 910a85fe12eSEd Maste int fd, i, opt; 911a85fe12eSEd Maste 912a85fe12eSEd Maste exe = NULL; 913a85fe12eSEd Maste section = NULL; 91495fd7f26SEd Maste while ((opt = getopt_long(argc, argv, "ab:Ce:fij:psHV", longopts, 91595fd7f26SEd Maste NULL)) != -1) { 916a85fe12eSEd Maste switch (opt) { 91795fd7f26SEd Maste case 'a': 91895fd7f26SEd Maste print_addr = 1; 91995fd7f26SEd Maste break; 920a85fe12eSEd Maste case 'b': 921a85fe12eSEd Maste /* ignored */ 922a85fe12eSEd Maste break; 923a85fe12eSEd Maste case 'C': 924a85fe12eSEd Maste demangle = 1; 925a85fe12eSEd Maste break; 926a85fe12eSEd Maste case 'e': 927a85fe12eSEd Maste exe = optarg; 928a85fe12eSEd Maste break; 929a85fe12eSEd Maste case 'f': 930a85fe12eSEd Maste func = 1; 931a85fe12eSEd Maste break; 93295fd7f26SEd Maste case 'i': 93395fd7f26SEd Maste inlines = 1; 93495fd7f26SEd Maste break; 935a85fe12eSEd Maste case 'j': 936a85fe12eSEd Maste section = optarg; 937a85fe12eSEd Maste break; 93895fd7f26SEd Maste case 'p': 93995fd7f26SEd Maste pretty_print = 1; 94095fd7f26SEd Maste break; 941a85fe12eSEd Maste case 's': 942a85fe12eSEd Maste base = 1; 943a85fe12eSEd Maste break; 944a85fe12eSEd Maste case 'H': 945a85fe12eSEd Maste usage(); 946a85fe12eSEd Maste case 'V': 947a85fe12eSEd Maste version(); 948a85fe12eSEd Maste default: 949a85fe12eSEd Maste usage(); 950a85fe12eSEd Maste } 951a85fe12eSEd Maste } 952a85fe12eSEd Maste 953a85fe12eSEd Maste argv += optind; 954a85fe12eSEd Maste argc -= optind; 955a85fe12eSEd Maste 956a85fe12eSEd Maste if (exe == NULL) 957a85fe12eSEd Maste exe = "a.out"; 958a85fe12eSEd Maste 959a85fe12eSEd Maste if ((fd = open(exe, O_RDONLY)) < 0) 960a85fe12eSEd Maste err(EXIT_FAILURE, "%s", exe); 961a85fe12eSEd Maste 9621d954fedSMark Johnston if (caph_rights_limit(fd, cap_rights_init(&rights, CAP_FSTAT, 9631d954fedSMark Johnston CAP_MMAP_R)) < 0) 9641d954fedSMark Johnston errx(EXIT_FAILURE, "caph_rights_limit"); 9651d954fedSMark Johnston 9661d954fedSMark Johnston caph_cache_catpages(); 9671d954fedSMark Johnston if (caph_limit_stdio() < 0) 9681d954fedSMark Johnston errx(EXIT_FAILURE, "failed to limit stdio rights"); 9691d954fedSMark Johnston if (caph_enter() < 0) 9701d954fedSMark Johnston errx(EXIT_FAILURE, "failed to enter capability mode"); 9711d954fedSMark Johnston 972a85fe12eSEd Maste if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) 973a85fe12eSEd Maste errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); 974a85fe12eSEd Maste 975a85fe12eSEd Maste if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) 976a85fe12eSEd Maste errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); 977a85fe12eSEd Maste 978a85fe12eSEd Maste if (section) 979a85fe12eSEd Maste find_section_base(exe, e, section); 980a85fe12eSEd Maste else 981a85fe12eSEd Maste section_base = 0; 982a85fe12eSEd Maste 983a85fe12eSEd Maste if (argc > 0) 984a85fe12eSEd Maste for (i = 0; i < argc; i++) 98595fd7f26SEd Maste translate(dbg, e, argv[i]); 986bee2765cSEd Maste else { 987bee2765cSEd Maste setvbuf(stdout, NULL, _IOLBF, 0); 988bee2765cSEd Maste while (fgets(line, sizeof(line), stdin) != NULL) 98995fd7f26SEd Maste translate(dbg, e, line); 990a7265433SEd Maste } 991a85fe12eSEd Maste 992a85fe12eSEd Maste dwarf_finish(dbg, &de); 993a85fe12eSEd Maste 994a85fe12eSEd Maste (void) elf_end(e); 995a85fe12eSEd Maste 996a85fe12eSEd Maste exit(0); 997a85fe12eSEd Maste } 998