51 #ifdef GLOG_BUILD_CONFIG_INCLUDE
52 #include GLOG_BUILD_CONFIG_INCLUDE
53 #endif // GLOG_BUILD_CONFIG_INCLUDE
57 #if defined(HAVE_SYMBOLIZE)
74 static int AssertFail() {
79 #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
81 static SymbolizeCallback g_symbolize_callback =
NULL;
82 void InstallSymbolizeCallback(SymbolizeCallback callback) {
83 g_symbolize_callback = callback;
86 static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
88 void InstallSymbolizeOpenObjectFileCallback(
89 SymbolizeOpenObjectFileCallback callback) {
90 g_symbolize_open_object_file_callback = callback;
99 if (
Demangle(out, demangled,
sizeof(demangled))) {
101 size_t len = strlen(demangled);
102 if (
len + 1 <=
static_cast<size_t>(out_size)) {
103 SAFE_ASSERT(
len <
sizeof(demangled));
104 memmove(out, demangled,
len + 1);
109 _END_GOOGLE_NAMESPACE_
113 #if defined(HAVE_DLFCN_H)
116 #if defined(GLOG_OS_OPENBSD)
117 #include <sys/exec_elf.h>
129 #include <sys/stat.h>
130 #include <sys/types.h>
135 #include <glog/raw_logging.h>
138 #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
146 static ssize_t ReadFromOffset(
const int fd,
void *
buf,
const size_t count,
148 SAFE_ASSERT(fd >= 0);
149 SAFE_ASSERT(
count <=
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
150 char *buf0 =
reinterpret_cast<char *
>(
buf);
151 size_t num_bytes = 0;
152 while (num_bytes <
count) {
155 static_cast<off_t
>(
offset + num_bytes)));
162 num_bytes +=
static_cast<size_t>(
len);
164 SAFE_ASSERT(num_bytes <=
count);
165 return static_cast<ssize_t
>(num_bytes);
172 static bool ReadFromOffsetExact(
const int fd,
void *
buf,
175 return static_cast<size_t>(
len) ==
count;
179 static int FileGetElfType(
const int fd) {
180 ElfW(Ehdr) elf_header;
181 if (!ReadFromOffsetExact(fd, &elf_header,
sizeof(elf_header), 0)) {
184 if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
187 return elf_header.e_type;
196 GetSectionHeaderByType(
const int fd, ElfW(Half) sh_num,
const size_t sh_offset,
197 ElfW(Word)
type, ElfW(Shdr) *out) {
200 for (
size_t i = 0;
i < sh_num;) {
201 const size_t num_bytes_left = (sh_num -
i) *
sizeof(
buf[0]);
202 const size_t num_bytes_to_read =
203 (
sizeof(
buf) > num_bytes_left) ? num_bytes_left :
sizeof(
buf);
204 const ssize_t
len = ReadFromOffset(fd,
buf, num_bytes_to_read,
205 sh_offset +
i *
sizeof(
buf[0]));
209 SAFE_ASSERT(
static_cast<size_t>(
len) %
sizeof(
buf[0]) == 0);
210 const size_t num_headers_in_buf =
static_cast<size_t>(
len) /
sizeof(
buf[0]);
211 SAFE_ASSERT(num_headers_in_buf <=
sizeof(
buf) /
sizeof(
buf[0]));
212 for (
size_t j = 0; j < num_headers_in_buf; ++j) {
218 i += num_headers_in_buf;
225 const int kMaxSectionNameLen = 64;
228 bool GetSectionHeaderByName(
int fd,
const char *
name,
size_t name_len,
230 ElfW(Ehdr) elf_header;
231 if (!ReadFromOffsetExact(fd, &elf_header,
sizeof(elf_header), 0)) {
236 size_t shstrtab_offset =
237 (elf_header.e_shoff +
static_cast<size_t>(elf_header.e_shentsize) *
238 static_cast<size_t>(elf_header.e_shstrndx));
239 if (!ReadFromOffsetExact(fd, &shstrtab,
sizeof(shstrtab), shstrtab_offset)) {
243 for (
size_t i = 0;
i < elf_header.e_shnum; ++
i) {
244 size_t section_header_offset = (elf_header.e_shoff +
245 elf_header.e_shentsize *
i);
246 if (!ReadFromOffsetExact(fd, out,
sizeof(*out), section_header_offset)) {
249 char header_name[kMaxSectionNameLen];
250 if (
sizeof(header_name) <
name_len) {
251 RAW_LOG(
WARNING,
"Section name '%s' is too long (%" PRIuS "); "
252 "section will not be found (even if present).",
name,
name_len);
256 size_t name_offset = shstrtab.sh_offset + out->sh_name;
257 ssize_t n_read = ReadFromOffset(fd, &header_name,
name_len, name_offset);
260 }
else if (
static_cast<size_t>(n_read) !=
name_len) {
278 FindSymbol(uint64_t pc,
const int fd,
char *out,
size_t out_size,
279 uint64_t symbol_offset,
const ElfW(Shdr) *strtab,
280 const ElfW(Shdr) *
symtab) {
284 const size_t num_symbols =
symtab->sh_size /
symtab->sh_entsize;
285 for (
unsigned i = 0;
i < num_symbols;) {
291 #if defined(__WORDSIZE) && __WORDSIZE == 64
292 const size_t NUM_SYMBOLS = 32U;
294 const size_t NUM_SYMBOLS = 64U;
298 ElfW(Sym)
buf[NUM_SYMBOLS];
299 size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols -
i);
301 ReadFromOffset(fd, &
buf,
sizeof(
buf[0]) * num_symbols_to_read,
offset);
302 SAFE_ASSERT(
static_cast<size_t>(
len) %
sizeof(
buf[0]) == 0);
303 const size_t num_symbols_in_buf =
static_cast<size_t>(
len) /
sizeof(
buf[0]);
304 SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
305 for (
unsigned j = 0; j < num_symbols_in_buf; ++j) {
306 const ElfW(Sym)& symbol =
buf[j];
307 uint64_t start_address = symbol.st_value;
308 start_address += symbol_offset;
309 uint64_t end_address = start_address + symbol.st_size;
310 if (symbol.st_value != 0 &&
311 symbol.st_shndx != 0 &&
312 start_address <= pc && pc < end_address) {
313 ssize_t len1 = ReadFromOffset(fd, out, out_size,
314 strtab->sh_offset + symbol.st_name);
315 if (len1 <= 0 || memchr(out,
'\0', out_size) ==
NULL) {
316 memset(out, 0, out_size);
322 i += num_symbols_in_buf;
331 static bool GetSymbolFromObjectFile(
const int fd,
335 uint64_t base_address) {
337 ElfW(Ehdr) elf_header;
338 if (!ReadFromOffsetExact(fd, &elf_header,
sizeof(elf_header), 0)) {
342 ElfW(Shdr)
symtab, strtab;
345 if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
347 if (!ReadFromOffsetExact(fd, &strtab,
sizeof(strtab), elf_header.e_shoff +
351 if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &
symtab)) {
357 if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
359 if (!ReadFromOffsetExact(fd, &strtab,
sizeof(strtab), elf_header.e_shoff +
363 if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &
symtab)) {
382 int get() {
return fd_; }
396 explicit LineReader(
int fd,
char *
buf,
size_t buf_len,
size_t offset)
410 bool ReadLine(
const char **bol,
const char **eol) {
411 if (BufferIsEmpty()) {
412 const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
413 if (num_bytes <= 0) {
416 offset_ +=
static_cast<size_t>(num_bytes);
417 eod_ = buf_ + num_bytes;
421 SAFE_ASSERT(bol_ <= eod_);
422 if (!HasCompleteLine()) {
423 const size_t incomplete_line_length =
static_cast<size_t>(eod_ - bol_);
425 memmove(buf_, bol_, incomplete_line_length);
427 char *
const append_pos = buf_ + incomplete_line_length;
428 const size_t capacity_left = buf_len_ - incomplete_line_length;
429 const ssize_t num_bytes =
430 ReadFromOffset(fd_, append_pos, capacity_left, offset_);
431 if (num_bytes <= 0) {
434 offset_ +=
static_cast<size_t>(num_bytes);
435 eod_ = append_pos + num_bytes;
439 eol_ = FindLineFeed();
461 LineReader(
const LineReader &);
462 void operator=(
const LineReader&);
464 char *FindLineFeed() {
465 return reinterpret_cast<char *
>(memchr(bol_,
'\n',
static_cast<size_t>(eod_ - bol_)));
468 bool BufferIsEmpty() {
472 bool HasCompleteLine() {
473 return !BufferIsEmpty() && FindLineFeed() !=
NULL;
478 const size_t buf_len_;
488 static char *GetHex(
const char *
start,
const char *
end, uint64_t *hex) {
493 if ((
ch >=
'0' &&
ch <=
'9') ||
494 (
ch >=
'A' &&
ch <=
'F') || (
ch >=
'a' &&
ch <=
'f')) {
495 *hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(
ch -
'0') : (
ch & 0xF) + 9U);
500 SAFE_ASSERT(
p <=
end);
501 return const_cast<char *
>(
p);
513 OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
514 uint64_t &start_address,
515 uint64_t &base_address,
517 size_t out_file_name_size) {
521 NO_INTR(maps_fd = open(
"/proc/self/maps", O_RDONLY));
523 if (wrapped_maps_fd.get() < 0) {
528 NO_INTR(mem_fd = open(
"/proc/self/mem", O_RDONLY));
530 if (wrapped_mem_fd.get() < 0) {
537 unsigned num_maps = 0;
538 LineReader reader(wrapped_maps_fd.get(),
buf,
sizeof(
buf), 0);
543 if (!reader.ReadLine(&cursor, &eol)) {
555 cursor = GetHex(cursor, eol, &start_address);
556 if (cursor == eol || *cursor !=
'-') {
562 uint64_t end_address;
563 cursor = GetHex(cursor, eol, &end_address);
564 if (cursor == eol || *cursor !=
' ') {
570 const char *
const flags_start = cursor;
571 while (cursor < eol && *cursor !=
' ') {
575 if (cursor == eol || cursor < flags_start + 4) {
582 if (flags_start[0] ==
'r' &&
583 ReadFromOffsetExact(mem_fd, &ehdr,
sizeof(ElfW(Ehdr)), start_address) &&
584 memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
585 switch (ehdr.e_type) {
598 base_address = start_address;
599 for (
unsigned i = 0;
i != ehdr.e_phnum; ++
i) {
601 if (ReadFromOffsetExact(
602 mem_fd, &phdr,
sizeof(phdr),
603 start_address + ehdr.e_phoff +
i *
sizeof(phdr)) &&
604 phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
605 base_address = start_address - phdr.p_vaddr;
618 if (!(start_address <= pc && pc < end_address)) {
623 if (flags_start[0] !=
'r' || flags_start[2] !=
'x') {
629 uint64_t file_offset;
630 cursor = GetHex(cursor, eol, &file_offset);
631 if (cursor == eol || *cursor !=
' ') {
639 while (cursor < eol) {
640 if (*cursor ==
' ') {
642 }
else if (num_spaces >= 2) {
654 NO_INTR(object_fd = open(cursor, O_RDONLY));
658 strncpy(out_file_name, cursor, out_file_name_size);
660 out_file_name[out_file_name_size - 1] =
'\0';
674 static char *itoa_r(uintptr_t
i,
char *
buf,
size_t sz,
unsigned base,
size_t padding) {
681 if (base < 2 || base > 16) {
699 *ptr++ =
"0123456789abcdef"[
i %
base];
705 }
while (
i > 0 || padding > 0);
714 while (--ptr >
start) {
724 static void SafeAppendString(
const char*
source,
char*
dest,
size_t dest_size) {
725 size_t dest_string_length = strlen(
dest);
726 SAFE_ASSERT(dest_string_length < dest_size);
727 dest += dest_string_length;
728 dest_size -= dest_string_length;
731 dest[dest_size - 1] =
'\0';
737 static void SafeAppendHexNumber(uint64_t
value,
char*
dest,
size_t dest_size) {
739 char buf[17] = {
'\0'};
740 SafeAppendString(itoa_r(
value,
buf,
sizeof(
buf), 16, 0),
dest, dest_size);
753 uint64_t pc0 =
reinterpret_cast<uintptr_t
>(pc);
754 uint64_t start_address = 0;
755 uint64_t base_address = 0;
762 SafeAppendString(
"(", out, out_size);
764 if (g_symbolize_open_object_file_callback) {
765 object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
766 base_address, out + 1,
769 object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
777 #if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
788 out[out_size - 1] =
'\0';
789 SafeAppendString(
"+0x", out, out_size);
790 SafeAppendHexNumber(pc0 - base_address, out, out_size);
791 SafeAppendString(
")", out, out_size);
797 int elf_type = FileGetElfType(wrapped_object_fd.get());
798 if (elf_type == -1) {
801 if (g_symbolize_callback) {
805 uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
806 int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
809 if (num_bytes_written > 0) {
810 out +=
static_cast<size_t>(num_bytes_written);
811 out_size -=
static_cast<size_t>(num_bytes_written);
814 if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
815 out, out_size, base_address)) {
816 if (out[1] && !g_symbolize_callback) {
821 out[out_size - 1] =
'\0';
822 SafeAppendString(
"+0x", out, out_size);
823 SafeAppendHexNumber(pc0 - base_address, out, out_size);
824 SafeAppendString(
")", out, out_size);
831 DemangleInplace(out, out_size);
835 _END_GOOGLE_NAMESPACE_
837 #elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
847 if (dladdr(pc, &info)) {
848 if (info.dli_sname) {
849 if (strlen(info.dli_sname) < out_size) {
850 strcpy(out, info.dli_sname);
852 DemangleInplace(out, out_size);
860 _END_GOOGLE_NAMESPACE_
862 #elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
868 #pragma comment(lib, "dbghelp")
873 class SymInitializer {
877 SymInitializer() : process(
NULL), ready(
false) {
880 process = GetCurrentProcess();
884 SymSetOptions(SYMOPT_DEFERRED_LOADS);
885 if (SymInitialize(process,
NULL,
true)) {
894 SymInitializer(
const SymInitializer&);
895 SymInitializer& operator=(
const SymInitializer&);
900 const static SymInitializer symInitializer;
901 if (!symInitializer.ready) {
906 char buf[
sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
907 SYMBOL_INFO *symbol =
reinterpret_cast<SYMBOL_INFO *
>(
buf);
908 symbol->SizeOfStruct =
sizeof(SYMBOL_INFO);
909 symbol->MaxNameLen = MAX_SYM_NAME;
912 BOOL ret = SymFromAddr(symInitializer.process,
913 reinterpret_cast<DWORD64
>(pc), 0, symbol);
914 if (ret == 1 &&
static_cast<int>(symbol->NameLen) < out_size) {
916 strncpy(out, symbol->Name,
static_cast<size_t>(symbol->NameLen) + 1);
917 out[
static_cast<size_t>(symbol->NameLen)] =
'\0';
919 DemangleInplace(out, out_size);
925 _END_GOOGLE_NAMESPACE_
928 # error BUG: HAVE_SYMBOLIZE was wrongly set
933 bool Symbolize(
void *pc,
char *out,
size_t out_size) {
934 return SymbolizeAndDemangle(pc, out, out_size);
937 _END_GOOGLE_NAMESPACE_
953 _END_GOOGLE_NAMESPACE_