1 /*- 2 * Copyright (c) 2009 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <dwarf.h> 29 #include <err.h> 30 #include <fcntl.h> 31 #include <gelf.h> 32 #include <getopt.h> 33 #include <libdwarf.h> 34 #include <libelftc.h> 35 #include <libgen.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 #include "_elftc.h" 41 42 ELFTC_VCSID("$Id: addr2line.c 3197 2015-05-12 21:01:31Z emaste $"); 43 44 static struct option longopts[] = { 45 {"target" , required_argument, NULL, 'b'}, 46 {"demangle", no_argument, NULL, 'C'}, 47 {"exe", required_argument, NULL, 'e'}, 48 {"functions", no_argument, NULL, 'f'}, 49 {"section", required_argument, NULL, 'j'}, 50 {"basename", no_argument, NULL, 's'}, 51 {"help", no_argument, NULL, 'H'}, 52 {"version", no_argument, NULL, 'V'}, 53 {NULL, 0, NULL, 0} 54 }; 55 static int demangle, func, base; 56 static char unknown[] = { '?', '?', '\0' }; 57 static Dwarf_Addr section_base; 58 59 #define USAGE_MESSAGE "\ 60 Usage: %s [options] hexaddress...\n\ 61 Map program addresses to source file names and line numbers.\n\n\ 62 Options:\n\ 63 -b TGT | --target=TGT (Accepted but ignored).\n\ 64 -e EXE | --exec=EXE Use program \"EXE\" to translate addresses.\n\ 65 -f | --functions Display function names.\n\ 66 -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ 67 -s | --basename Only show the base name for each file name.\n\ 68 -C | --demangle Demangle C++ names.\n\ 69 -H | --help Print a help message.\n\ 70 -V | --version Print a version identifier and exit.\n" 71 72 static void 73 usage(void) 74 { 75 (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 76 exit(1); 77 } 78 79 static void 80 version(void) 81 { 82 83 fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 84 exit(0); 85 } 86 87 /* 88 * Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't 89 * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1) 90 * generate DW_AT_high_pc as an offset from DW_AT_low_pc. 91 * 92 * "If the value of the DW_AT_high_pc is of class address, it is the 93 * relocated address of the first location past the last instruction 94 * associated with the entity; if it is of class constant, the value 95 * is an unsigned integer offset which when added to the low PC gives 96 * the address of the first location past the last instruction 97 * associated with the entity." 98 * 99 * DWARF4 spec, section 2.17.2. 100 */ 101 static int 102 handle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc) 103 { 104 Dwarf_Error de; 105 Dwarf_Half form; 106 Dwarf_Attribute at; 107 int ret; 108 109 ret = dwarf_attr(die, DW_AT_high_pc, &at, &de); 110 if (ret == DW_DLV_ERROR) { 111 warnx("dwarf_attr failed: %s", dwarf_errmsg(de)); 112 return (ret); 113 } 114 ret = dwarf_whatform(at, &form, &de); 115 if (ret == DW_DLV_ERROR) { 116 warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); 117 return (ret); 118 } 119 if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT) 120 *hipc += lopc; 121 122 return (DW_DLV_OK); 123 } 124 125 static void 126 search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr, 127 const char **rlt_func) 128 { 129 Dwarf_Die ret_die, spec_die; 130 Dwarf_Error de; 131 Dwarf_Half tag; 132 Dwarf_Unsigned lopc, hipc; 133 Dwarf_Off ref; 134 Dwarf_Attribute sub_at, spec_at; 135 char *func0; 136 int ret; 137 138 if (*rlt_func != NULL) 139 return; 140 141 if (dwarf_tag(die, &tag, &de)) { 142 warnx("dwarf_tag: %s", dwarf_errmsg(de)); 143 goto cont_search; 144 } 145 if (tag == DW_TAG_subprogram) { 146 if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || 147 dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) 148 goto cont_search; 149 if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) 150 goto cont_search; 151 if (addr < lopc || addr >= hipc) 152 goto cont_search; 153 154 /* Found it! */ 155 156 *rlt_func = unknown; 157 ret = dwarf_attr(die, DW_AT_name, &sub_at, &de); 158 if (ret == DW_DLV_ERROR) 159 return; 160 if (ret == DW_DLV_OK) { 161 if (dwarf_formstring(sub_at, &func0, &de)) 162 *rlt_func = unknown; 163 else 164 *rlt_func = func0; 165 return; 166 } 167 168 /* 169 * If DW_AT_name is not present, but DW_AT_specification is 170 * present, then probably the actual name is in the DIE 171 * referenced by DW_AT_specification. 172 */ 173 if (dwarf_attr(die, DW_AT_specification, &spec_at, &de)) 174 return; 175 if (dwarf_global_formref(spec_at, &ref, &de)) 176 return; 177 if (dwarf_offdie(dbg, ref, &spec_die, &de)) 178 return; 179 if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de)) 180 *rlt_func = unknown; 181 182 return; 183 } 184 185 cont_search: 186 187 /* Search children. */ 188 ret = dwarf_child(die, &ret_die, &de); 189 if (ret == DW_DLV_ERROR) 190 errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de)); 191 else if (ret == DW_DLV_OK) 192 search_func(dbg, ret_die, addr, rlt_func); 193 194 /* Search sibling. */ 195 ret = dwarf_siblingof(dbg, die, &ret_die, &de); 196 if (ret == DW_DLV_ERROR) 197 errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); 198 else if (ret == DW_DLV_OK) 199 search_func(dbg, ret_die, addr, rlt_func); 200 } 201 202 static void 203 translate(Dwarf_Debug dbg, const char* addrstr) 204 { 205 Dwarf_Die die; 206 Dwarf_Line *lbuf; 207 Dwarf_Error de; 208 Dwarf_Half tag; 209 Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; 210 Dwarf_Signed lcount; 211 Dwarf_Addr lineaddr, plineaddr; 212 const char *funcname; 213 char *file, *file0, *pfile; 214 char demangled[1024]; 215 int i, ret; 216 217 addr = strtoull(addrstr, NULL, 16); 218 addr += section_base; 219 lineno = 0; 220 file = unknown; 221 222 while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 223 &de)) == DW_DLV_OK) { 224 die = NULL; 225 while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { 226 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 227 warnx("dwarf_tag failed: %s", 228 dwarf_errmsg(de)); 229 goto out; 230 } 231 /* XXX: What about DW_TAG_partial_unit? */ 232 if (tag == DW_TAG_compile_unit) 233 break; 234 } 235 if (die == NULL) { 236 warnx("could not find DW_TAG_compile_unit die"); 237 goto out; 238 } 239 if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) && 240 !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) { 241 /* 242 * Check if the address falls into the PC range of 243 * this CU. 244 */ 245 if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) 246 continue; 247 if (addr < lopc || addr >= hipc) 248 continue; 249 } 250 251 switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { 252 case DW_DLV_OK: 253 break; 254 case DW_DLV_NO_ENTRY: 255 /* If one CU lacks debug info, just skip it. */ 256 continue; 257 default: 258 warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 259 goto out; 260 } 261 262 plineaddr = ~0ULL; 263 plineno = 0; 264 pfile = unknown; 265 for (i = 0; i < lcount; i++) { 266 if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 267 warnx("dwarf_lineaddr: %s", 268 dwarf_errmsg(de)); 269 goto out; 270 } 271 if (dwarf_lineno(lbuf[i], &lineno, &de)) { 272 warnx("dwarf_lineno: %s", 273 dwarf_errmsg(de)); 274 goto out; 275 } 276 if (dwarf_linesrc(lbuf[i], &file0, &de)) { 277 warnx("dwarf_linesrc: %s", 278 dwarf_errmsg(de)); 279 } else 280 file = file0; 281 if (addr == lineaddr) 282 goto out; 283 else if (addr < lineaddr && addr > plineaddr) { 284 lineno = plineno; 285 file = pfile; 286 goto out; 287 } 288 plineaddr = lineaddr; 289 plineno = lineno; 290 pfile = file; 291 } 292 } 293 294 out: 295 funcname = NULL; 296 if (ret == DW_DLV_OK && func) 297 search_func(dbg, die, addr, &funcname); 298 299 if (func) { 300 if (funcname == NULL) 301 funcname = unknown; 302 if (demangle && 303 !elftc_demangle(funcname, demangled, sizeof(demangled), 0)) 304 printf("%s\n", demangled); 305 else 306 printf("%s\n", funcname); 307 } 308 309 (void) printf("%s:%ju\n", base ? basename(file) : file, lineno); 310 311 /* 312 * Reset internal CU pointer, so we will start from the first CU 313 * next round. 314 */ 315 while (ret != DW_DLV_NO_ENTRY) { 316 if (ret == DW_DLV_ERROR) 317 errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", 318 dwarf_errmsg(de)); 319 ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 320 &de); 321 } 322 } 323 324 static void 325 find_section_base(const char *exe, Elf *e, const char *section) 326 { 327 Dwarf_Addr off; 328 Elf_Scn *scn; 329 GElf_Ehdr eh; 330 GElf_Shdr sh; 331 size_t shstrndx; 332 int elferr; 333 const char *name; 334 335 if (gelf_getehdr(e, &eh) != &eh) { 336 warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 337 return; 338 } 339 340 if (!elf_getshstrndx(e, &shstrndx)) { 341 warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 342 return; 343 } 344 345 (void) elf_errno(); 346 off = 0; 347 scn = NULL; 348 while ((scn = elf_nextscn(e, scn)) != NULL) { 349 if (gelf_getshdr(scn, &sh) == NULL) { 350 warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 351 continue; 352 } 353 if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) 354 goto next; 355 if (!strcmp(section, name)) { 356 if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { 357 /* 358 * For executables, section base is the virtual 359 * address of the specified section. 360 */ 361 section_base = sh.sh_addr; 362 } else if (eh.e_type == ET_REL) { 363 /* 364 * For relocatables, section base is the 365 * relative offset of the specified section 366 * to the start of the first section. 367 */ 368 section_base = off; 369 } else 370 warnx("unknown e_type %u", eh.e_type); 371 return; 372 } 373 next: 374 off += sh.sh_size; 375 } 376 elferr = elf_errno(); 377 if (elferr != 0) 378 warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 379 380 errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); 381 } 382 383 int 384 main(int argc, char **argv) 385 { 386 Elf *e; 387 Dwarf_Debug dbg; 388 Dwarf_Error de; 389 const char *exe, *section; 390 char line[1024]; 391 int fd, i, opt; 392 393 exe = NULL; 394 section = NULL; 395 while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) != 396 -1) { 397 switch (opt) { 398 case 'b': 399 /* ignored */ 400 break; 401 case 'C': 402 demangle = 1; 403 break; 404 case 'e': 405 exe = optarg; 406 break; 407 case 'f': 408 func = 1; 409 break; 410 case 'j': 411 section = optarg; 412 break; 413 case 's': 414 base = 1; 415 break; 416 case 'H': 417 usage(); 418 case 'V': 419 version(); 420 default: 421 usage(); 422 } 423 } 424 425 argv += optind; 426 argc -= optind; 427 428 if (exe == NULL) 429 exe = "a.out"; 430 431 if ((fd = open(exe, O_RDONLY)) < 0) 432 err(EXIT_FAILURE, "%s", exe); 433 434 if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) 435 errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); 436 437 if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) 438 errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); 439 440 if (section) 441 find_section_base(exe, e, section); 442 else 443 section_base = 0; 444 445 if (argc > 0) 446 for (i = 0; i < argc; i++) 447 translate(dbg, argv[i]); 448 else 449 while (fgets(line, sizeof(line), stdin) != NULL) { 450 translate(dbg, line); 451 fflush(stdout); 452 } 453 454 dwarf_finish(dbg, &de); 455 456 (void) elf_end(e); 457 458 exit(0); 459 } 460