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