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 6095fd7f26SEd Maste struct CU { 61af843291SMark Johnston RB_ENTRY(CU) 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; 9235beedaeSMark Johnston static RB_HEAD(cutree, CU) cuhead = RB_INITIALIZER(&cuhead); 93af843291SMark Johnston 94af843291SMark Johnston static int 95af843291SMark Johnston lopccmp(struct CU *e1, struct CU *e2) 96af843291SMark Johnston { 97af843291SMark Johnston return (e1->lopc < e2->lopc ? -1 : e1->lopc > e2->lopc); 98af843291SMark Johnston } 99af843291SMark Johnston 100af843291SMark Johnston RB_PROTOTYPE(cutree, CU, entry, lopccmp); 101af843291SMark Johnston RB_GENERATE(cutree, CU, 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 * 17495fd7f26SEd Maste search_func(struct CU *cu, 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 18295fd7f26SEd Maste STAILQ_FOREACH(f, &cu->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 21995fd7f26SEd Maste collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu) 22095fd7f26SEd Maste { 22195fd7f26SEd Maste Dwarf_Die ret_die, abst_die, spec_die; 222a85fe12eSEd Maste Dwarf_Error de; 223a85fe12eSEd Maste Dwarf_Half tag; 22495fd7f26SEd Maste Dwarf_Unsigned lopc, hipc, ranges_off; 22595fd7f26SEd Maste Dwarf_Signed ranges_cnt; 226a85fe12eSEd Maste Dwarf_Off ref; 22795fd7f26SEd Maste Dwarf_Attribute abst_at, spec_at; 22895fd7f26SEd Maste Dwarf_Ranges *ranges; 22995fd7f26SEd Maste const char *funcname; 23095fd7f26SEd Maste struct Func *f; 23195fd7f26SEd Maste int found_ranges, ret; 232a85fe12eSEd Maste 23395fd7f26SEd Maste f = NULL; 23495fd7f26SEd Maste abst_die = spec_die = NULL; 235a85fe12eSEd Maste 236a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de)) { 237a85fe12eSEd Maste warnx("dwarf_tag: %s", dwarf_errmsg(de)); 238a85fe12eSEd Maste goto cont_search; 239a85fe12eSEd Maste } 24095fd7f26SEd Maste if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || 24195fd7f26SEd Maste tag == DW_TAG_inlined_subroutine) { 24295fd7f26SEd Maste /* 24395fd7f26SEd Maste * Function address range can be specified by either 24495fd7f26SEd Maste * a DW_AT_ranges attribute which points to a range list or 24595fd7f26SEd Maste * by a pair of DW_AT_low_pc and DW_AT_high_pc attributes. 24695fd7f26SEd Maste */ 24795fd7f26SEd Maste ranges = NULL; 24895fd7f26SEd Maste ranges_cnt = 0; 24995fd7f26SEd Maste found_ranges = 0; 25095fd7f26SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, 25195fd7f26SEd Maste &de) == DW_DLV_OK && 25295fd7f26SEd Maste dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges, 25395fd7f26SEd Maste &ranges_cnt, NULL, &de) == DW_DLV_OK) { 25495fd7f26SEd Maste if (ranges != NULL && ranges_cnt > 0) { 25595fd7f26SEd Maste found_ranges = 1; 25695fd7f26SEd Maste goto get_func_name; 25795fd7f26SEd Maste } 25895fd7f26SEd Maste } 25995fd7f26SEd Maste 26095fd7f26SEd Maste /* 26195fd7f26SEd Maste * Search for DW_AT_low_pc/DW_AT_high_pc if ranges pointer 26295fd7f26SEd Maste * not found. 26395fd7f26SEd Maste */ 264a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || 265a85fe12eSEd Maste dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) 266a85fe12eSEd Maste goto cont_search; 267b00fe64fSEd Maste if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) 268b00fe64fSEd Maste goto cont_search; 269a85fe12eSEd Maste 27095fd7f26SEd Maste get_func_name: 27195fd7f26SEd Maste /* 27295fd7f26SEd Maste * Most common case the function name is stored in DW_AT_name 27395fd7f26SEd Maste * attribute. 27495fd7f26SEd Maste */ 27595fd7f26SEd Maste if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) == 27695fd7f26SEd Maste DW_DLV_OK) 27795fd7f26SEd Maste goto add_func; 278a85fe12eSEd Maste 27995fd7f26SEd Maste /* 28095fd7f26SEd Maste * For inlined function, the actual name is probably in the DIE 28195fd7f26SEd Maste * referenced by DW_AT_abstract_origin. (if present) 28295fd7f26SEd Maste */ 28395fd7f26SEd Maste if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) == 28495fd7f26SEd Maste DW_DLV_OK && 28595fd7f26SEd Maste dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK && 28695fd7f26SEd Maste dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK && 28795fd7f26SEd Maste dwarf_attrval_string(abst_die, DW_AT_name, &funcname, 28895fd7f26SEd Maste &de) == DW_DLV_OK) 28995fd7f26SEd Maste goto add_func; 290a85fe12eSEd Maste 291a85fe12eSEd Maste /* 292a85fe12eSEd Maste * If DW_AT_name is not present, but DW_AT_specification is 293a85fe12eSEd Maste * present, then probably the actual name is in the DIE 294a85fe12eSEd Maste * referenced by DW_AT_specification. 295a85fe12eSEd Maste */ 29695fd7f26SEd Maste if (dwarf_attr(die, DW_AT_specification, &spec_at, &de) == 29795fd7f26SEd Maste DW_DLV_OK && 29895fd7f26SEd Maste dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK && 29995fd7f26SEd Maste dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK && 30095fd7f26SEd Maste dwarf_attrval_string(spec_die, DW_AT_name, &funcname, 30195fd7f26SEd Maste &de) == DW_DLV_OK) 30295fd7f26SEd Maste goto add_func; 303a85fe12eSEd Maste 304b6b6f9ccSEd Maste /* Skip if no name associated with this DIE. */ 30595fd7f26SEd Maste goto cont_search; 30695fd7f26SEd Maste 30795fd7f26SEd Maste add_func: 30895fd7f26SEd Maste if ((f = calloc(1, sizeof(*f))) == NULL) 30995fd7f26SEd Maste err(EXIT_FAILURE, "calloc"); 31095fd7f26SEd Maste if ((f->name = strdup(funcname)) == NULL) 31195fd7f26SEd Maste err(EXIT_FAILURE, "strdup"); 31295fd7f26SEd Maste if (found_ranges) { 31395fd7f26SEd Maste f->ranges = ranges; 31495fd7f26SEd Maste f->ranges_cnt = ranges_cnt; 31595fd7f26SEd Maste } else { 31695fd7f26SEd Maste f->lopc = lopc; 31795fd7f26SEd Maste f->hipc = hipc; 31895fd7f26SEd Maste } 31995fd7f26SEd Maste if (tag == DW_TAG_inlined_subroutine) { 32095fd7f26SEd Maste f->inlined_caller = parent; 32195fd7f26SEd Maste dwarf_attrval_unsigned(die, DW_AT_call_file, 32295fd7f26SEd Maste &f->call_file, &de); 32395fd7f26SEd Maste dwarf_attrval_unsigned(die, DW_AT_call_line, 32495fd7f26SEd Maste &f->call_line, &de); 32595fd7f26SEd Maste } 32695fd7f26SEd Maste STAILQ_INSERT_TAIL(&cu->funclist, f, next); 327a85fe12eSEd Maste } 328a85fe12eSEd Maste 329a85fe12eSEd Maste cont_search: 330a85fe12eSEd Maste 331a85fe12eSEd Maste /* Search children. */ 332a85fe12eSEd Maste ret = dwarf_child(die, &ret_die, &de); 333a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 33495fd7f26SEd Maste warnx("dwarf_child: %s", dwarf_errmsg(de)); 33595fd7f26SEd Maste else if (ret == DW_DLV_OK) { 33695fd7f26SEd Maste if (f != NULL) 33795fd7f26SEd Maste collect_func(dbg, ret_die, f, cu); 33895fd7f26SEd Maste else 33995fd7f26SEd Maste collect_func(dbg, ret_die, parent, cu); 34095fd7f26SEd Maste } 341a85fe12eSEd Maste 342a85fe12eSEd Maste /* Search sibling. */ 343a85fe12eSEd Maste ret = dwarf_siblingof(dbg, die, &ret_die, &de); 344a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 34595fd7f26SEd Maste warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); 346a85fe12eSEd Maste else if (ret == DW_DLV_OK) 34795fd7f26SEd Maste collect_func(dbg, ret_die, parent, cu); 348656f49f8SEd Maste 34995fd7f26SEd Maste /* Cleanup */ 3506c4a4f1bSEd Maste if (die != cu->die) 351656f49f8SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 35295fd7f26SEd Maste 35395fd7f26SEd Maste if (abst_die != NULL) 35495fd7f26SEd Maste dwarf_dealloc(dbg, abst_die, DW_DLA_DIE); 35595fd7f26SEd Maste 35695fd7f26SEd Maste if (spec_die != NULL) 35795fd7f26SEd Maste dwarf_dealloc(dbg, spec_die, DW_DLA_DIE); 358a85fe12eSEd Maste } 359a85fe12eSEd Maste 360a85fe12eSEd Maste static void 36195fd7f26SEd Maste print_inlines(struct CU *cu, struct Func *f, Dwarf_Unsigned call_file, 36295fd7f26SEd Maste Dwarf_Unsigned call_line) 36395fd7f26SEd Maste { 36495fd7f26SEd Maste char demangled[1024]; 36595fd7f26SEd Maste char *file; 36695fd7f26SEd Maste 36795fd7f26SEd Maste if (call_file > 0 && (Dwarf_Signed) call_file <= cu->nsrcfiles) 36895fd7f26SEd Maste file = cu->srcfiles[call_file - 1]; 36995fd7f26SEd Maste else 37095fd7f26SEd Maste file = unknown; 37195fd7f26SEd Maste 37295fd7f26SEd Maste if (pretty_print) 37395fd7f26SEd Maste printf(" (inlined by) "); 37495fd7f26SEd Maste 37595fd7f26SEd Maste if (func) { 37695fd7f26SEd Maste if (demangle && !elftc_demangle(f->name, demangled, 37795fd7f26SEd Maste sizeof(demangled), 0)) { 37895fd7f26SEd Maste if (pretty_print) 37995fd7f26SEd Maste printf("%s at ", demangled); 38095fd7f26SEd Maste else 38195fd7f26SEd Maste printf("%s\n", demangled); 38295fd7f26SEd Maste } else { 38395fd7f26SEd Maste if (pretty_print) 38495fd7f26SEd Maste printf("%s at ", f->name); 38595fd7f26SEd Maste else 38695fd7f26SEd Maste printf("%s\n", f->name); 38795fd7f26SEd Maste } 38895fd7f26SEd Maste } 389839529caSEd Maste (void) printf("%s:%ju\n", base ? basename(file) : file, 390839529caSEd Maste (uintmax_t) call_line); 39195fd7f26SEd Maste 39295fd7f26SEd Maste if (f->inlined_caller != NULL) 39395fd7f26SEd Maste print_inlines(cu, f->inlined_caller, f->call_file, 39495fd7f26SEd Maste f->call_line); 39595fd7f26SEd Maste } 39695fd7f26SEd Maste 397af843291SMark Johnston static struct CU * 398af843291SMark Johnston culookup(Dwarf_Unsigned addr) 399af843291SMark Johnston { 400af843291SMark Johnston struct CU find, *res; 401af843291SMark Johnston 402af843291SMark Johnston find.lopc = addr; 40335beedaeSMark Johnston res = RB_NFIND(cutree, &cuhead, &find); 404af843291SMark Johnston if (res != NULL) { 405af843291SMark Johnston if (res->lopc != addr) 40635beedaeSMark Johnston res = RB_PREV(cutree, &cuhead, res); 407af843291SMark Johnston if (res != NULL && addr >= res->lopc && addr < res->hipc) 408af843291SMark Johnston return (res); 409af843291SMark Johnston } else { 41035beedaeSMark Johnston res = RB_MAX(cutree, &cuhead); 411af843291SMark Johnston if (res != NULL && addr >= res->lopc && addr < res->hipc) 412af843291SMark Johnston return (res); 413af843291SMark Johnston } 414af843291SMark Johnston return (NULL); 415af843291SMark Johnston } 416af843291SMark Johnston 4176c4a4f1bSEd Maste /* 4186c4a4f1bSEd Maste * Check whether addr falls into range(s) of current CU, and save current CU 4196c4a4f1bSEd Maste * to lookup tree if so. 4206c4a4f1bSEd Maste */ 4216c4a4f1bSEd Maste static int 4226c4a4f1bSEd Maste check_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr, 4236c4a4f1bSEd Maste struct CU **cu) 4246c4a4f1bSEd Maste { 4256c4a4f1bSEd Maste Dwarf_Error de; 4266c4a4f1bSEd Maste Dwarf_Unsigned addr_base, lopc, hipc; 4276c4a4f1bSEd Maste Dwarf_Off ranges_off; 4286c4a4f1bSEd Maste Dwarf_Signed ranges_cnt; 4296c4a4f1bSEd Maste Dwarf_Ranges *ranges; 4306c4a4f1bSEd Maste int i, ret; 4316c4a4f1bSEd Maste bool in_range; 4326c4a4f1bSEd Maste 4336c4a4f1bSEd Maste addr_base = 0; 4346c4a4f1bSEd Maste ranges = NULL; 4356c4a4f1bSEd Maste ranges_cnt = 0; 4366c4a4f1bSEd Maste in_range = false; 4376c4a4f1bSEd Maste 4386c4a4f1bSEd Maste ret = dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de); 439*65c20775SEd Maste if (ret == DW_DLV_OK) { 4406c4a4f1bSEd Maste ret = dwarf_get_ranges(dbg, ranges_off, &ranges, 4416c4a4f1bSEd Maste &ranges_cnt, NULL, &de); 4426c4a4f1bSEd Maste if (ret != DW_DLV_OK) 4436c4a4f1bSEd Maste return (ret); 4446c4a4f1bSEd Maste 4456c4a4f1bSEd Maste if (!ranges || ranges_cnt <= 0) 4466c4a4f1bSEd Maste return (DW_DLV_ERROR); 4476c4a4f1bSEd Maste 4486c4a4f1bSEd Maste for (i = 0; i < ranges_cnt; i++) { 4496c4a4f1bSEd Maste if (ranges[i].dwr_type == DW_RANGES_END) 4506c4a4f1bSEd Maste return (DW_DLV_NO_ENTRY); 4516c4a4f1bSEd Maste 4526c4a4f1bSEd Maste if (ranges[i].dwr_type == 4536c4a4f1bSEd Maste DW_RANGES_ADDRESS_SELECTION) { 4546c4a4f1bSEd Maste addr_base = ranges[i].dwr_addr2; 4556c4a4f1bSEd Maste continue; 4566c4a4f1bSEd Maste } 4576c4a4f1bSEd Maste 4586c4a4f1bSEd Maste /* DW_RANGES_ENTRY */ 4596c4a4f1bSEd Maste lopc = ranges[i].dwr_addr1 + addr_base; 4606c4a4f1bSEd Maste hipc = ranges[i].dwr_addr2 + addr_base; 4616c4a4f1bSEd Maste 4626c4a4f1bSEd Maste if (lopc == curlopc) 4636c4a4f1bSEd Maste return (DW_DLV_ERROR); 4646c4a4f1bSEd Maste 4656c4a4f1bSEd Maste if (addr >= lopc && addr < hipc){ 4666c4a4f1bSEd Maste in_range = true; 4676c4a4f1bSEd Maste break; 4686c4a4f1bSEd Maste } 4696c4a4f1bSEd Maste } 470*65c20775SEd Maste } else if (ret == DW_DLV_NO_ENTRY) { 471*65c20775SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) == 472*65c20775SEd Maste DW_DLV_OK) { 473*65c20775SEd Maste if (lopc == curlopc) 474*65c20775SEd Maste return (DW_DLV_ERROR); 475*65c20775SEd Maste if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, 476*65c20775SEd Maste &de) == DW_DLV_OK) { 477*65c20775SEd Maste /* 478*65c20775SEd Maste * Check if the address falls into the PC 479*65c20775SEd Maste * range of this CU. 480*65c20775SEd Maste */ 481*65c20775SEd Maste if (handle_high_pc(die, lopc, &hipc) != 482*65c20775SEd Maste DW_DLV_OK) 483*65c20775SEd Maste return (DW_DLV_ERROR); 484*65c20775SEd Maste } else { 485*65c20775SEd Maste /* Assume ~0ULL if DW_AT_high_pc not present */ 486*65c20775SEd Maste hipc = ~0ULL; 487*65c20775SEd Maste } 488*65c20775SEd Maste 489*65c20775SEd Maste if (addr >= lopc && addr < hipc) { 490*65c20775SEd Maste in_range = true; 491*65c20775SEd Maste } 492*65c20775SEd Maste } 4936c4a4f1bSEd Maste } else { 4946c4a4f1bSEd Maste return (DW_DLV_ERROR); 4956c4a4f1bSEd Maste } 4966c4a4f1bSEd Maste 4976c4a4f1bSEd Maste if (in_range) { 4986c4a4f1bSEd Maste if ((*cu = calloc(1, sizeof(struct CU))) == NULL) 4996c4a4f1bSEd Maste err(EXIT_FAILURE, "calloc"); 5006c4a4f1bSEd Maste (*cu)->lopc = lopc; 5016c4a4f1bSEd Maste (*cu)->hipc = hipc; 5026c4a4f1bSEd Maste (*cu)->die = die; 5036c4a4f1bSEd Maste (*cu)->dbg = dbg; 5046c4a4f1bSEd Maste STAILQ_INIT(&(*cu)->funclist); 5056c4a4f1bSEd Maste RB_INSERT(cutree, &cuhead, *cu); 5066c4a4f1bSEd Maste curlopc = lopc; 5076c4a4f1bSEd Maste return (DW_DLV_OK); 5086c4a4f1bSEd Maste } else { 5096c4a4f1bSEd Maste return (DW_DLV_NO_ENTRY); 5106c4a4f1bSEd Maste } 5116c4a4f1bSEd Maste } 5126c4a4f1bSEd Maste 51395fd7f26SEd Maste static void 51495fd7f26SEd Maste translate(Dwarf_Debug dbg, Elf *e, const char* addrstr) 515a85fe12eSEd Maste { 516656f49f8SEd Maste Dwarf_Die die, ret_die; 517a85fe12eSEd Maste Dwarf_Line *lbuf; 518a85fe12eSEd Maste Dwarf_Error de; 519a85fe12eSEd Maste Dwarf_Half tag; 5206c4a4f1bSEd Maste Dwarf_Unsigned addr, lineno, plineno; 521a85fe12eSEd Maste Dwarf_Signed lcount; 522a85fe12eSEd Maste Dwarf_Addr lineaddr, plineaddr; 52395fd7f26SEd Maste struct CU *cu; 52495fd7f26SEd Maste struct Func *f; 52595fd7f26SEd Maste const char *funcname; 526a85fe12eSEd Maste char *file, *file0, *pfile; 527a85fe12eSEd Maste char demangled[1024]; 52895fd7f26SEd Maste int ec, i, ret; 529a85fe12eSEd Maste 530a85fe12eSEd Maste addr = strtoull(addrstr, NULL, 16); 531a85fe12eSEd Maste addr += section_base; 532a85fe12eSEd Maste lineno = 0; 533a85fe12eSEd Maste file = unknown; 5347a2e729bSEd Maste die = NULL; 535af843291SMark Johnston ret = DW_DLV_OK; 536a85fe12eSEd Maste 537af843291SMark Johnston cu = culookup(addr); 538af843291SMark Johnston if (cu != NULL) { 539af843291SMark Johnston die = cu->die; 5406c4a4f1bSEd Maste dbg = cu->dbg; 541af843291SMark Johnston goto status_ok; 542af843291SMark Johnston } 543af843291SMark Johnston 544af843291SMark Johnston while (true) { 545af843291SMark Johnston /* 546af843291SMark Johnston * We resume the CU scan from the last place we found a match. 547af843291SMark Johnston * Because when we have 2 sequential addresses, and the second 548af843291SMark Johnston * one is of the next CU, it is faster to just go to the next CU 549af843291SMark Johnston * instead of starting from the beginning. 550af843291SMark Johnston */ 551af843291SMark Johnston ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 552af843291SMark Johnston &de); 553af843291SMark Johnston if (ret == DW_DLV_NO_ENTRY) { 554af843291SMark Johnston if (curlopc == ~0ULL) 555af843291SMark Johnston goto out; 556af843291SMark Johnston ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, 557af843291SMark Johnston NULL, &de); 558af843291SMark Johnston } 559a85fe12eSEd Maste die = NULL; 560656f49f8SEd Maste while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { 561656f49f8SEd Maste if (die != NULL) 562656f49f8SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 563656f49f8SEd Maste die = ret_die; 564a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 565a85fe12eSEd Maste warnx("dwarf_tag failed: %s", 566a85fe12eSEd Maste dwarf_errmsg(de)); 567656f49f8SEd Maste goto next_cu; 568a85fe12eSEd Maste } 569656f49f8SEd Maste 570a85fe12eSEd Maste /* XXX: What about DW_TAG_partial_unit? */ 571a85fe12eSEd Maste if (tag == DW_TAG_compile_unit) 572a85fe12eSEd Maste break; 573a85fe12eSEd Maste } 574af843291SMark Johnston 575656f49f8SEd Maste if (ret_die == NULL) { 576a85fe12eSEd Maste warnx("could not find DW_TAG_compile_unit die"); 577656f49f8SEd Maste goto next_cu; 578a85fe12eSEd Maste } 5796c4a4f1bSEd Maste ret = check_range(dbg, die, addr, &cu); 5806c4a4f1bSEd Maste if (ret == DW_DLV_OK) 58195fd7f26SEd Maste break; 5826c4a4f1bSEd Maste if (ret == DW_DLV_ERROR) 5836c4a4f1bSEd Maste goto out; 58495fd7f26SEd Maste next_cu: 58595fd7f26SEd Maste if (die != NULL) { 58695fd7f26SEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 58795fd7f26SEd Maste die = NULL; 58895fd7f26SEd Maste } 58995fd7f26SEd Maste } 59095fd7f26SEd Maste 59195fd7f26SEd Maste if (ret != DW_DLV_OK || die == NULL) 59295fd7f26SEd Maste goto out; 59395fd7f26SEd Maste 594af843291SMark Johnston status_ok: 595c9dbb1ccSEd Maste switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { 596c9dbb1ccSEd Maste case DW_DLV_OK: 597c9dbb1ccSEd Maste break; 598c9dbb1ccSEd Maste case DW_DLV_NO_ENTRY: 599656f49f8SEd Maste /* If a CU lacks debug info, just skip it. */ 60095fd7f26SEd Maste goto out; 601c9dbb1ccSEd Maste default: 602a85fe12eSEd Maste warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 603a85fe12eSEd Maste goto out; 604a85fe12eSEd Maste } 605a85fe12eSEd Maste 606a85fe12eSEd Maste plineaddr = ~0ULL; 607a85fe12eSEd Maste plineno = 0; 608a85fe12eSEd Maste pfile = unknown; 609a85fe12eSEd Maste for (i = 0; i < lcount; i++) { 610a85fe12eSEd Maste if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 61195fd7f26SEd Maste warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); 612a85fe12eSEd Maste goto out; 613a85fe12eSEd Maste } 614a85fe12eSEd Maste if (dwarf_lineno(lbuf[i], &lineno, &de)) { 61595fd7f26SEd Maste warnx("dwarf_lineno: %s", dwarf_errmsg(de)); 616a85fe12eSEd Maste goto out; 617a85fe12eSEd Maste } 618a85fe12eSEd Maste if (dwarf_linesrc(lbuf[i], &file0, &de)) { 61995fd7f26SEd Maste warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); 620a85fe12eSEd Maste } else 621a85fe12eSEd Maste file = file0; 622a85fe12eSEd Maste if (addr == lineaddr) 623a85fe12eSEd Maste goto out; 624a85fe12eSEd Maste else if (addr < lineaddr && addr > plineaddr) { 625a85fe12eSEd Maste lineno = plineno; 626a85fe12eSEd Maste file = pfile; 627a85fe12eSEd Maste goto out; 628a85fe12eSEd Maste } 629a85fe12eSEd Maste plineaddr = lineaddr; 630a85fe12eSEd Maste plineno = lineno; 631a85fe12eSEd Maste pfile = file; 632a85fe12eSEd Maste } 633a85fe12eSEd Maste 634a85fe12eSEd Maste out: 63595fd7f26SEd Maste f = NULL; 636a85fe12eSEd Maste funcname = NULL; 63795fd7f26SEd Maste if (ret == DW_DLV_OK && (func || inlines) && cu != NULL) { 63895fd7f26SEd Maste if (cu->srcfiles == NULL) 63995fd7f26SEd Maste if (dwarf_srcfiles(die, &cu->srcfiles, &cu->nsrcfiles, 64095fd7f26SEd Maste &de)) 64195fd7f26SEd Maste warnx("dwarf_srcfiles: %s", dwarf_errmsg(de)); 64295fd7f26SEd Maste if (STAILQ_EMPTY(&cu->funclist)) { 64395fd7f26SEd Maste collect_func(dbg, die, NULL, cu); 644656f49f8SEd Maste die = NULL; 645656f49f8SEd Maste } 64695fd7f26SEd Maste f = search_func(cu, addr); 64795fd7f26SEd Maste if (f != NULL) 64895fd7f26SEd Maste funcname = f->name; 64995fd7f26SEd Maste } 65095fd7f26SEd Maste 65195fd7f26SEd Maste if (print_addr) { 65295fd7f26SEd Maste if ((ec = gelf_getclass(e)) == ELFCLASSNONE) { 65395fd7f26SEd Maste warnx("gelf_getclass failed: %s", elf_errmsg(-1)); 65495fd7f26SEd Maste ec = ELFCLASS64; 65595fd7f26SEd Maste } 65695fd7f26SEd Maste if (ec == ELFCLASS32) { 65795fd7f26SEd Maste if (pretty_print) 65895fd7f26SEd Maste printf("0x%08jx: ", (uintmax_t) addr); 65995fd7f26SEd Maste else 66095fd7f26SEd Maste printf("0x%08jx\n", (uintmax_t) addr); 66195fd7f26SEd Maste } else { 66295fd7f26SEd Maste if (pretty_print) 66395fd7f26SEd Maste printf("0x%016jx: ", (uintmax_t) addr); 66495fd7f26SEd Maste else 66595fd7f26SEd Maste printf("0x%016jx\n", (uintmax_t) addr); 66695fd7f26SEd Maste } 66795fd7f26SEd Maste } 668a85fe12eSEd Maste 669a85fe12eSEd Maste if (func) { 670a85fe12eSEd Maste if (funcname == NULL) 67195fd7f26SEd Maste funcname = unknown; 67295fd7f26SEd Maste if (demangle && !elftc_demangle(funcname, demangled, 67395fd7f26SEd Maste sizeof(demangled), 0)) { 67495fd7f26SEd Maste if (pretty_print) 67595fd7f26SEd Maste printf("%s at ", demangled); 67695fd7f26SEd Maste else 677a85fe12eSEd Maste printf("%s\n", demangled); 67895fd7f26SEd Maste } else { 67995fd7f26SEd Maste if (pretty_print) 68095fd7f26SEd Maste printf("%s at ", funcname); 681a85fe12eSEd Maste else 682a85fe12eSEd Maste printf("%s\n", funcname); 68395fd7f26SEd Maste } 684a85fe12eSEd Maste } 685a85fe12eSEd Maste 686839529caSEd Maste (void) printf("%s:%ju\n", base ? basename(file) : file, 687839529caSEd Maste (uintmax_t) lineno); 688a85fe12eSEd Maste 68995fd7f26SEd Maste if (ret == DW_DLV_OK && inlines && cu != NULL && 69095fd7f26SEd Maste cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL) 69195fd7f26SEd Maste print_inlines(cu, f->inlined_caller, f->call_file, 69295fd7f26SEd Maste f->call_line); 693a85fe12eSEd Maste } 694a85fe12eSEd Maste 695a85fe12eSEd Maste static void 696a85fe12eSEd Maste find_section_base(const char *exe, Elf *e, const char *section) 697a85fe12eSEd Maste { 698a85fe12eSEd Maste Dwarf_Addr off; 699a85fe12eSEd Maste Elf_Scn *scn; 700a85fe12eSEd Maste GElf_Ehdr eh; 701a85fe12eSEd Maste GElf_Shdr sh; 702a85fe12eSEd Maste size_t shstrndx; 703a85fe12eSEd Maste int elferr; 704a85fe12eSEd Maste const char *name; 705a85fe12eSEd Maste 706a85fe12eSEd Maste if (gelf_getehdr(e, &eh) != &eh) { 707a85fe12eSEd Maste warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 708a85fe12eSEd Maste return; 709a85fe12eSEd Maste } 710a85fe12eSEd Maste 711a85fe12eSEd Maste if (!elf_getshstrndx(e, &shstrndx)) { 712a85fe12eSEd Maste warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 713a85fe12eSEd Maste return; 714a85fe12eSEd Maste } 715a85fe12eSEd Maste 716a85fe12eSEd Maste (void) elf_errno(); 717a85fe12eSEd Maste off = 0; 718a85fe12eSEd Maste scn = NULL; 719a85fe12eSEd Maste while ((scn = elf_nextscn(e, scn)) != NULL) { 720a85fe12eSEd Maste if (gelf_getshdr(scn, &sh) == NULL) { 721a85fe12eSEd Maste warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 722a85fe12eSEd Maste continue; 723a85fe12eSEd Maste } 724a85fe12eSEd Maste if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) 725a85fe12eSEd Maste goto next; 726a85fe12eSEd Maste if (!strcmp(section, name)) { 727a85fe12eSEd Maste if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { 728a85fe12eSEd Maste /* 729a85fe12eSEd Maste * For executables, section base is the virtual 730a85fe12eSEd Maste * address of the specified section. 731a85fe12eSEd Maste */ 732a85fe12eSEd Maste section_base = sh.sh_addr; 733a85fe12eSEd Maste } else if (eh.e_type == ET_REL) { 734a85fe12eSEd Maste /* 735a85fe12eSEd Maste * For relocatables, section base is the 736a85fe12eSEd Maste * relative offset of the specified section 737a85fe12eSEd Maste * to the start of the first section. 738a85fe12eSEd Maste */ 739a85fe12eSEd Maste section_base = off; 740a85fe12eSEd Maste } else 741a85fe12eSEd Maste warnx("unknown e_type %u", eh.e_type); 742a85fe12eSEd Maste return; 743a85fe12eSEd Maste } 744a85fe12eSEd Maste next: 745a85fe12eSEd Maste off += sh.sh_size; 746a85fe12eSEd Maste } 747a85fe12eSEd Maste elferr = elf_errno(); 748a85fe12eSEd Maste if (elferr != 0) 749a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 750a85fe12eSEd Maste 751a85fe12eSEd Maste errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); 752a85fe12eSEd Maste } 753a85fe12eSEd Maste 754a85fe12eSEd Maste int 755a85fe12eSEd Maste main(int argc, char **argv) 756a85fe12eSEd Maste { 7571d954fedSMark Johnston cap_rights_t rights; 758a85fe12eSEd Maste Elf *e; 759a85fe12eSEd Maste Dwarf_Debug dbg; 760a85fe12eSEd Maste Dwarf_Error de; 761a85fe12eSEd Maste const char *exe, *section; 762a85fe12eSEd Maste char line[1024]; 763a85fe12eSEd Maste int fd, i, opt; 764a85fe12eSEd Maste 765a85fe12eSEd Maste exe = NULL; 766a85fe12eSEd Maste section = NULL; 76795fd7f26SEd Maste while ((opt = getopt_long(argc, argv, "ab:Ce:fij:psHV", longopts, 76895fd7f26SEd Maste NULL)) != -1) { 769a85fe12eSEd Maste switch (opt) { 77095fd7f26SEd Maste case 'a': 77195fd7f26SEd Maste print_addr = 1; 77295fd7f26SEd Maste break; 773a85fe12eSEd Maste case 'b': 774a85fe12eSEd Maste /* ignored */ 775a85fe12eSEd Maste break; 776a85fe12eSEd Maste case 'C': 777a85fe12eSEd Maste demangle = 1; 778a85fe12eSEd Maste break; 779a85fe12eSEd Maste case 'e': 780a85fe12eSEd Maste exe = optarg; 781a85fe12eSEd Maste break; 782a85fe12eSEd Maste case 'f': 783a85fe12eSEd Maste func = 1; 784a85fe12eSEd Maste break; 78595fd7f26SEd Maste case 'i': 78695fd7f26SEd Maste inlines = 1; 78795fd7f26SEd Maste break; 788a85fe12eSEd Maste case 'j': 789a85fe12eSEd Maste section = optarg; 790a85fe12eSEd Maste break; 79195fd7f26SEd Maste case 'p': 79295fd7f26SEd Maste pretty_print = 1; 79395fd7f26SEd Maste break; 794a85fe12eSEd Maste case 's': 795a85fe12eSEd Maste base = 1; 796a85fe12eSEd Maste break; 797a85fe12eSEd Maste case 'H': 798a85fe12eSEd Maste usage(); 799a85fe12eSEd Maste case 'V': 800a85fe12eSEd Maste version(); 801a85fe12eSEd Maste default: 802a85fe12eSEd Maste usage(); 803a85fe12eSEd Maste } 804a85fe12eSEd Maste } 805a85fe12eSEd Maste 806a85fe12eSEd Maste argv += optind; 807a85fe12eSEd Maste argc -= optind; 808a85fe12eSEd Maste 809a85fe12eSEd Maste if (exe == NULL) 810a85fe12eSEd Maste exe = "a.out"; 811a85fe12eSEd Maste 812a85fe12eSEd Maste if ((fd = open(exe, O_RDONLY)) < 0) 813a85fe12eSEd Maste err(EXIT_FAILURE, "%s", exe); 814a85fe12eSEd Maste 8151d954fedSMark Johnston if (caph_rights_limit(fd, cap_rights_init(&rights, CAP_FSTAT, 8161d954fedSMark Johnston CAP_MMAP_R)) < 0) 8171d954fedSMark Johnston errx(EXIT_FAILURE, "caph_rights_limit"); 8181d954fedSMark Johnston 8191d954fedSMark Johnston caph_cache_catpages(); 8201d954fedSMark Johnston if (caph_limit_stdio() < 0) 8211d954fedSMark Johnston errx(EXIT_FAILURE, "failed to limit stdio rights"); 8221d954fedSMark Johnston if (caph_enter() < 0) 8231d954fedSMark Johnston errx(EXIT_FAILURE, "failed to enter capability mode"); 8241d954fedSMark Johnston 825a85fe12eSEd Maste if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) 826a85fe12eSEd Maste errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); 827a85fe12eSEd Maste 828a85fe12eSEd Maste if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) 829a85fe12eSEd Maste errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); 830a85fe12eSEd Maste 831a85fe12eSEd Maste if (section) 832a85fe12eSEd Maste find_section_base(exe, e, section); 833a85fe12eSEd Maste else 834a85fe12eSEd Maste section_base = 0; 835a85fe12eSEd Maste 836a85fe12eSEd Maste if (argc > 0) 837a85fe12eSEd Maste for (i = 0; i < argc; i++) 83895fd7f26SEd Maste translate(dbg, e, argv[i]); 839bee2765cSEd Maste else { 840bee2765cSEd Maste setvbuf(stdout, NULL, _IOLBF, 0); 841bee2765cSEd Maste while (fgets(line, sizeof(line), stdin) != NULL) 84295fd7f26SEd Maste translate(dbg, e, line); 843a7265433SEd Maste } 844a85fe12eSEd Maste 845a85fe12eSEd Maste dwarf_finish(dbg, &de); 846a85fe12eSEd Maste 847a85fe12eSEd Maste (void) elf_end(e); 848a85fe12eSEd Maste 849a85fe12eSEd Maste exit(0); 850a85fe12eSEd Maste } 851