X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsymbolize.cc;h=98a754f7ca09918c2f1de648984b2ca1af169dad;hb=0a9f71036f5617ecd3549abff78a8d9a09c7e56e;hp=b18796e15e594eb74084884d422afba6cb8147ad;hpb=de6149ef8e67b064a433a8b88924fa9f606ad5d5;p=platform%2Fupstream%2Fglog.git diff --git a/src/symbolize.cc b/src/symbolize.cc index b18796e..98a754f 100644 --- a/src/symbolize.cc +++ b/src/symbolize.cc @@ -56,6 +56,8 @@ #if defined(HAVE_SYMBOLIZE) +#include + #include #include "symbolize.h" @@ -325,20 +327,17 @@ FindSymbol(uint64_t pc, const int fd, char *out, int out_size, // both regular and dynamic symbol tables if necessary. On success, // write the symbol name to "out" and return true. Otherwise, return // false. -static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, - char *out, int out_size, - uint64_t map_start_address) { +static bool GetSymbolFromObjectFile(const int fd, + uint64_t pc, + char* out, + int out_size, + uint64_t base_address) { // Read the ELF header. ElfW(Ehdr) elf_header; if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { return false; } - uint64_t symbol_offset = 0; - if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment. - symbol_offset = map_start_address; - } - ElfW(Shdr) symtab, strtab; // Consult a regular symbol table first. @@ -348,8 +347,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, symtab.sh_link * sizeof(symtab))) { return false; } - if (FindSymbol(pc, fd, out, out_size, symbol_offset, - &strtab, &symtab)) { + if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { return true; // Found the symbol in a regular symbol table. } } @@ -361,8 +359,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, symtab.sh_link * sizeof(symtab))) { return false; } - if (FindSymbol(pc, fd, out, out_size, symbol_offset, - &strtab, &symtab)) { + if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { return true; // Found the symbol in a dynamic symbol table. } } @@ -511,7 +508,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, int out_file_name_size) { int object_fd; - // Open /proc/self/maps. int maps_fd; NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY)); FileDescriptor wrapped_maps_fd(maps_fd); @@ -519,6 +515,13 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, return -1; } + int mem_fd; + NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY)); + FileDescriptor wrapped_mem_fd(mem_fd); + if (wrapped_mem_fd.get() < 0) { + return -1; + } + // Iterate over maps and look for the map containing the pc. Then // look into the symbol tables inside. char buf[1024]; // Big enough for line of sane /proc/self/maps @@ -554,11 +557,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, } ++cursor; // Skip ' '. - // Check start and end addresses. - if (!(start_address <= pc && pc < end_address)) { - continue; // We skip this map. PC isn't in this map. - } - // Read flags. Skip flags until we encounter a space or eol. const char * const flags_start = cursor; while (cursor < eol && *cursor != ' ') { @@ -569,6 +567,49 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, return -1; // Malformed line. } + // Determine the base address by reading ELF headers in process memory. + ElfW(Ehdr) ehdr; + // Skip non-readable maps. + if (flags_start[0] == 'r' && + ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) && + memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) { + switch (ehdr.e_type) { + case ET_EXEC: + base_address = 0; + break; + case ET_DYN: + // Find the segment containing file offset 0. This will correspond + // to the ELF header that we just read. Normally this will have + // virtual address 0, but this is not guaranteed. We must subtract + // the virtual address from the address where the ELF header was + // mapped to get the base address. + // + // If we fail to find a segment for file offset 0, use the address + // of the ELF header as the base address. + base_address = start_address; + for (unsigned i = 0; i != ehdr.e_phnum; ++i) { + ElfW(Phdr) phdr; + if (ReadFromOffsetExact( + mem_fd, &phdr, sizeof(phdr), + start_address + ehdr.e_phoff + i * sizeof(phdr)) && + phdr.p_type == PT_LOAD && phdr.p_offset == 0) { + base_address = start_address - phdr.p_vaddr; + break; + } + } + break; + default: + // ET_REL or ET_CORE. These aren't directly executable, so they don't + // affect the base address. + break; + } + } + + // Check start and end addresses. + if (!(start_address <= pc && pc < end_address)) { + continue; // We skip this map. PC isn't in this map. + } + // Check flags. We are only interested in "r*x" maps. if (flags_start[0] != 'r' || flags_start[2] != 'x') { continue; // We skip this map. @@ -583,19 +624,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, } ++cursor; // Skip ' '. - // Don't subtract 'start_address' from the first entry: - // * If a binary is compiled w/o -pie, then the first entry in - // process maps is likely the binary itself (all dynamic libs - // are mapped higher in address space). For such a binary, - // instruction offset in binary coincides with the actual - // instruction address in virtual memory (as code section - // is mapped to a fixed memory range). - // * If a binary is compiled with -pie, all the modules are - // mapped high at address space (in particular, higher than - // shadow memory of the tool), so the module can't be the - // first entry. - base_address = ((num_maps == 1) ? 0U : start_address) - file_offset; - // Skip to file name. "cursor" now points to dev. We need to // skip at least two spaces for dev and inode. int num_spaces = 0; @@ -782,7 +810,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, } } if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0, - out, out_size, start_address)) { + out, out_size, base_address)) { return false; } @@ -816,6 +844,67 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, _END_GOOGLE_NAMESPACE_ +#elif defined(OS_WINDOWS) + +#include +#pragma comment(lib, "DbgHelp") + +_START_GOOGLE_NAMESPACE_ + +class SymInitializer { +public: + HANDLE process = NULL; + bool ready = false; + SymInitializer() { + // Initialize the symbol handler. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx + process = GetCurrentProcess(); + // Defer symbol loading. + // We do not request undecorated symbols with SYMOPT_UNDNAME + // because the mangling library calls UnDecorateSymbolName. + SymSetOptions(SYMOPT_DEFERRED_LOADS); + if (SymInitialize(process, NULL, true)) { + ready = true; + } + } + ~SymInitializer() { + SymCleanup(process); + // We do not need to close `HANDLE process` because it's a "pseudo handle." + } +private: + SymInitializer(const SymInitializer&); + SymInitializer& operator=(const SymInitializer&); +}; + +static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, + int out_size) { + const static SymInitializer symInitializer; + if (!symInitializer.ready) { + return false; + } + // Resolve symbol information from address. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx + char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO *symbol = reinterpret_cast(buf); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + // We use the ANSI version to ensure the string type is always `char *`. + // This could break if a symbol has Unicode in it. + BOOL ret = SymFromAddr(symInitializer.process, + reinterpret_cast(pc), 0, symbol); + if (ret == 1 && static_cast(symbol->NameLen) < out_size) { + // `NameLen` does not include the null terminating character. + strncpy(out, symbol->Name, static_cast(symbol->NameLen) + 1); + out[static_cast(symbol->NameLen)] = '\0'; + // Symbolization succeeded. Now we try to demangle the symbol. + DemangleInplace(out, out_size); + return true; + } + return false; +} + +_END_GOOGLE_NAMESPACE_ + #else # error BUG: HAVE_SYMBOLIZE was wrongly set #endif