addr2line.c revision 260684
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/cdefs.h> 28260684Skaiw#include <sys/param.h> 29260684Skaiw#include <dwarf.h> 30260684Skaiw#include <err.h> 31260684Skaiw#include <fcntl.h> 32260684Skaiw#include <gelf.h> 33260684Skaiw#include <getopt.h> 34260684Skaiw#include <libdwarf.h> 35260684Skaiw#include <libelftc.h> 36260684Skaiw#include <libgen.h> 37260684Skaiw#include <stdio.h> 38260684Skaiw#include <stdlib.h> 39260684Skaiw#include <string.h> 40260684Skaiw 41260684Skaiw#include "_elftc.h" 42260684Skaiw 43260684SkaiwELFTC_VCSID("$Id: addr2line.c 2185 2011-11-19 16:07:16Z jkoshy $"); 44260684Skaiw 45260684Skaiwstatic struct option longopts[] = { 46260684Skaiw {"target" , required_argument, NULL, 'b'}, 47260684Skaiw {"demangle", no_argument, NULL, 'C'}, 48260684Skaiw {"exe", required_argument, NULL, 'e'}, 49260684Skaiw {"functions", no_argument, NULL, 'f'}, 50260684Skaiw {"section", required_argument, NULL, 'j'}, 51260684Skaiw {"basename", no_argument, NULL, 's'}, 52260684Skaiw {"help", no_argument, NULL, 'H'}, 53260684Skaiw {"version", no_argument, NULL, 'V'}, 54260684Skaiw {NULL, 0, NULL, 0} 55260684Skaiw}; 56260684Skaiwstatic int demangle, func, base; 57260684Skaiwstatic char unknown[] = { '?', '?', '\0' }; 58260684Skaiwstatic Dwarf_Addr section_base; 59260684Skaiw 60260684Skaiw#define USAGE_MESSAGE "\ 61260684SkaiwUsage: %s [options] hexaddress...\n\ 62260684Skaiw Map program addresses to source file names and line numbers.\n\n\ 63260684Skaiw Options:\n\ 64260684Skaiw -b TGT | --target=TGT (Accepted but ignored).\n\ 65260684Skaiw -e EXE | --exec=EXE Use program \"EXE\" to translate addresses.\n\ 66260684Skaiw -f | --functions Display function names.\n\ 67260684Skaiw -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ 68260684Skaiw -s | --basename Only show the base name for each file name.\n\ 69260684Skaiw -C | --demangle Demangle C++ names.\n\ 70260684Skaiw -H | --help Print a help message.\n\ 71260684Skaiw -V | --version Print a version identifier and exit.\n" 72260684Skaiw 73260684Skaiwstatic void 74260684Skaiwusage(void) 75260684Skaiw{ 76260684Skaiw (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 77260684Skaiw exit(1); 78260684Skaiw} 79260684Skaiw 80260684Skaiwstatic void 81260684Skaiwversion(void) 82260684Skaiw{ 83260684Skaiw 84260684Skaiw fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 85260684Skaiw exit(0); 86260684Skaiw} 87260684Skaiw 88260684Skaiwstatic void 89260684Skaiwsearch_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr, 90260684Skaiw const char **rlt_func) 91260684Skaiw{ 92260684Skaiw Dwarf_Die ret_die, spec_die; 93260684Skaiw Dwarf_Error de; 94260684Skaiw Dwarf_Half tag; 95260684Skaiw Dwarf_Unsigned lopc, hipc; 96260684Skaiw Dwarf_Off ref; 97260684Skaiw Dwarf_Attribute sub_at, spec_at; 98260684Skaiw char *func0; 99260684Skaiw int ret; 100260684Skaiw 101260684Skaiw if (*rlt_func != NULL) 102260684Skaiw return; 103260684Skaiw 104260684Skaiw if (dwarf_tag(die, &tag, &de)) { 105260684Skaiw warnx("dwarf_tag: %s", dwarf_errmsg(de)); 106260684Skaiw goto cont_search; 107260684Skaiw } 108260684Skaiw if (tag == DW_TAG_subprogram) { 109260684Skaiw if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || 110260684Skaiw dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) 111260684Skaiw goto cont_search; 112260684Skaiw if (addr < lopc || addr >= hipc) 113260684Skaiw goto cont_search; 114260684Skaiw 115260684Skaiw /* Found it! */ 116260684Skaiw 117260684Skaiw *rlt_func = unknown; 118260684Skaiw ret = dwarf_attr(die, DW_AT_name, &sub_at, &de); 119260684Skaiw if (ret == DW_DLV_ERROR) 120260684Skaiw return; 121260684Skaiw if (ret == DW_DLV_OK) { 122260684Skaiw if (dwarf_formstring(sub_at, &func0, &de)) 123260684Skaiw *rlt_func = unknown; 124260684Skaiw else 125260684Skaiw *rlt_func = func0; 126260684Skaiw return; 127260684Skaiw } 128260684Skaiw 129260684Skaiw /* 130260684Skaiw * If DW_AT_name is not present, but DW_AT_specification is 131260684Skaiw * present, then probably the actual name is in the DIE 132260684Skaiw * referenced by DW_AT_specification. 133260684Skaiw */ 134260684Skaiw if (dwarf_attr(die, DW_AT_specification, &spec_at, &de)) 135260684Skaiw return; 136260684Skaiw if (dwarf_global_formref(spec_at, &ref, &de)) 137260684Skaiw return; 138260684Skaiw if (dwarf_offdie(dbg, ref, &spec_die, &de)) 139260684Skaiw return; 140260684Skaiw if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de)) 141260684Skaiw *rlt_func = unknown; 142260684Skaiw 143260684Skaiw return; 144260684Skaiw } 145260684Skaiw 146260684Skaiwcont_search: 147260684Skaiw 148260684Skaiw /* Search children. */ 149260684Skaiw ret = dwarf_child(die, &ret_die, &de); 150260684Skaiw if (ret == DW_DLV_ERROR) 151260684Skaiw errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de)); 152260684Skaiw else if (ret == DW_DLV_OK) 153260684Skaiw search_func(dbg, ret_die, addr, rlt_func); 154260684Skaiw 155260684Skaiw /* Search sibling. */ 156260684Skaiw ret = dwarf_siblingof(dbg, die, &ret_die, &de); 157260684Skaiw if (ret == DW_DLV_ERROR) 158260684Skaiw errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); 159260684Skaiw else if (ret == DW_DLV_OK) 160260684Skaiw search_func(dbg, ret_die, addr, rlt_func); 161260684Skaiw} 162260684Skaiw 163260684Skaiwstatic void 164260684Skaiwtranslate(Dwarf_Debug dbg, const char* addrstr) 165260684Skaiw{ 166260684Skaiw Dwarf_Die die; 167260684Skaiw Dwarf_Line *lbuf; 168260684Skaiw Dwarf_Error de; 169260684Skaiw Dwarf_Half tag; 170260684Skaiw Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; 171260684Skaiw Dwarf_Signed lcount; 172260684Skaiw Dwarf_Addr lineaddr, plineaddr; 173260684Skaiw const char *funcname; 174260684Skaiw char *file, *file0, *pfile; 175260684Skaiw char demangled[1024]; 176260684Skaiw int i, ret; 177260684Skaiw 178260684Skaiw addr = strtoull(addrstr, NULL, 16); 179260684Skaiw addr += section_base; 180260684Skaiw lineno = 0; 181260684Skaiw file = unknown; 182260684Skaiw 183260684Skaiw while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 184260684Skaiw &de)) == DW_DLV_OK) { 185260684Skaiw die = NULL; 186260684Skaiw while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { 187260684Skaiw if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 188260684Skaiw warnx("dwarf_tag failed: %s", 189260684Skaiw dwarf_errmsg(de)); 190260684Skaiw goto out; 191260684Skaiw } 192260684Skaiw /* XXX: What about DW_TAG_partial_unit? */ 193260684Skaiw if (tag == DW_TAG_compile_unit) 194260684Skaiw break; 195260684Skaiw } 196260684Skaiw if (die == NULL) { 197260684Skaiw warnx("could not find DW_TAG_compile_unit die"); 198260684Skaiw goto out; 199260684Skaiw } 200260684Skaiw if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) && 201260684Skaiw !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) { 202260684Skaiw /* 203260684Skaiw * Check if the address falls into the PC range of 204260684Skaiw * this CU. 205260684Skaiw */ 206260684Skaiw if (addr < lopc || addr >= hipc) 207260684Skaiw continue; 208260684Skaiw } 209260684Skaiw 210260684Skaiw if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) { 211260684Skaiw warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 212260684Skaiw goto out; 213260684Skaiw } 214260684Skaiw 215260684Skaiw plineaddr = ~0ULL; 216260684Skaiw plineno = 0; 217260684Skaiw pfile = unknown; 218260684Skaiw for (i = 0; i < lcount; i++) { 219260684Skaiw if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 220260684Skaiw warnx("dwarf_lineaddr: %s", 221260684Skaiw dwarf_errmsg(de)); 222260684Skaiw goto out; 223260684Skaiw } 224260684Skaiw if (dwarf_lineno(lbuf[i], &lineno, &de)) { 225260684Skaiw warnx("dwarf_lineno: %s", 226260684Skaiw dwarf_errmsg(de)); 227260684Skaiw goto out; 228260684Skaiw } 229260684Skaiw if (dwarf_linesrc(lbuf[i], &file0, &de)) { 230260684Skaiw warnx("dwarf_linesrc: %s", 231260684Skaiw dwarf_errmsg(de)); 232260684Skaiw } else 233260684Skaiw file = file0; 234260684Skaiw if (addr == lineaddr) 235260684Skaiw goto out; 236260684Skaiw else if (addr < lineaddr && addr > plineaddr) { 237260684Skaiw lineno = plineno; 238260684Skaiw file = pfile; 239260684Skaiw goto out; 240260684Skaiw } 241260684Skaiw plineaddr = lineaddr; 242260684Skaiw plineno = lineno; 243260684Skaiw pfile = file; 244260684Skaiw } 245260684Skaiw } 246260684Skaiw 247260684Skaiwout: 248260684Skaiw funcname = NULL; 249260684Skaiw if (ret == DW_DLV_OK && func) 250260684Skaiw search_func(dbg, die, addr, &funcname); 251260684Skaiw 252260684Skaiw if (func) { 253260684Skaiw if (funcname == NULL) 254260684Skaiw funcname = unknown; 255260684Skaiw if (demangle && 256260684Skaiw !elftc_demangle(funcname, demangled, sizeof(demangled), 0)) 257260684Skaiw printf("%s\n", demangled); 258260684Skaiw else 259260684Skaiw printf("%s\n", funcname); 260260684Skaiw } 261260684Skaiw 262260684Skaiw (void) printf("%s:%ju\n", base ? basename(file) : file, lineno); 263260684Skaiw 264260684Skaiw /* 265260684Skaiw * Reset internal CU pointer, so we will start from the first CU 266260684Skaiw * next round. 267260684Skaiw */ 268260684Skaiw while (ret != DW_DLV_NO_ENTRY) { 269260684Skaiw if (ret == DW_DLV_ERROR) 270260684Skaiw errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", 271260684Skaiw dwarf_errmsg(de)); 272260684Skaiw ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 273260684Skaiw &de); 274260684Skaiw } 275260684Skaiw} 276260684Skaiw 277260684Skaiwstatic void 278260684Skaiwfind_section_base(const char *exe, Elf *e, const char *section) 279260684Skaiw{ 280260684Skaiw Dwarf_Addr off; 281260684Skaiw Elf_Scn *scn; 282260684Skaiw GElf_Ehdr eh; 283260684Skaiw GElf_Shdr sh; 284260684Skaiw size_t shstrndx; 285260684Skaiw int elferr; 286260684Skaiw const char *name; 287260684Skaiw 288260684Skaiw if (gelf_getehdr(e, &eh) != &eh) { 289260684Skaiw warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 290260684Skaiw return; 291260684Skaiw } 292260684Skaiw 293260684Skaiw if (!elf_getshstrndx(e, &shstrndx)) { 294260684Skaiw warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 295260684Skaiw return; 296260684Skaiw } 297260684Skaiw 298260684Skaiw (void) elf_errno(); 299260684Skaiw off = 0; 300260684Skaiw scn = NULL; 301260684Skaiw while ((scn = elf_nextscn(e, scn)) != NULL) { 302260684Skaiw if (gelf_getshdr(scn, &sh) == NULL) { 303260684Skaiw warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 304260684Skaiw continue; 305260684Skaiw } 306260684Skaiw if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) 307260684Skaiw goto next; 308260684Skaiw if (!strcmp(section, name)) { 309260684Skaiw if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { 310260684Skaiw /* 311260684Skaiw * For executables, section base is the virtual 312260684Skaiw * address of the specified section. 313260684Skaiw */ 314260684Skaiw section_base = sh.sh_addr; 315260684Skaiw } else if (eh.e_type == ET_REL) { 316260684Skaiw /* 317260684Skaiw * For relocatables, section base is the 318260684Skaiw * relative offset of the specified section 319260684Skaiw * to the start of the first section. 320260684Skaiw */ 321260684Skaiw section_base = off; 322260684Skaiw } else 323260684Skaiw warnx("unknown e_type %u", eh.e_type); 324260684Skaiw return; 325260684Skaiw } 326260684Skaiw next: 327260684Skaiw off += sh.sh_size; 328260684Skaiw } 329260684Skaiw elferr = elf_errno(); 330260684Skaiw if (elferr != 0) 331260684Skaiw warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 332260684Skaiw 333260684Skaiw errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); 334260684Skaiw} 335260684Skaiw 336260684Skaiwint 337260684Skaiwmain(int argc, char **argv) 338260684Skaiw{ 339260684Skaiw Elf *e; 340260684Skaiw Dwarf_Debug dbg; 341260684Skaiw Dwarf_Error de; 342260684Skaiw const char *exe, *section; 343260684Skaiw char line[1024]; 344260684Skaiw int fd, i, opt; 345260684Skaiw 346260684Skaiw exe = NULL; 347260684Skaiw section = NULL; 348260684Skaiw while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) != 349260684Skaiw -1) { 350260684Skaiw switch (opt) { 351260684Skaiw case 'b': 352260684Skaiw /* ignored */ 353260684Skaiw break; 354260684Skaiw case 'C': 355260684Skaiw demangle = 1; 356260684Skaiw break; 357260684Skaiw case 'e': 358260684Skaiw exe = optarg; 359260684Skaiw break; 360260684Skaiw case 'f': 361260684Skaiw func = 1; 362260684Skaiw break; 363260684Skaiw case 'j': 364260684Skaiw section = optarg; 365260684Skaiw break; 366260684Skaiw case 's': 367260684Skaiw base = 1; 368260684Skaiw break; 369260684Skaiw case 'H': 370260684Skaiw usage(); 371260684Skaiw case 'V': 372260684Skaiw version(); 373260684Skaiw default: 374260684Skaiw usage(); 375260684Skaiw } 376260684Skaiw } 377260684Skaiw 378260684Skaiw argv += optind; 379260684Skaiw argc -= optind; 380260684Skaiw 381260684Skaiw if (exe == NULL) 382260684Skaiw exe = "a.out"; 383260684Skaiw 384260684Skaiw if ((fd = open(exe, O_RDONLY)) < 0) 385260684Skaiw err(EXIT_FAILURE, "%s", exe); 386260684Skaiw 387260684Skaiw if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) 388260684Skaiw errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); 389260684Skaiw 390260684Skaiw if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) 391260684Skaiw errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); 392260684Skaiw 393260684Skaiw if (section) 394260684Skaiw find_section_base(exe, e, section); 395260684Skaiw else 396260684Skaiw section_base = 0; 397260684Skaiw 398260684Skaiw if (argc > 0) 399260684Skaiw for (i = 0; i < argc; i++) 400260684Skaiw translate(dbg, argv[i]); 401260684Skaiw else 402260684Skaiw while (fgets(line, sizeof(line), stdin) != NULL) 403260684Skaiw translate(dbg, line); 404260684Skaiw 405260684Skaiw dwarf_finish(dbg, &de); 406260684Skaiw 407260684Skaiw (void) elf_end(e); 408260684Skaiw 409260684Skaiw exit(0); 410260684Skaiw} 411