/thirdparty/breakpad/third_party/glog/src/symbolize.cc

http://github.com/tomahawk-player/tomahawk · C++ · 681 lines · 451 code · 78 blank · 152 comment · 115 complexity · 80e88657b5e5c9bea49504f059f5083e MD5 · raw file

  1. // Copyright (c) 2006, Google Inc.
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. //
  30. // Author: Satoru Takabayashi
  31. // Stack-footprint reduction work done by Raksit Ashok
  32. //
  33. // Implementation note:
  34. //
  35. // We don't use heaps but only use stacks. We want to reduce the
  36. // stack consumption so that the symbolizer can run on small stacks.
  37. //
  38. // Here are some numbers collected with GCC 4.1.0 on x86:
  39. // - sizeof(Elf32_Sym) = 16
  40. // - sizeof(Elf32_Shdr) = 40
  41. // - sizeof(Elf64_Sym) = 24
  42. // - sizeof(Elf64_Shdr) = 64
  43. //
  44. // This implementation is intended to be async-signal-safe but uses
  45. // some functions which are not guaranteed to be so, such as memchr()
  46. // and memmove(). We assume they are async-signal-safe.
  47. //
  48. #include "utilities.h"
  49. #if defined(HAVE_SYMBOLIZE)
  50. #include <limits>
  51. #include "symbolize.h"
  52. #include "demangle.h"
  53. _START_GOOGLE_NAMESPACE_
  54. // We don't use assert() since it's not guaranteed to be
  55. // async-signal-safe. Instead we define a minimal assertion
  56. // macro. So far, we don't need pretty printing for __FILE__, etc.
  57. // A wrapper for abort() to make it callable in ? :.
  58. static int AssertFail() {
  59. abort();
  60. return 0; // Should not reach.
  61. }
  62. #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
  63. static SymbolizeCallback g_symbolize_callback = NULL;
  64. void InstallSymbolizeCallback(SymbolizeCallback callback) {
  65. g_symbolize_callback = callback;
  66. }
  67. // This function wraps the Demangle function to provide an interface
  68. // where the input symbol is demangled in-place.
  69. // To keep stack consumption low, we would like this function to not
  70. // get inlined.
  71. static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
  72. char demangled[256]; // Big enough for sane demangled symbols.
  73. if (Demangle(out, demangled, sizeof(demangled))) {
  74. // Demangling succeeded. Copy to out if the space allows.
  75. int len = strlen(demangled);
  76. if (len + 1 <= out_size) { // +1 for '\0'.
  77. SAFE_ASSERT(len < sizeof(demangled));
  78. memmove(out, demangled, len + 1);
  79. }
  80. }
  81. }
  82. _END_GOOGLE_NAMESPACE_
  83. #if defined(__ELF__)
  84. #include <dlfcn.h>
  85. #include <elf.h>
  86. #include <errno.h>
  87. #include <fcntl.h>
  88. #include <limits.h>
  89. #include <link.h> // For ElfW() macro.
  90. #include <stdint.h>
  91. #include <stdio.h>
  92. #include <stdlib.h>
  93. #include <stddef.h>
  94. #include <string.h>
  95. #include <sys/stat.h>
  96. #include <sys/types.h>
  97. #include <unistd.h>
  98. #include "symbolize.h"
  99. #include "config.h"
  100. #include "glog/raw_logging.h"
  101. // Re-runs fn until it doesn't cause EINTR.
  102. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
  103. _START_GOOGLE_NAMESPACE_
  104. // Read up to "count" bytes from file descriptor "fd" into the buffer
  105. // starting at "buf" while handling short reads and EINTR. On
  106. // success, return the number of bytes read. Otherwise, return -1.
  107. static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
  108. SAFE_ASSERT(fd >= 0);
  109. SAFE_ASSERT(count >= 0 && count <= std::numeric_limits<ssize_t>::max());
  110. char *buf0 = reinterpret_cast<char *>(buf);
  111. ssize_t num_bytes = 0;
  112. while (num_bytes < count) {
  113. ssize_t len;
  114. NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
  115. if (len < 0) { // There was an error other than EINTR.
  116. return -1;
  117. }
  118. if (len == 0) { // Reached EOF.
  119. break;
  120. }
  121. num_bytes += len;
  122. }
  123. SAFE_ASSERT(num_bytes <= count);
  124. return num_bytes;
  125. }
  126. // Read up to "count" bytes from "offset" in the file pointed by file
  127. // descriptor "fd" into the buffer starting at "buf". On success,
  128. // return the number of bytes read. Otherwise, return -1.
  129. static ssize_t ReadFromOffset(const int fd, void *buf,
  130. const size_t count, const off_t offset) {
  131. off_t off = lseek(fd, offset, SEEK_SET);
  132. if (off == (off_t)-1) {
  133. return -1;
  134. }
  135. return ReadPersistent(fd, buf, count);
  136. }
  137. // Try reading exactly "count" bytes from "offset" bytes in a file
  138. // pointed by "fd" into the buffer starting at "buf" while handling
  139. // short reads and EINTR. On success, return true. Otherwise, return
  140. // false.
  141. static bool ReadFromOffsetExact(const int fd, void *buf,
  142. const size_t count, const off_t offset) {
  143. ssize_t len = ReadFromOffset(fd, buf, count, offset);
  144. return len == count;
  145. }
  146. // Returns elf_header.e_type if the file pointed by fd is an ELF binary.
  147. static int FileGetElfType(const int fd) {
  148. ElfW(Ehdr) elf_header;
  149. if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
  150. return -1;
  151. }
  152. if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
  153. return -1;
  154. }
  155. return elf_header.e_type;
  156. }
  157. // Read the section headers in the given ELF binary, and if a section
  158. // of the specified type is found, set the output to this section header
  159. // and return true. Otherwise, return false.
  160. // To keep stack consumption low, we would like this function to not get
  161. // inlined.
  162. static ATTRIBUTE_NOINLINE bool
  163. GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
  164. ElfW(Word) type, ElfW(Shdr) *out) {
  165. // Read at most 16 section headers at a time to save read calls.
  166. ElfW(Shdr) buf[16];
  167. for (int i = 0; i < sh_num;) {
  168. const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
  169. const ssize_t num_bytes_to_read =
  170. (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
  171. const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
  172. sh_offset + i * sizeof(buf[0]));
  173. SAFE_ASSERT(len % sizeof(buf[0]) == 0);
  174. const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
  175. SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
  176. for (int j = 0; j < num_headers_in_buf; ++j) {
  177. if (buf[j].sh_type == type) {
  178. *out = buf[j];
  179. return true;
  180. }
  181. }
  182. i += num_headers_in_buf;
  183. }
  184. return false;
  185. }
  186. // There is no particular reason to limit section name to 63 characters,
  187. // but there has (as yet) been no need for anything longer either.
  188. const int kMaxSectionNameLen = 64;
  189. // name_len should include terminating '\0'.
  190. bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
  191. ElfW(Shdr) *out) {
  192. ElfW(Ehdr) elf_header;
  193. if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
  194. return false;
  195. }
  196. ElfW(Shdr) shstrtab;
  197. off_t shstrtab_offset = (elf_header.e_shoff +
  198. elf_header.e_shentsize * elf_header.e_shstrndx);
  199. if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
  200. return false;
  201. }
  202. for (int i = 0; i < elf_header.e_shnum; ++i) {
  203. off_t section_header_offset = (elf_header.e_shoff +
  204. elf_header.e_shentsize * i);
  205. if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
  206. return false;
  207. }
  208. char header_name[kMaxSectionNameLen];
  209. if (sizeof(header_name) < name_len) {
  210. RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
  211. "section will not be found (even if present).", name, name_len);
  212. // No point in even trying.
  213. return false;
  214. }
  215. off_t name_offset = shstrtab.sh_offset + out->sh_name;
  216. ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
  217. if (n_read == -1) {
  218. return false;
  219. } else if (n_read != name_len) {
  220. // Short read -- name could be at end of file.
  221. continue;
  222. }
  223. if (memcmp(header_name, name, name_len) == 0) {
  224. return true;
  225. }
  226. }
  227. return false;
  228. }
  229. // Read a symbol table and look for the symbol containing the
  230. // pc. Iterate over symbols in a symbol table and look for the symbol
  231. // containing "pc". On success, return true and write the symbol name
  232. // to out. Otherwise, return false.
  233. // To keep stack consumption low, we would like this function to not get
  234. // inlined.
  235. static ATTRIBUTE_NOINLINE bool
  236. FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
  237. uint64_t symbol_offset, const ElfW(Shdr) *strtab,
  238. const ElfW(Shdr) *symtab) {
  239. if (symtab == NULL) {
  240. return false;
  241. }
  242. const int num_symbols = symtab->sh_size / symtab->sh_entsize;
  243. for (int i = 0; i < num_symbols;) {
  244. off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
  245. // If we are reading Elf64_Sym's, we want to limit this array to
  246. // 32 elements (to keep stack consumption low), otherwise we can
  247. // have a 64 element Elf32_Sym array.
  248. #if __WORDSIZE == 64
  249. #define NUM_SYMBOLS 32
  250. #else
  251. #define NUM_SYMBOLS 64
  252. #endif
  253. // Read at most NUM_SYMBOLS symbols at once to save read() calls.
  254. ElfW(Sym) buf[NUM_SYMBOLS];
  255. const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
  256. SAFE_ASSERT(len % sizeof(buf[0]) == 0);
  257. const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
  258. SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
  259. for (int j = 0; j < num_symbols_in_buf; ++j) {
  260. const ElfW(Sym)& symbol = buf[j];
  261. uint64_t start_address = symbol.st_value;
  262. start_address += symbol_offset;
  263. uint64_t end_address = start_address + symbol.st_size;
  264. if (symbol.st_value != 0 && // Skip null value symbols.
  265. symbol.st_shndx != 0 && // Skip undefined symbols.
  266. start_address <= pc && pc < end_address) {
  267. ssize_t len1 = ReadFromOffset(fd, out, out_size,
  268. strtab->sh_offset + symbol.st_name);
  269. if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
  270. return false;
  271. }
  272. return true; // Obtained the symbol name.
  273. }
  274. }
  275. i += num_symbols_in_buf;
  276. }
  277. return false;
  278. }
  279. // Get the symbol name of "pc" from the file pointed by "fd". Process
  280. // both regular and dynamic symbol tables if necessary. On success,
  281. // write the symbol name to "out" and return true. Otherwise, return
  282. // false.
  283. static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
  284. char *out, int out_size,
  285. uint64_t map_start_address) {
  286. // Read the ELF header.
  287. ElfW(Ehdr) elf_header;
  288. if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
  289. return false;
  290. }
  291. uint64_t symbol_offset = 0;
  292. if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
  293. symbol_offset = map_start_address;
  294. }
  295. ElfW(Shdr) symtab, strtab;
  296. // Consult a regular symbol table first.
  297. if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
  298. SHT_SYMTAB, &symtab)) {
  299. return false;
  300. }
  301. if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
  302. symtab.sh_link * sizeof(symtab))) {
  303. return false;
  304. }
  305. if (FindSymbol(pc, fd, out, out_size, symbol_offset,
  306. &strtab, &symtab)) {
  307. return true; // Found the symbol in a regular symbol table.
  308. }
  309. // If the symbol is not found, then consult a dynamic symbol table.
  310. if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
  311. SHT_DYNSYM, &symtab)) {
  312. return false;
  313. }
  314. if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
  315. symtab.sh_link * sizeof(symtab))) {
  316. return false;
  317. }
  318. if (FindSymbol(pc, fd, out, out_size, symbol_offset,
  319. &strtab, &symtab)) {
  320. return true; // Found the symbol in a dynamic symbol table.
  321. }
  322. return false;
  323. }
  324. namespace {
  325. // Thin wrapper around a file descriptor so that the file descriptor
  326. // gets closed for sure.
  327. struct FileDescriptor {
  328. const int fd_;
  329. explicit FileDescriptor(int fd) : fd_(fd) {}
  330. ~FileDescriptor() {
  331. if (fd_ >= 0) {
  332. NO_INTR(close(fd_));
  333. }
  334. }
  335. int get() { return fd_; }
  336. private:
  337. explicit FileDescriptor(const FileDescriptor&);
  338. void operator=(const FileDescriptor&);
  339. };
  340. // Helper class for reading lines from file.
  341. //
  342. // Note: we don't use ProcMapsIterator since the object is big (it has
  343. // a 5k array member) and uses async-unsafe functions such as sscanf()
  344. // and snprintf().
  345. class LineReader {
  346. public:
  347. explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
  348. buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
  349. }
  350. // Read '\n'-terminated line from file. On success, modify "bol"
  351. // and "eol", then return true. Otherwise, return false.
  352. //
  353. // Note: if the last line doesn't end with '\n', the line will be
  354. // dropped. It's an intentional behavior to make the code simple.
  355. bool ReadLine(const char **bol, const char **eol) {
  356. if (BufferIsEmpty()) { // First time.
  357. const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
  358. if (num_bytes <= 0) { // EOF or error.
  359. return false;
  360. }
  361. eod_ = buf_ + num_bytes;
  362. bol_ = buf_;
  363. } else {
  364. bol_ = eol_ + 1; // Advance to the next line in the buffer.
  365. SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
  366. if (!HasCompleteLine()) {
  367. const int incomplete_line_length = eod_ - bol_;
  368. // Move the trailing incomplete line to the beginning.
  369. memmove(buf_, bol_, incomplete_line_length);
  370. // Read text from file and append it.
  371. char * const append_pos = buf_ + incomplete_line_length;
  372. const int capacity_left = buf_len_ - incomplete_line_length;
  373. const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
  374. capacity_left);
  375. if (num_bytes <= 0) { // EOF or error.
  376. return false;
  377. }
  378. eod_ = append_pos + num_bytes;
  379. bol_ = buf_;
  380. }
  381. }
  382. eol_ = FindLineFeed();
  383. if (eol_ == NULL) { // '\n' not found. Malformed line.
  384. return false;
  385. }
  386. *eol_ = '\0'; // Replace '\n' with '\0'.
  387. *bol = bol_;
  388. *eol = eol_;
  389. return true;
  390. }
  391. // Beginning of line.
  392. const char *bol() {
  393. return bol_;
  394. }
  395. // End of line.
  396. const char *eol() {
  397. return eol_;
  398. }
  399. private:
  400. explicit LineReader(const LineReader&);
  401. void operator=(const LineReader&);
  402. char *FindLineFeed() {
  403. return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
  404. }
  405. bool BufferIsEmpty() {
  406. return buf_ == eod_;
  407. }
  408. bool HasCompleteLine() {
  409. return !BufferIsEmpty() && FindLineFeed() != NULL;
  410. }
  411. const int fd_;
  412. char * const buf_;
  413. const int buf_len_;
  414. char *bol_;
  415. char *eol_;
  416. const char *eod_; // End of data in "buf_".
  417. };
  418. } // namespace
  419. // Place the hex number read from "start" into "*hex". The pointer to
  420. // the first non-hex character or "end" is returned.
  421. static char *GetHex(const char *start, const char *end, uint64_t *hex) {
  422. *hex = 0;
  423. const char *p;
  424. for (p = start; p < end; ++p) {
  425. int ch = *p;
  426. if ((ch >= '0' && ch <= '9') ||
  427. (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
  428. *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
  429. } else { // Encountered the first non-hex character.
  430. break;
  431. }
  432. }
  433. SAFE_ASSERT(p <= end);
  434. return const_cast<char *>(p);
  435. }
  436. // Search for the object file (from /proc/self/maps) that contains
  437. // the specified pc. If found, open this file and return the file handle,
  438. // and also set start_address to the start address of where this object
  439. // file is mapped to in memory. Otherwise, return -1.
  440. static ATTRIBUTE_NOINLINE int
  441. OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
  442. uint64_t &start_address) {
  443. int object_fd;
  444. // Open /proc/self/maps.
  445. int maps_fd;
  446. NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
  447. FileDescriptor wrapped_maps_fd(maps_fd);
  448. if (wrapped_maps_fd.get() < 0) {
  449. return -1;
  450. }
  451. // Iterate over maps and look for the map containing the pc. Then
  452. // look into the symbol tables inside.
  453. char buf[1024]; // Big enough for line of sane /proc/self/maps
  454. LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
  455. while (true) {
  456. const char *cursor;
  457. const char *eol;
  458. if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
  459. return -1;
  460. }
  461. // Start parsing line in /proc/self/maps. Here is an example:
  462. //
  463. // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
  464. //
  465. // We want start address (08048000), end address (0804c000), flags
  466. // (r-xp) and file name (/bin/cat).
  467. // Read start address.
  468. cursor = GetHex(cursor, eol, &start_address);
  469. if (cursor == eol || *cursor != '-') {
  470. return -1; // Malformed line.
  471. }
  472. ++cursor; // Skip '-'.
  473. // Read end address.
  474. uint64_t end_address;
  475. cursor = GetHex(cursor, eol, &end_address);
  476. if (cursor == eol || *cursor != ' ') {
  477. return -1; // Malformed line.
  478. }
  479. ++cursor; // Skip ' '.
  480. // Check start and end addresses.
  481. if (!(start_address <= pc && pc < end_address)) {
  482. continue; // We skip this map. PC isn't in this map.
  483. }
  484. // Read flags. Skip flags until we encounter a space or eol.
  485. const char * const flags_start = cursor;
  486. while (cursor < eol && *cursor != ' ') {
  487. ++cursor;
  488. }
  489. // We expect at least four letters for flags (ex. "r-xp").
  490. if (cursor == eol || cursor < flags_start + 4) {
  491. return -1; // Malformed line.
  492. }
  493. // Check flags. We are only interested in "r-x" maps.
  494. if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
  495. continue; // We skip this map.
  496. }
  497. ++cursor; // Skip ' '.
  498. // Skip to file name. "cursor" now points to file offset. We need to
  499. // skip at least three spaces for file offset, dev, and inode.
  500. int num_spaces = 0;
  501. while (cursor < eol) {
  502. if (*cursor == ' ') {
  503. ++num_spaces;
  504. } else if (num_spaces >= 3) {
  505. // The first non-space character after skipping three spaces
  506. // is the beginning of the file name.
  507. break;
  508. }
  509. ++cursor;
  510. }
  511. if (cursor == eol) {
  512. return -1; // Malformed line.
  513. }
  514. // Finally, "cursor" now points to file name of our interest.
  515. NO_INTR(object_fd = open(cursor, O_RDONLY));
  516. if (object_fd < 0) {
  517. return -1;
  518. }
  519. return object_fd;
  520. }
  521. }
  522. // The implementation of our symbolization routine. If it
  523. // successfully finds the symbol containing "pc" and obtains the
  524. // symbol name, returns true and write the symbol name to "out".
  525. // Otherwise, returns false. If Callback function is installed via
  526. // InstallSymbolizeCallback(), the function is also called in this function,
  527. // and "out" is used as its output.
  528. // To keep stack consumption low, we would like this function to not
  529. // get inlined.
  530. static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
  531. int out_size) {
  532. uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
  533. uint64_t start_address = 0;
  534. int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
  535. start_address);
  536. if (object_fd == -1) {
  537. return false;
  538. }
  539. FileDescriptor wrapped_object_fd(object_fd);
  540. int elf_type = FileGetElfType(wrapped_object_fd.get());
  541. if (elf_type == -1) {
  542. return false;
  543. }
  544. if (g_symbolize_callback) {
  545. // Run the call back if it's installed.
  546. // Note: relocation (and much of the rest of this code) will be
  547. // wrong for prelinked shared libraries and PIE executables.
  548. uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
  549. int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
  550. pc, out, out_size,
  551. relocation);
  552. if (num_bytes_written > 0) {
  553. out += num_bytes_written;
  554. out_size -= num_bytes_written;
  555. }
  556. }
  557. if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
  558. out, out_size, start_address)) {
  559. return false;
  560. }
  561. // Symbolization succeeded. Now we try to demangle the symbol.
  562. DemangleInplace(out, out_size);
  563. return true;
  564. }
  565. _END_GOOGLE_NAMESPACE_
  566. #elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
  567. #include <dlfcn.h>
  568. #include <string.h>
  569. _START_GOOGLE_NAMESPACE_
  570. static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
  571. int out_size) {
  572. Dl_info info;
  573. if (dladdr(pc, &info)) {
  574. if (strlen(info.dli_sname) < out_size) {
  575. strcpy(out, info.dli_sname);
  576. // Symbolization succeeded. Now we try to demangle the symbol.
  577. DemangleInplace(out, out_size);
  578. return true;
  579. }
  580. }
  581. return false;
  582. }
  583. _END_GOOGLE_NAMESPACE_
  584. #else
  585. # error BUG: HAVE_SYMBOLIZE was wrongly set
  586. #endif
  587. _START_GOOGLE_NAMESPACE_
  588. bool Symbolize(void *pc, char *out, int out_size) {
  589. SAFE_ASSERT(out_size >= 0);
  590. return SymbolizeAndDemangle(pc, out, out_size);
  591. }
  592. _END_GOOGLE_NAMESPACE_
  593. #else /* HAVE_SYMBOLIZE */
  594. #include <assert.h>
  595. #include "config.h"
  596. _START_GOOGLE_NAMESPACE_
  597. // TODO: Support other environments.
  598. bool Symbolize(void *pc, char *out, int out_size) {
  599. assert(0);
  600. return false;
  601. }
  602. _END_GOOGLE_NAMESPACE_
  603. #endif