addr2line.c revision 317623
1260684Skaiw/*- 2260684Skaiw * Copyright (c) 2009 Kai Wang 3260684Skaiw * All rights reserved. 4260684Skaiw * 5260684Skaiw * Redistribution and use in source and binary forms, with or without 6260684Skaiw * modification, are permitted provided that the following conditions 7260684Skaiw * are met: 8260684Skaiw * 1. Redistributions of source code must retain the above copyright 9260684Skaiw * notice, this list of conditions and the following disclaimer. 10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright 11260684Skaiw * notice, this list of conditions and the following disclaimer in the 12260684Skaiw * documentation and/or other materials provided with the distribution. 13260684Skaiw * 14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17260684Skaiw * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24260684Skaiw * SUCH DAMAGE. 25260684Skaiw */ 26260684Skaiw 27260684Skaiw#include <sys/param.h> 28260684Skaiw#include <dwarf.h> 29260684Skaiw#include <err.h> 30260684Skaiw#include <fcntl.h> 31260684Skaiw#include <gelf.h> 32260684Skaiw#include <getopt.h> 33260684Skaiw#include <libdwarf.h> 34260684Skaiw#include <libelftc.h> 35260684Skaiw#include <libgen.h> 36260684Skaiw#include <stdio.h> 37260684Skaiw#include <stdlib.h> 38260684Skaiw#include <string.h> 39260684Skaiw 40292120Semaste#include "uthash.h" 41260684Skaiw#include "_elftc.h" 42260684Skaiw 43317623SemasteELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $"); 44260684Skaiw 45292120Semastestruct Func { 46292120Semaste char *name; 47292120Semaste Dwarf_Unsigned lopc; 48292120Semaste Dwarf_Unsigned hipc; 49292120Semaste Dwarf_Unsigned call_file; 50292120Semaste Dwarf_Unsigned call_line; 51292120Semaste Dwarf_Ranges *ranges; 52292120Semaste Dwarf_Signed ranges_cnt; 53292120Semaste struct Func *inlined_caller; 54292120Semaste STAILQ_ENTRY(Func) next; 55292120Semaste}; 56292120Semaste 57292120Semastestruct CU { 58292120Semaste Dwarf_Off off; 59292120Semaste Dwarf_Unsigned lopc; 60292120Semaste Dwarf_Unsigned hipc; 61292120Semaste char **srcfiles; 62292120Semaste Dwarf_Signed nsrcfiles; 63292120Semaste STAILQ_HEAD(, Func) funclist; 64292120Semaste UT_hash_handle hh; 65292120Semaste}; 66292120Semaste 67260684Skaiwstatic struct option longopts[] = { 68292120Semaste {"addresses", no_argument, NULL, 'a'}, 69260684Skaiw {"target" , required_argument, NULL, 'b'}, 70260684Skaiw {"demangle", no_argument, NULL, 'C'}, 71260684Skaiw {"exe", required_argument, NULL, 'e'}, 72260684Skaiw {"functions", no_argument, NULL, 'f'}, 73292120Semaste {"inlines", no_argument, NULL, 'i'}, 74260684Skaiw {"section", required_argument, NULL, 'j'}, 75292120Semaste {"pretty-print", no_argument, NULL, 'p'}, 76260684Skaiw {"basename", no_argument, NULL, 's'}, 77260684Skaiw {"help", no_argument, NULL, 'H'}, 78260684Skaiw {"version", no_argument, NULL, 'V'}, 79260684Skaiw {NULL, 0, NULL, 0} 80260684Skaiw}; 81292120Semastestatic int demangle, func, base, inlines, print_addr, pretty_print; 82260684Skaiwstatic char unknown[] = { '?', '?', '\0' }; 83260684Skaiwstatic Dwarf_Addr section_base; 84292120Semastestatic struct CU *culist; 85260684Skaiw 86260684Skaiw#define USAGE_MESSAGE "\ 87260684SkaiwUsage: %s [options] hexaddress...\n\ 88260684Skaiw Map program addresses to source file names and line numbers.\n\n\ 89260684Skaiw Options:\n\ 90292120Semaste -a | --addresses Display address prior to line number info.\n\ 91260684Skaiw -b TGT | --target=TGT (Accepted but ignored).\n\ 92289071Semaste -e EXE | --exe=EXE Use program \"EXE\" to translate addresses.\n\ 93260684Skaiw -f | --functions Display function names.\n\ 94292120Semaste -i | --inlines Display caller info for inlined functions.\n\ 95260684Skaiw -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ 96292120Semaste -p | --pretty-print Display line number info and function name\n\ 97292120Semaste in human readable manner.\n\ 98260684Skaiw -s | --basename Only show the base name for each file name.\n\ 99260684Skaiw -C | --demangle Demangle C++ names.\n\ 100260684Skaiw -H | --help Print a help message.\n\ 101260684Skaiw -V | --version Print a version identifier and exit.\n" 102260684Skaiw 103260684Skaiwstatic void 104260684Skaiwusage(void) 105260684Skaiw{ 106260684Skaiw (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 107260684Skaiw exit(1); 108260684Skaiw} 109260684Skaiw 110260684Skaiwstatic void 111260684Skaiwversion(void) 112260684Skaiw{ 113260684Skaiw 114260684Skaiw fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 115260684Skaiw exit(0); 116260684Skaiw} 117260684Skaiw 118282918Semaste/* 119282918Semaste * Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't 120282918Semaste * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1) 121282918Semaste * generate DW_AT_high_pc as an offset from DW_AT_low_pc. 122282918Semaste * 123282918Semaste * "If the value of the DW_AT_high_pc is of class address, it is the 124282918Semaste * relocated address of the first location past the last instruction 125282918Semaste * associated with the entity; if it is of class constant, the value 126282918Semaste * is an unsigned integer offset which when added to the low PC gives 127282918Semaste * the address of the first location past the last instruction 128282918Semaste * associated with the entity." 129282918Semaste * 130282918Semaste * DWARF4 spec, section 2.17.2. 131282918Semaste */ 132282918Semastestatic int 133282918Semastehandle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc) 134282918Semaste{ 135282918Semaste Dwarf_Error de; 136282918Semaste Dwarf_Half form; 137282918Semaste Dwarf_Attribute at; 138282918Semaste int ret; 139282918Semaste 140282918Semaste ret = dwarf_attr(die, DW_AT_high_pc, &at, &de); 141282918Semaste if (ret == DW_DLV_ERROR) { 142282918Semaste warnx("dwarf_attr failed: %s", dwarf_errmsg(de)); 143282918Semaste return (ret); 144282918Semaste } 145282918Semaste ret = dwarf_whatform(at, &form, &de); 146282918Semaste if (ret == DW_DLV_ERROR) { 147282918Semaste warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); 148282918Semaste return (ret); 149282918Semaste } 150282918Semaste if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT) 151282918Semaste *hipc += lopc; 152282918Semaste 153282918Semaste return (DW_DLV_OK); 154282918Semaste} 155282918Semaste 156292120Semastestatic struct Func * 157292120Semastesearch_func(struct CU *cu, Dwarf_Unsigned addr) 158292120Semaste{ 159292120Semaste struct Func *f, *f0; 160292120Semaste Dwarf_Unsigned lopc, hipc, addr_base; 161292120Semaste int i; 162292120Semaste 163292120Semaste f0 = NULL; 164292120Semaste 165292120Semaste STAILQ_FOREACH(f, &cu->funclist, next) { 166292120Semaste if (f->ranges != NULL) { 167292120Semaste addr_base = 0; 168292120Semaste for (i = 0; i < f->ranges_cnt; i++) { 169292120Semaste if (f->ranges[i].dwr_type == DW_RANGES_END) 170292120Semaste break; 171292120Semaste if (f->ranges[i].dwr_type == 172292120Semaste DW_RANGES_ADDRESS_SELECTION) { 173292120Semaste addr_base = f->ranges[i].dwr_addr2; 174292120Semaste continue; 175292120Semaste } 176292120Semaste 177292120Semaste /* DW_RANGES_ENTRY */ 178292120Semaste lopc = f->ranges[i].dwr_addr1 + addr_base; 179292120Semaste hipc = f->ranges[i].dwr_addr2 + addr_base; 180292120Semaste if (addr >= lopc && addr < hipc) { 181292120Semaste if (f0 == NULL || 182292120Semaste (lopc >= f0->lopc && 183292120Semaste hipc <= f0->hipc)) { 184292120Semaste f0 = f; 185292120Semaste f0->lopc = lopc; 186292120Semaste f0->hipc = hipc; 187292120Semaste break; 188292120Semaste } 189292120Semaste } 190292120Semaste } 191292120Semaste } else if (addr >= f->lopc && addr < f->hipc) { 192292120Semaste if (f0 == NULL || 193292120Semaste (f->lopc >= f0->lopc && f->hipc <= f0->hipc)) 194292120Semaste f0 = f; 195292120Semaste } 196292120Semaste } 197292120Semaste 198292120Semaste return (f0); 199292120Semaste} 200292120Semaste 201260684Skaiwstatic void 202292120Semastecollect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu) 203260684Skaiw{ 204292120Semaste Dwarf_Die ret_die, abst_die, spec_die; 205260684Skaiw Dwarf_Error de; 206260684Skaiw Dwarf_Half tag; 207292120Semaste Dwarf_Unsigned lopc, hipc, ranges_off; 208292120Semaste Dwarf_Signed ranges_cnt; 209260684Skaiw Dwarf_Off ref; 210292120Semaste Dwarf_Attribute abst_at, spec_at; 211292120Semaste Dwarf_Ranges *ranges; 212292120Semaste const char *funcname; 213292120Semaste struct Func *f; 214292120Semaste int found_ranges, ret; 215260684Skaiw 216292120Semaste f = NULL; 217292120Semaste abst_die = spec_die = NULL; 218260684Skaiw 219260684Skaiw if (dwarf_tag(die, &tag, &de)) { 220260684Skaiw warnx("dwarf_tag: %s", dwarf_errmsg(de)); 221260684Skaiw goto cont_search; 222260684Skaiw } 223292120Semaste if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || 224292120Semaste tag == DW_TAG_inlined_subroutine) { 225292120Semaste /* 226292120Semaste * Function address range can be specified by either 227292120Semaste * a DW_AT_ranges attribute which points to a range list or 228292120Semaste * by a pair of DW_AT_low_pc and DW_AT_high_pc attributes. 229292120Semaste */ 230292120Semaste ranges = NULL; 231292120Semaste ranges_cnt = 0; 232292120Semaste found_ranges = 0; 233292120Semaste if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, 234292120Semaste &de) == DW_DLV_OK && 235292120Semaste dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges, 236292120Semaste &ranges_cnt, NULL, &de) == DW_DLV_OK) { 237292120Semaste if (ranges != NULL && ranges_cnt > 0) { 238292120Semaste found_ranges = 1; 239292120Semaste goto get_func_name; 240292120Semaste } 241292120Semaste } 242292120Semaste 243292120Semaste /* 244292120Semaste * Search for DW_AT_low_pc/DW_AT_high_pc if ranges pointer 245292120Semaste * not found. 246292120Semaste */ 247260684Skaiw if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || 248260684Skaiw dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) 249260684Skaiw goto cont_search; 250282918Semaste if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) 251282918Semaste goto cont_search; 252260684Skaiw 253292120Semaste get_func_name: 254292120Semaste /* 255292120Semaste * Most common case the function name is stored in DW_AT_name 256292120Semaste * attribute. 257292120Semaste */ 258292120Semaste if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) == 259292120Semaste DW_DLV_OK) 260292120Semaste goto add_func; 261260684Skaiw 262292120Semaste /* 263292120Semaste * For inlined function, the actual name is probably in the DIE 264292120Semaste * referenced by DW_AT_abstract_origin. (if present) 265292120Semaste */ 266292120Semaste if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) == 267292120Semaste DW_DLV_OK && 268292120Semaste dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK && 269292120Semaste dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK && 270292120Semaste dwarf_attrval_string(abst_die, DW_AT_name, &funcname, 271292120Semaste &de) == DW_DLV_OK) 272292120Semaste goto add_func; 273260684Skaiw 274260684Skaiw /* 275260684Skaiw * If DW_AT_name is not present, but DW_AT_specification is 276260684Skaiw * present, then probably the actual name is in the DIE 277260684Skaiw * referenced by DW_AT_specification. 278260684Skaiw */ 279292120Semaste if (dwarf_attr(die, DW_AT_specification, &spec_at, &de) == 280292120Semaste DW_DLV_OK && 281292120Semaste dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK && 282292120Semaste dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK && 283292120Semaste dwarf_attrval_string(spec_die, DW_AT_name, &funcname, 284292120Semaste &de) == DW_DLV_OK) 285292120Semaste goto add_func; 286292120Semaste 287300311Semaste /* Skip if no name associated with this DIE. */ 288292120Semaste goto cont_search; 289292120Semaste 290292120Semaste add_func: 291292120Semaste if ((f = calloc(1, sizeof(*f))) == NULL) 292292120Semaste err(EXIT_FAILURE, "calloc"); 293292120Semaste if ((f->name = strdup(funcname)) == NULL) 294292120Semaste err(EXIT_FAILURE, "strdup"); 295292120Semaste if (found_ranges) { 296292120Semaste f->ranges = ranges; 297292120Semaste f->ranges_cnt = ranges_cnt; 298292120Semaste } else { 299292120Semaste f->lopc = lopc; 300292120Semaste f->hipc = hipc; 301289071Semaste } 302292120Semaste if (tag == DW_TAG_inlined_subroutine) { 303292120Semaste f->inlined_caller = parent; 304292120Semaste dwarf_attrval_unsigned(die, DW_AT_call_file, 305292120Semaste &f->call_file, &de); 306292120Semaste dwarf_attrval_unsigned(die, DW_AT_call_line, 307292120Semaste &f->call_line, &de); 308292120Semaste } 309292120Semaste STAILQ_INSERT_TAIL(&cu->funclist, f, next); 310260684Skaiw } 311260684Skaiw 312260684Skaiwcont_search: 313260684Skaiw 314260684Skaiw /* Search children. */ 315260684Skaiw ret = dwarf_child(die, &ret_die, &de); 316260684Skaiw if (ret == DW_DLV_ERROR) 317292120Semaste warnx("dwarf_child: %s", dwarf_errmsg(de)); 318292120Semaste else if (ret == DW_DLV_OK) { 319292120Semaste if (f != NULL) 320292120Semaste collect_func(dbg, ret_die, f, cu); 321292120Semaste else 322292120Semaste collect_func(dbg, ret_die, parent, cu); 323292120Semaste } 324260684Skaiw 325260684Skaiw /* Search sibling. */ 326260684Skaiw ret = dwarf_siblingof(dbg, die, &ret_die, &de); 327260684Skaiw if (ret == DW_DLV_ERROR) 328292120Semaste warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); 329260684Skaiw else if (ret == DW_DLV_OK) 330292120Semaste collect_func(dbg, ret_die, parent, cu); 331289071Semaste 332292120Semaste /* Cleanup */ 333289071Semaste dwarf_dealloc(dbg, die, DW_DLA_DIE); 334292120Semaste 335292120Semaste if (abst_die != NULL) 336292120Semaste dwarf_dealloc(dbg, abst_die, DW_DLA_DIE); 337292120Semaste 338292120Semaste if (spec_die != NULL) 339292120Semaste dwarf_dealloc(dbg, spec_die, DW_DLA_DIE); 340260684Skaiw} 341260684Skaiw 342260684Skaiwstatic void 343292120Semasteprint_inlines(struct CU *cu, struct Func *f, Dwarf_Unsigned call_file, 344292120Semaste Dwarf_Unsigned call_line) 345260684Skaiw{ 346292120Semaste char demangled[1024]; 347292120Semaste char *file; 348292120Semaste 349292120Semaste if (call_file > 0 && (Dwarf_Signed) call_file <= cu->nsrcfiles) 350292120Semaste file = cu->srcfiles[call_file - 1]; 351292120Semaste else 352292120Semaste file = unknown; 353292120Semaste 354292120Semaste if (pretty_print) 355292120Semaste printf(" (inlined by) "); 356292120Semaste 357292120Semaste if (func) { 358292120Semaste if (demangle && !elftc_demangle(f->name, demangled, 359292120Semaste sizeof(demangled), 0)) { 360292120Semaste if (pretty_print) 361292120Semaste printf("%s at ", demangled); 362292120Semaste else 363292120Semaste printf("%s\n", demangled); 364292120Semaste } else { 365292120Semaste if (pretty_print) 366292120Semaste printf("%s at ", f->name); 367292120Semaste else 368292120Semaste printf("%s\n", f->name); 369292120Semaste } 370292120Semaste } 371295577Semaste (void) printf("%s:%ju\n", base ? basename(file) : file, 372295577Semaste (uintmax_t) call_line); 373292120Semaste 374292120Semaste if (f->inlined_caller != NULL) 375292120Semaste print_inlines(cu, f->inlined_caller, f->call_file, 376292120Semaste f->call_line); 377292120Semaste} 378292120Semaste 379292120Semastestatic void 380292120Semastetranslate(Dwarf_Debug dbg, Elf *e, const char* addrstr) 381292120Semaste{ 382289071Semaste Dwarf_Die die, ret_die; 383260684Skaiw Dwarf_Line *lbuf; 384260684Skaiw Dwarf_Error de; 385260684Skaiw Dwarf_Half tag; 386260684Skaiw Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; 387260684Skaiw Dwarf_Signed lcount; 388260684Skaiw Dwarf_Addr lineaddr, plineaddr; 389292120Semaste Dwarf_Off off; 390292120Semaste struct CU *cu; 391292120Semaste struct Func *f; 392292120Semaste const char *funcname; 393260684Skaiw char *file, *file0, *pfile; 394260684Skaiw char demangled[1024]; 395292120Semaste int ec, i, ret; 396260684Skaiw 397260684Skaiw addr = strtoull(addrstr, NULL, 16); 398260684Skaiw addr += section_base; 399260684Skaiw lineno = 0; 400260684Skaiw file = unknown; 401292120Semaste cu = NULL; 402289074Semaste die = NULL; 403260684Skaiw 404260684Skaiw while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 405260684Skaiw &de)) == DW_DLV_OK) { 406260684Skaiw die = NULL; 407289071Semaste while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { 408289071Semaste if (die != NULL) 409289071Semaste dwarf_dealloc(dbg, die, DW_DLA_DIE); 410289071Semaste die = ret_die; 411260684Skaiw if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 412260684Skaiw warnx("dwarf_tag failed: %s", 413260684Skaiw dwarf_errmsg(de)); 414289071Semaste goto next_cu; 415260684Skaiw } 416289071Semaste 417260684Skaiw /* XXX: What about DW_TAG_partial_unit? */ 418260684Skaiw if (tag == DW_TAG_compile_unit) 419260684Skaiw break; 420260684Skaiw } 421289071Semaste if (ret_die == NULL) { 422260684Skaiw warnx("could not find DW_TAG_compile_unit die"); 423289071Semaste goto next_cu; 424260684Skaiw } 425292120Semaste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) == 426292120Semaste DW_DLV_OK) { 427292120Semaste if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, 428292120Semaste &de) == DW_DLV_OK) { 429292120Semaste /* 430292120Semaste * Check if the address falls into the PC 431292120Semaste * range of this CU. 432292120Semaste */ 433292120Semaste if (handle_high_pc(die, lopc, &hipc) != 434292120Semaste DW_DLV_OK) 435292120Semaste goto out; 436292120Semaste } else { 437292120Semaste /* Assume ~0ULL if DW_AT_high_pc not present */ 438292120Semaste hipc = ~0ULL; 439292120Semaste } 440292120Semaste 441260684Skaiw /* 442292120Semaste * Record the CU in the hash table for faster lookup 443292120Semaste * later. 444260684Skaiw */ 445292120Semaste if (dwarf_dieoffset(die, &off, &de) != DW_DLV_OK) { 446292120Semaste warnx("dwarf_dieoffset failed: %s", 447260684Skaiw dwarf_errmsg(de)); 448260684Skaiw goto out; 449260684Skaiw } 450292120Semaste HASH_FIND(hh, culist, &off, sizeof(off), cu); 451292120Semaste if (cu == NULL) { 452292120Semaste if ((cu = calloc(1, sizeof(*cu))) == NULL) 453292120Semaste err(EXIT_FAILURE, "calloc"); 454292120Semaste cu->off = off; 455292120Semaste cu->lopc = lopc; 456292120Semaste cu->hipc = hipc; 457292120Semaste STAILQ_INIT(&cu->funclist); 458292120Semaste HASH_ADD(hh, culist, off, sizeof(off), cu); 459260684Skaiw } 460292120Semaste 461292120Semaste if (addr >= lopc && addr < hipc) 462292120Semaste break; 463260684Skaiw } 464292120Semaste 465289071Semaste next_cu: 466289071Semaste if (die != NULL) { 467289071Semaste dwarf_dealloc(dbg, die, DW_DLA_DIE); 468289071Semaste die = NULL; 469289071Semaste } 470260684Skaiw } 471260684Skaiw 472292120Semaste if (ret != DW_DLV_OK || die == NULL) 473292120Semaste goto out; 474292120Semaste 475292120Semaste switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { 476292120Semaste case DW_DLV_OK: 477292120Semaste break; 478292120Semaste case DW_DLV_NO_ENTRY: 479292120Semaste /* If a CU lacks debug info, just skip it. */ 480292120Semaste goto out; 481292120Semaste default: 482292120Semaste warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 483292120Semaste goto out; 484292120Semaste } 485292120Semaste 486292120Semaste plineaddr = ~0ULL; 487292120Semaste plineno = 0; 488292120Semaste pfile = unknown; 489292120Semaste for (i = 0; i < lcount; i++) { 490292120Semaste if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 491292120Semaste warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); 492292120Semaste goto out; 493292120Semaste } 494292120Semaste if (dwarf_lineno(lbuf[i], &lineno, &de)) { 495292120Semaste warnx("dwarf_lineno: %s", dwarf_errmsg(de)); 496292120Semaste goto out; 497292120Semaste } 498292120Semaste if (dwarf_linesrc(lbuf[i], &file0, &de)) { 499292120Semaste warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); 500292120Semaste } else 501292120Semaste file = file0; 502292120Semaste if (addr == lineaddr) 503292120Semaste goto out; 504292120Semaste else if (addr < lineaddr && addr > plineaddr) { 505292120Semaste lineno = plineno; 506292120Semaste file = pfile; 507292120Semaste goto out; 508292120Semaste } 509292120Semaste plineaddr = lineaddr; 510292120Semaste plineno = lineno; 511292120Semaste pfile = file; 512292120Semaste } 513292120Semaste 514260684Skaiwout: 515292120Semaste f = NULL; 516260684Skaiw funcname = NULL; 517292120Semaste if (ret == DW_DLV_OK && (func || inlines) && cu != NULL) { 518292120Semaste if (cu->srcfiles == NULL) 519292120Semaste if (dwarf_srcfiles(die, &cu->srcfiles, &cu->nsrcfiles, 520292120Semaste &de)) 521292120Semaste warnx("dwarf_srcfiles: %s", dwarf_errmsg(de)); 522292120Semaste if (STAILQ_EMPTY(&cu->funclist)) { 523292120Semaste collect_func(dbg, die, NULL, cu); 524292120Semaste die = NULL; 525292120Semaste } 526292120Semaste f = search_func(cu, addr); 527292120Semaste if (f != NULL) 528292120Semaste funcname = f->name; 529289071Semaste } 530260684Skaiw 531292120Semaste if (print_addr) { 532292120Semaste if ((ec = gelf_getclass(e)) == ELFCLASSNONE) { 533292120Semaste warnx("gelf_getclass failed: %s", elf_errmsg(-1)); 534292120Semaste ec = ELFCLASS64; 535292120Semaste } 536292120Semaste if (ec == ELFCLASS32) { 537292120Semaste if (pretty_print) 538292120Semaste printf("0x%08jx: ", (uintmax_t) addr); 539292120Semaste else 540292120Semaste printf("0x%08jx\n", (uintmax_t) addr); 541292120Semaste } else { 542292120Semaste if (pretty_print) 543292120Semaste printf("0x%016jx: ", (uintmax_t) addr); 544292120Semaste else 545292120Semaste printf("0x%016jx\n", (uintmax_t) addr); 546292120Semaste } 547292120Semaste } 548292120Semaste 549260684Skaiw if (func) { 550260684Skaiw if (funcname == NULL) 551292120Semaste funcname = unknown; 552292120Semaste if (demangle && !elftc_demangle(funcname, demangled, 553292120Semaste sizeof(demangled), 0)) { 554292120Semaste if (pretty_print) 555292120Semaste printf("%s at ", demangled); 556292120Semaste else 557292120Semaste printf("%s\n", demangled); 558292120Semaste } else { 559292120Semaste if (pretty_print) 560292120Semaste printf("%s at ", funcname); 561292120Semaste else 562292120Semaste printf("%s\n", funcname); 563292120Semaste } 564260684Skaiw } 565260684Skaiw 566295577Semaste (void) printf("%s:%ju\n", base ? basename(file) : file, 567295577Semaste (uintmax_t) lineno); 568260684Skaiw 569292120Semaste if (ret == DW_DLV_OK && inlines && cu != NULL && 570292120Semaste cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL) 571292120Semaste print_inlines(cu, f->inlined_caller, f->call_file, 572292120Semaste f->call_line); 573292120Semaste 574289071Semaste if (die != NULL) 575289071Semaste dwarf_dealloc(dbg, die, DW_DLA_DIE); 576289071Semaste 577260684Skaiw /* 578260684Skaiw * Reset internal CU pointer, so we will start from the first CU 579260684Skaiw * next round. 580260684Skaiw */ 581260684Skaiw while (ret != DW_DLV_NO_ENTRY) { 582260684Skaiw if (ret == DW_DLV_ERROR) 583260684Skaiw errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", 584260684Skaiw dwarf_errmsg(de)); 585260684Skaiw ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 586260684Skaiw &de); 587260684Skaiw } 588260684Skaiw} 589260684Skaiw 590260684Skaiwstatic void 591260684Skaiwfind_section_base(const char *exe, Elf *e, const char *section) 592260684Skaiw{ 593260684Skaiw Dwarf_Addr off; 594260684Skaiw Elf_Scn *scn; 595260684Skaiw GElf_Ehdr eh; 596260684Skaiw GElf_Shdr sh; 597260684Skaiw size_t shstrndx; 598260684Skaiw int elferr; 599260684Skaiw const char *name; 600260684Skaiw 601260684Skaiw if (gelf_getehdr(e, &eh) != &eh) { 602260684Skaiw warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 603260684Skaiw return; 604260684Skaiw } 605260684Skaiw 606260684Skaiw if (!elf_getshstrndx(e, &shstrndx)) { 607260684Skaiw warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 608260684Skaiw return; 609260684Skaiw } 610260684Skaiw 611260684Skaiw (void) elf_errno(); 612260684Skaiw off = 0; 613260684Skaiw scn = NULL; 614260684Skaiw while ((scn = elf_nextscn(e, scn)) != NULL) { 615260684Skaiw if (gelf_getshdr(scn, &sh) == NULL) { 616260684Skaiw warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 617260684Skaiw continue; 618260684Skaiw } 619260684Skaiw if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) 620260684Skaiw goto next; 621260684Skaiw if (!strcmp(section, name)) { 622260684Skaiw if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { 623260684Skaiw /* 624260684Skaiw * For executables, section base is the virtual 625260684Skaiw * address of the specified section. 626260684Skaiw */ 627260684Skaiw section_base = sh.sh_addr; 628260684Skaiw } else if (eh.e_type == ET_REL) { 629260684Skaiw /* 630260684Skaiw * For relocatables, section base is the 631260684Skaiw * relative offset of the specified section 632260684Skaiw * to the start of the first section. 633260684Skaiw */ 634260684Skaiw section_base = off; 635260684Skaiw } else 636260684Skaiw warnx("unknown e_type %u", eh.e_type); 637260684Skaiw return; 638260684Skaiw } 639260684Skaiw next: 640260684Skaiw off += sh.sh_size; 641260684Skaiw } 642260684Skaiw elferr = elf_errno(); 643260684Skaiw if (elferr != 0) 644260684Skaiw warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 645260684Skaiw 646260684Skaiw errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); 647260684Skaiw} 648260684Skaiw 649260684Skaiwint 650260684Skaiwmain(int argc, char **argv) 651260684Skaiw{ 652260684Skaiw Elf *e; 653260684Skaiw Dwarf_Debug dbg; 654260684Skaiw Dwarf_Error de; 655260684Skaiw const char *exe, *section; 656260684Skaiw char line[1024]; 657260684Skaiw int fd, i, opt; 658260684Skaiw 659260684Skaiw exe = NULL; 660260684Skaiw section = NULL; 661292120Semaste while ((opt = getopt_long(argc, argv, "ab:Ce:fij:psHV", longopts, 662292120Semaste NULL)) != -1) { 663260684Skaiw switch (opt) { 664292120Semaste case 'a': 665292120Semaste print_addr = 1; 666292120Semaste break; 667260684Skaiw case 'b': 668260684Skaiw /* ignored */ 669260684Skaiw break; 670260684Skaiw case 'C': 671260684Skaiw demangle = 1; 672260684Skaiw break; 673260684Skaiw case 'e': 674260684Skaiw exe = optarg; 675260684Skaiw break; 676260684Skaiw case 'f': 677260684Skaiw func = 1; 678260684Skaiw break; 679292120Semaste case 'i': 680292120Semaste inlines = 1; 681292120Semaste break; 682260684Skaiw case 'j': 683260684Skaiw section = optarg; 684260684Skaiw break; 685292120Semaste case 'p': 686292120Semaste pretty_print = 1; 687292120Semaste break; 688260684Skaiw case 's': 689260684Skaiw base = 1; 690260684Skaiw break; 691260684Skaiw case 'H': 692260684Skaiw usage(); 693260684Skaiw case 'V': 694260684Skaiw version(); 695260684Skaiw default: 696260684Skaiw usage(); 697260684Skaiw } 698260684Skaiw } 699260684Skaiw 700260684Skaiw argv += optind; 701260684Skaiw argc -= optind; 702260684Skaiw 703260684Skaiw if (exe == NULL) 704260684Skaiw exe = "a.out"; 705260684Skaiw 706260684Skaiw if ((fd = open(exe, O_RDONLY)) < 0) 707260684Skaiw err(EXIT_FAILURE, "%s", exe); 708260684Skaiw 709260684Skaiw if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) 710260684Skaiw errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); 711260684Skaiw 712260684Skaiw if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) 713260684Skaiw errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); 714260684Skaiw 715260684Skaiw if (section) 716260684Skaiw find_section_base(exe, e, section); 717260684Skaiw else 718260684Skaiw section_base = 0; 719260684Skaiw 720260684Skaiw if (argc > 0) 721260684Skaiw for (i = 0; i < argc; i++) 722292120Semaste translate(dbg, e, argv[i]); 723317623Semaste else { 724317623Semaste setvbuf(stdout, NULL, _IOLBF, 0); 725317623Semaste while (fgets(line, sizeof(line), stdin) != NULL) 726292120Semaste translate(dbg, e, line); 727317623Semaste } 728260684Skaiw 729260684Skaiw dwarf_finish(dbg, &de); 730260684Skaiw 731260684Skaiw (void) elf_end(e); 732260684Skaiw 733260684Skaiw exit(0); 734260684Skaiw} 735