db_dwarf.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /* $OpenBSD: db_dwarf.c,v 1.2 2015/07/07 19:31:02 matthew Exp $ */
  2. /*
  3. * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #ifdef _KERNEL
  18. #include <sys/param.h>
  19. #include <sys/stdint.h>
  20. #include <sys/systm.h>
  21. #include <sys/types.h>
  22. #include <ddb/db_dwarf.h>
  23. #ifdef DIAGNOSTIC
  24. #define DWARN(fmt, ...) printf("ddb: " fmt "\n", __VA_ARGS__)
  25. #else
  26. #define DWARN(fmt, ...) ((void)0)
  27. #endif
  28. #else /* _KERNEL */
  29. #include <err.h>
  30. #include <stdbool.h>
  31. #include <stdint.h>
  32. #include <string.h>
  33. #define DWARN warnx
  34. #endif /* _KERNEL */
  35. enum {
  36. DW_LNS_copy = 1,
  37. DW_LNS_advance_pc = 2,
  38. DW_LNS_advance_line = 3,
  39. DW_LNS_set_file = 4,
  40. DW_LNS_set_column = 5,
  41. DW_LNS_negate_stmt = 6,
  42. DW_LNS_set_basic_block = 7,
  43. DW_LNS_const_add_pc = 8,
  44. DW_LNS_fixed_advance_pc = 9,
  45. DW_LNS_set_prologue_end = 10,
  46. DW_LNS_set_epilogue_begin = 11,
  47. };
  48. enum {
  49. DW_LNE_end_sequence = 1,
  50. DW_LNE_set_address = 2,
  51. DW_LNE_define_file = 3,
  52. };
  53. struct dwbuf {
  54. const char *buf;
  55. size_t len;
  56. };
  57. static inline bool
  58. read_bytes(struct dwbuf *d, void *v, size_t n)
  59. {
  60. if (d->len < n)
  61. return (false);
  62. memcpy(v, d->buf, n);
  63. d->buf += n;
  64. d->len -= n;
  65. return (true);
  66. }
  67. static bool
  68. read_s8(struct dwbuf *d, int8_t *v)
  69. {
  70. return (read_bytes(d, v, sizeof(*v)));
  71. }
  72. static bool
  73. read_u8(struct dwbuf *d, uint8_t *v)
  74. {
  75. return (read_bytes(d, v, sizeof(*v)));
  76. }
  77. static bool
  78. read_u16(struct dwbuf *d, uint16_t *v)
  79. {
  80. return (read_bytes(d, v, sizeof(*v)));
  81. }
  82. static bool
  83. read_u32(struct dwbuf *d, uint32_t *v)
  84. {
  85. return (read_bytes(d, v, sizeof(*v)));
  86. }
  87. static bool
  88. read_u64(struct dwbuf *d, uint64_t *v)
  89. {
  90. return (read_bytes(d, v, sizeof(*v)));
  91. }
  92. /* Read a DWARF LEB128 (little-endian base-128) value. */
  93. static bool
  94. read_leb128(struct dwbuf *d, uint64_t *v, bool signextend)
  95. {
  96. unsigned int shift = 0;
  97. uint64_t res = 0;
  98. uint8_t x;
  99. while (shift < 64 && read_u8(d, &x)) {
  100. res |= (uint64_t)(x & 0x7f) << shift;
  101. shift += 7;
  102. if ((x & 0x80) == 0) {
  103. if (signextend && shift < 64 && (x & 0x40) != 0)
  104. res |= ~(uint64_t)0 << shift;
  105. *v = res;
  106. return (true);
  107. }
  108. }
  109. return (false);
  110. }
  111. static bool
  112. read_sleb128(struct dwbuf *d, int64_t *v)
  113. {
  114. return (read_leb128(d, (uint64_t *)v, true));
  115. }
  116. static bool
  117. read_uleb128(struct dwbuf *d, uint64_t *v)
  118. {
  119. return (read_leb128(d, v, false));
  120. }
  121. /* Read a NUL terminated string. */
  122. static bool
  123. read_string(struct dwbuf *d, const char **s)
  124. {
  125. const char *end = memchr(d->buf, '\0', d->len);
  126. if (end == NULL)
  127. return (false);
  128. size_t n = end - d->buf + 1;
  129. *s = d->buf;
  130. d->buf += n;
  131. d->len -= n;
  132. return (true);
  133. }
  134. static bool
  135. read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)
  136. {
  137. if (d->len < n)
  138. return (false);
  139. v->buf = d->buf;
  140. v->len = n;
  141. d->buf += n;
  142. d->len -= n;
  143. return (true);
  144. }
  145. static bool
  146. skip_bytes(struct dwbuf *d, size_t n)
  147. {
  148. if (d->len < n)
  149. return (false);
  150. d->buf += n;
  151. d->len -= n;
  152. return (true);
  153. }
  154. static bool
  155. read_filename(struct dwbuf *names, const char **outdirname,
  156. const char **outbasename, uint8_t opcode_base, uint64_t file)
  157. {
  158. if (file == 0)
  159. return (false);
  160. /* Skip over opcode table. */
  161. size_t i;
  162. for (i = 1; i < opcode_base; i++) {
  163. uint64_t dummy;
  164. if (!read_uleb128(names, &dummy))
  165. return (false);
  166. }
  167. /* Skip over directory name table for now. */
  168. struct dwbuf dirnames = *names;
  169. for (;;) {
  170. const char *name;
  171. if (!read_string(names, &name))
  172. return (false);
  173. if (*name == '\0')
  174. break;
  175. }
  176. /* Locate file entry. */
  177. const char *basename = NULL;
  178. uint64_t dir = 0;
  179. for (i = 0; i < file; i++) {
  180. uint64_t mtime, size;
  181. if (!read_string(names, &basename) || *basename == '\0' ||
  182. !read_uleb128(names, &dir) ||
  183. !read_uleb128(names, &mtime) ||
  184. !read_uleb128(names, &size))
  185. return (false);
  186. }
  187. const char *dirname = NULL;
  188. for (i = 0; i < dir; i++) {
  189. if (!read_string(&dirnames, &dirname) || *dirname == '\0')
  190. return (false);
  191. }
  192. *outdirname = dirname;
  193. *outbasename = basename;
  194. return (true);
  195. }
  196. bool
  197. db_dwarf_line_at_pc(const char *linetab, size_t linetabsize, uintptr_t pc,
  198. const char **outdirname, const char **outbasename, int *outline)
  199. {
  200. struct dwbuf table = { .buf = linetab, .len = linetabsize };
  201. /*
  202. * For simplicity, we simply brute force search through the entire
  203. * line table each time.
  204. */
  205. uint32_t unitsize;
  206. struct dwbuf unit;
  207. next:
  208. /* Line tables are a sequence of compilation unit entries. */
  209. if (!read_u32(&table, &unitsize) || unitsize >= 0xfffffff0 ||
  210. !read_buf(&table, &unit, unitsize))
  211. return (false);
  212. uint16_t version;
  213. uint32_t header_size;
  214. if (!read_u16(&unit, &version) || version > 2 ||
  215. !read_u32(&unit, &header_size))
  216. goto next;
  217. struct dwbuf headerstart = unit;
  218. uint8_t min_insn_length, default_is_stmt, line_range, opcode_base;
  219. int8_t line_base;
  220. if (!read_u8(&unit, &min_insn_length) ||
  221. !read_u8(&unit, &default_is_stmt) ||
  222. !read_s8(&unit, &line_base) ||
  223. !read_u8(&unit, &line_range) ||
  224. !read_u8(&unit, &opcode_base))
  225. goto next;
  226. /*
  227. * Directory and file names are next in the header, but for now we
  228. * skip directly to the line number program.
  229. */
  230. struct dwbuf names = unit;
  231. unit = headerstart;
  232. if (!skip_bytes(&unit, header_size))
  233. return (false);
  234. /* VM registers. */
  235. uint64_t address = 0, file = 1, line = 1, column = 0;
  236. uint8_t is_stmt = default_is_stmt;
  237. bool basic_block = false, end_sequence = false;
  238. bool prologue_end = false, epilogue_begin = false;
  239. /* Last line table entry emitted, if any. */
  240. bool have_last = false;
  241. uint64_t last_line = 0, last_file = 0;
  242. /* Time to run the line program. */
  243. uint8_t opcode;
  244. while (read_u8(&unit, &opcode)) {
  245. bool emit = false, reset_basic_block = false;
  246. if (opcode >= opcode_base) {
  247. /* "Special" opcodes. */
  248. uint8_t diff = opcode - opcode_base;
  249. address += diff / line_range;
  250. line += line_base + diff % line_range;
  251. emit = true;
  252. } else if (opcode == 0) {
  253. /* "Extended" opcodes. */
  254. uint64_t extsize;
  255. struct dwbuf extra;
  256. if (!read_uleb128(&unit, &extsize) ||
  257. !read_buf(&unit, &extra, extsize) ||
  258. !read_u8(&extra, &opcode))
  259. goto next;
  260. switch (opcode) {
  261. case DW_LNE_end_sequence:
  262. emit = true;
  263. end_sequence = true;
  264. break;
  265. case DW_LNE_set_address:
  266. switch (extra.len) {
  267. case 4: {
  268. uint32_t address32;
  269. if (!read_u32(&extra, &address32))
  270. goto next;
  271. address = address32;
  272. break;
  273. }
  274. case 8:
  275. if (!read_u64(&extra, &address))
  276. goto next;
  277. break;
  278. default:
  279. DWARN("unexpected address length: %zu",
  280. extra.len);
  281. goto next;
  282. }
  283. break;
  284. case DW_LNE_define_file:
  285. /* XXX: hope this isn't needed */
  286. default:
  287. DWARN("unknown extended opcode: %d", opcode);
  288. goto next;
  289. }
  290. } else {
  291. /* "Standard" opcodes. */
  292. switch (opcode) {
  293. case DW_LNS_copy:
  294. emit = true;
  295. reset_basic_block = true;
  296. break;
  297. case DW_LNS_advance_pc: {
  298. uint64_t delta;
  299. if (!read_uleb128(&unit, &delta))
  300. goto next;
  301. address += delta * min_insn_length;
  302. break;
  303. }
  304. case DW_LNS_advance_line: {
  305. int64_t delta;
  306. if (!read_sleb128(&unit, &delta))
  307. goto next;
  308. line += delta;
  309. break;
  310. }
  311. case DW_LNS_set_file:
  312. if (!read_uleb128(&unit, &file))
  313. goto next;
  314. break;
  315. case DW_LNS_set_column:
  316. if (!read_uleb128(&unit, &column))
  317. goto next;
  318. break;
  319. case DW_LNS_negate_stmt:
  320. is_stmt = !is_stmt;
  321. break;
  322. case DW_LNS_set_basic_block:
  323. basic_block = true;
  324. break;
  325. case DW_LNS_const_add_pc:
  326. address += (255 - opcode_base) / line_range;
  327. break;
  328. case DW_LNS_set_prologue_end:
  329. prologue_end = true;
  330. break;
  331. case DW_LNS_set_epilogue_begin:
  332. epilogue_begin = true;
  333. break;
  334. default:
  335. DWARN("unknown standard opcode: %d", opcode);
  336. goto next;
  337. }
  338. }
  339. if (emit) {
  340. if (address > pc) {
  341. /* Found an entry after our target PC. */
  342. if (!have_last) {
  343. /* Give up on this program. */
  344. break;
  345. }
  346. /* Return the last entry. */
  347. *outline = last_line;
  348. return (read_filename(&names, outdirname,
  349. outbasename, opcode_base, last_file));
  350. }
  351. last_file = file;
  352. last_line = line;
  353. have_last = true;
  354. }
  355. if (reset_basic_block)
  356. basic_block = false;
  357. }
  358. goto next;
  359. }
  360. #ifndef _KERNEL
  361. #include <sys/endian.h>
  362. #include <sys/mman.h>
  363. #include <sys/stat.h>
  364. #include <elf_abi.h>
  365. #include <fcntl.h>
  366. #include <stdio.h>
  367. #include <stdlib.h>
  368. #include <unistd.h>
  369. #ifndef ELFDATA
  370. #if BYTE_ORDER == LITTLE_ENDIAN
  371. #define ELFDATA ELFDATA2LSB
  372. #elif BYTE_ORDER == BIG_ENDIAN
  373. #define ELFDATA ELFDATA2MSB
  374. #else
  375. #error Unsupported byte order
  376. #endif
  377. #endif /* !ELFDATA */
  378. static void
  379. usage()
  380. {
  381. extern const char *__progname;
  382. errx(1, "usage: %s [-s] [-e filename] [addr addr ...]", __progname);
  383. }
  384. /*
  385. * Basic addr2line clone for stand-alone testing.
  386. */
  387. int
  388. main(int argc, char *argv[])
  389. {
  390. const char *filename = "a.out";
  391. int ch;
  392. bool showdir = true;
  393. while ((ch = getopt(argc, argv, "e:s")) != EOF) {
  394. switch (ch) {
  395. case 'e':
  396. filename = optarg;
  397. break;
  398. case 's':
  399. showdir = false;
  400. break;
  401. default:
  402. usage();
  403. }
  404. }
  405. argc -= optind;
  406. argv += optind;
  407. /* Start by mapping the full file into memory. */
  408. int fd = open(filename, O_RDONLY);
  409. if (fd == -1)
  410. err(1, "open");
  411. struct stat st;
  412. if (fstat(fd, &st) == -1)
  413. err(1, "fstat");
  414. if (st.st_size < (off_t)sizeof(Elf_Ehdr))
  415. errx(1, "file too small to be ELF");
  416. if ((uintmax_t)st.st_size > SIZE_MAX)
  417. errx(1, "file too big to fit memory");
  418. size_t filesize = st.st_size;
  419. const char *p = mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
  420. if (p == MAP_FAILED)
  421. err(1, "mmap");
  422. close(fd);
  423. /* Read and validate ELF header. */
  424. Elf_Ehdr ehdr;
  425. memcpy(&ehdr, p, sizeof(ehdr));
  426. if (!IS_ELF(ehdr))
  427. errx(1, "file is not ELF");
  428. if (ehdr.e_ident[EI_CLASS] != ELFCLASS)
  429. errx(1, "unexpected word size");
  430. if (ehdr.e_ident[EI_DATA] != ELFDATA)
  431. errx(1, "unexpected data format");
  432. if (ehdr.e_shoff > filesize)
  433. errx(1, "bogus section table offset");
  434. if (ehdr.e_shentsize < sizeof(Elf_Shdr))
  435. errx(1, "unexpected section header size");
  436. if (ehdr.e_shnum > (filesize - ehdr.e_shoff) / ehdr.e_shentsize)
  437. errx(1, "bogus section header count");
  438. if (ehdr.e_shstrndx >= ehdr.e_shnum)
  439. errx(1, "bogus string table index");
  440. /* Find section header string table location and size. */
  441. Elf_Shdr shdr;
  442. memcpy(&shdr, p + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize,
  443. sizeof(shdr));
  444. if (shdr.sh_type != SHT_STRTAB)
  445. errx(1, "unexpected string table type");
  446. if (shdr.sh_offset > filesize)
  447. errx(1, "bogus string table offset");
  448. if (shdr.sh_size > filesize - shdr.sh_offset)
  449. errx(1, "bogus string table size");
  450. const char *shstrtab = p + shdr.sh_offset;
  451. size_t shstrtabsize = shdr.sh_size;
  452. /* Search through section table for .debug_line section. */
  453. size_t i;
  454. for (i = 0; i < ehdr.e_shnum; i++) {
  455. memcpy(&shdr, p + ehdr.e_shoff + i * ehdr.e_shentsize,
  456. sizeof(shdr));
  457. if (0 == strncmp(".debug_line", shstrtab + shdr.sh_name,
  458. shstrtabsize - shdr.sh_name))
  459. break;
  460. }
  461. if (i == ehdr.e_shnum)
  462. errx(1, "no DWARF line number table found");
  463. if (shdr.sh_offset > filesize)
  464. errx(1, "bogus line table offset");
  465. if (shdr.sh_size > filesize - shdr.sh_offset)
  466. errx(1, "bogus line table size");
  467. const char *linetab = p + shdr.sh_offset;
  468. size_t linetabsize = shdr.sh_size;
  469. const char *addrstr;
  470. while ((addrstr = *argv++) != NULL) {
  471. unsigned long addr = strtoul(addrstr, NULL, 16);
  472. const char *dir, *file;
  473. int line;
  474. if (!db_dwarf_line_at_pc(linetab, linetabsize, addr,
  475. &dir, &file, &line)) {
  476. dir = NULL;
  477. file = "??";
  478. line = 0;
  479. }
  480. if (showdir && dir != NULL)
  481. printf("%s/", dir);
  482. printf("%s:%d\n", file, line);
  483. }
  484. return (0);
  485. }
  486. #endif /* !_KERNEL */