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