chromium/base/third_party/symbolize/symbolize.cc

// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Satoru Takabayashi
// Stack-footprint reduction work done by Raksit Ashok
//
// Implementation note:
//
// We don't use heaps but only use stacks.  We want to reduce the
// stack consumption so that the symbolizer can run on small stacks.
//
// Here are some numbers collected with GCC 4.1.0 on x86:
// - sizeof(Elf32_Sym)  = 16
// - sizeof(Elf32_Shdr) = 40
// - sizeof(Elf64_Sym)  = 24
// - sizeof(Elf64_Shdr) = 64
//
// This implementation is intended to be async-signal-safe but uses
// some functions which are not guaranteed to be so, such as memchr()
// and memmove().  We assume they are async-signal-safe.
//
// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).

#ifdef GLOG_BUILD_CONFIG_INCLUDE
#include GLOG_BUILD_CONFIG_INCLUDE
#endif  // GLOG_BUILD_CONFIG_INCLUDE

#include "symbolize.h"

#include "utilities.h"

#if defined(HAVE_SYMBOLIZE)

#include <cstring>
#include <cstdlib>

#include <algorithm>
#include <limits>

#include "symbolize.h"
#include "demangle.h"

_START_GOOGLE_NAMESPACE_

// We don't use assert() since it's not guaranteed to be
// async-signal-safe.  Instead we define a minimal assertion
// macro. So far, we don't need pretty printing for __FILE__, etc.

// A wrapper for abort() to make it callable in ? :.
static int AssertFail() {}

#define SAFE_ASSERT(expr)

static SymbolizeCallback g_symbolize_callback =;
void InstallSymbolizeCallback(SymbolizeCallback callback) {}

static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =;
void InstallSymbolizeOpenObjectFileCallback(
    SymbolizeOpenObjectFileCallback callback) {}

// This function wraps the Demangle function to provide an interface
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE void DemangleInplace(char* out, size_t out_size) {}

_END_GOOGLE_NAMESPACE_

#if defined(__ELF__)

#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif
#if defined(GLOG_OS_OPENBSD)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif
#include <fcntl.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cerrno>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include "symbolize.h"
#include "config.h"
#include "glog/raw_logging.h"

// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn)

_START_GOOGLE_NAMESPACE_

FileDescriptor::~FileDescriptor() {}

ssize_t ReadFromOffset(const int fd,
                       void* buf,
                       const size_t count,
                       const size_t offset) {}

// Try reading exactly "count" bytes from "offset" bytes in a file
// pointed by "fd" into the buffer starting at "buf" while handling
// short reads and EINTR.  On success, return true. Otherwise, return
// false.
static bool ReadFromOffsetExact(const int fd,
                                void* buf,
                                const size_t count,
                                const size_t offset) {}

// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
static int FileGetElfType(const int fd) {}

// Read the section headers in the given ELF binary, and if a section
// of the specified type is found, set the output to this section header
// and return true.  Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
                                                      ElfW(Half) sh_num,
                                                      const size_t sh_offset,
                                                      ElfW(Word) type,
                                                      ElfW(Shdr) * out) {}

// There is no particular reason to limit section name to 63 characters,
// but there has (as yet) been no need for anything longer either.
const int kMaxSectionNameLen =;

// name_len should include terminating '\0'.
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
                            ElfW(Shdr) *out) {}

// Read a symbol table and look for the symbol containing the
// pc. Iterate over symbols in a symbol table and look for the symbol
// containing "pc".  On success, return true and write the symbol name
// to out.  Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc,
                                          const int fd,
                                          char* out,
                                          size_t out_size,
                                          uint64_t symbol_offset,
                                          const ElfW(Shdr) * strtab,
                                          const ElfW(Shdr) * symtab) {}

// Get the symbol name of "pc" from the file pointed by "fd".  Process
// 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,
                                    size_t out_size,
                                    uint64_t base_address) {}

namespace {

// Helper class for reading lines from file.
//
// Note: we don't use ProcMapsIterator since the object is big (it has
// a 5k array member) and uses async-unsafe functions such as sscanf()
// and snprintf().
class LineReader {};
}  // namespace

// Place the hex number read from "start" into "*hex".  The pointer to
// the first non-hex character or "end" is returned.
static char *GetHex(const char *start, const char *end, uint64_t *hex) {}

static int OpenObjectFileContainingPcAndGetStartAddressNoHook(
    uint64_t pc,
    uint64_t& start_address,
    uint64_t& base_address,
    char* out_file_name,
    size_t out_file_name_size) {}

int OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
                                                 uint64_t& start_address,
                                                 uint64_t& base_address,
                                                 char* out_file_name,
                                                 size_t out_file_name_size) {}

// POSIX doesn't define any async-signal safe function for converting
// an integer to ASCII. We'll have to define our own version.
// itoa_r() converts an (unsigned) integer to ASCII. It returns "buf", if the
// conversion was successful or NULL otherwise. It never writes more than "sz"
// bytes. Output will be truncated as needed, and a NUL character is always
// appended.
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
static char* itoa_r(uintptr_t i,
                    char* buf,
                    size_t sz,
                    unsigned base,
                    size_t padding) {}

// Safely appends string |source| to string |dest|.  Never writes past the
// buffer size |dest_size| and guarantees that |dest| is null-terminated.
static void SafeAppendString(const char* source, char* dest, size_t dest_size) {}

// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
// Never writes past the buffer size |dest_size| and guarantees that |dest| is
// null-terminated.
static void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {}

// The implementation of our symbolization routine.  If it
// successfully finds the symbol containing "pc" and obtains the
// symbol name, returns true and write the symbol name to "out".
// Otherwise, returns false. If Callback function is installed via
// InstallSymbolizeCallback(), the function is also called in this function,
// and "out" is used as its output.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc,
                                                    char* out,
                                                    size_t out_size) {}

_END_GOOGLE_NAMESPACE_

#elif (defined(GLOG_OS_MACOSX) || defined(GLOG_OS_EMSCRIPTEN)) && \
    defined(HAVE_DLADDR)

#include <dlfcn.h>
#include <cstring>

_START_GOOGLE_NAMESPACE_

static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc,
                                                    char* out,
                                                    size_t out_size) {
  Dl_info info;
  if (dladdr(pc, &info)) {
    if (info.dli_sname) {
      if (strlen(info.dli_sname) < out_size) {
        strcpy(out, info.dli_sname);
        // Symbolization succeeded.  Now we try to demangle the symbol.
        DemangleInplace(out, out_size);
        return true;
      }
    }
  }
  return false;
}

_END_GOOGLE_NAMESPACE_

#elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)

#include <windows.h>
#include <dbghelp.h>

#ifdef _MSC_VER
#pragma comment(lib, "dbghelp")
#endif

_START_GOOGLE_NAMESPACE_

class SymInitializer {
public:
  HANDLE process;
  bool ready;
  SymInitializer() : process(NULL), ready(false) {
    // 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,
                                                    size_t 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<SYMBOL_INFO *>(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<DWORD64>(pc), 0, symbol);
  if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
    // `NameLen` does not include the null terminating character.
    strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
    out[static_cast<size_t>(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

_START_GOOGLE_NAMESPACE_

bool Symbolize(void* pc, char* out, size_t out_size) {}

_END_GOOGLE_NAMESPACE_

#else  /* HAVE_SYMBOLIZE */

#include <cassert>

#include "config.h"

_START_GOOGLE_NAMESPACE_

// TODO: Support other environments.
bool Symbolize(void* /*pc*/, char* /*out*/, size_t /*out_size*/) {
  assert(0);
  return false;
}

_END_GOOGLE_NAMESPACE_

#endif