This source file includes following definitions.
- GetProgramInvocationName
- PrintError
- Add
- GetSymbol
- Symbolize
#include "config.h"
#include "symbolize.h"
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef __MACH__
#include <mach-o/dyld.h>
#include <limits.h>
#endif
#if defined(__CYGWIN__) || defined(__CYGWIN32__)
#include <io.h>
#endif
#include <string>
#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/sysinfo.h"
using std::string;
using tcmalloc::DumpProcSelfMaps;
DEFINE_string(symbolize_pprof,
EnvToString("PPROF_PATH", "pprof"),
"Path to pprof to call for reporting function names.");
static string* g_pprof_path = new string(FLAGS_symbolize_pprof);
static char* GetProgramInvocationName() {
#if defined(HAVE_PROGRAM_INVOCATION_NAME)
extern char* program_invocation_name;
return program_invocation_name;
#elif defined(__MACH__)
static char program_invocation_name[PATH_MAX];
if (program_invocation_name[0] == '\0') {
uint32_t length = sizeof(program_invocation_name);
if (_NSGetExecutablePath(program_invocation_name, &length))
return NULL;
}
return program_invocation_name;
#else
return NULL;
#endif
}
static void PrintError(const char* reason) {
RAW_LOG(ERROR,
"*** WARNING: Cannot convert addresses to symbols in output below.\n"
"*** Reason: %s\n"
"*** If you cannot fix this, try running pprof directly.\n",
reason);
}
void SymbolTable::Add(const void* addr) {
symbolization_table_[addr] = "";
}
const char* SymbolTable::GetSymbol(const void* addr) {
return symbolization_table_[addr];
}
int SymbolTable::Symbolize() {
#if !defined(HAVE_UNISTD_H) || !defined(HAVE_SYS_SOCKET_H) || !defined(HAVE_SYS_WAIT_H)
PrintError("Perftools does not know how to call a sub-process on this O/S");
return 0;
#else
const char* argv0 = GetProgramInvocationName();
if (argv0 == NULL) {
PrintError("Cannot figure out the name of this executable (argv0)");
return 0;
}
if (access(g_pprof_path->c_str(), R_OK) != 0) {
PrintError("Cannot find 'pprof' (is PPROF_PATH set correctly?)");
return 0;
}
int *child_in = NULL;
int *child_out = NULL;
int child_fds[5][2];
for (int i = 0; i < 5; i++) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_fds[i]) == -1) {
for (int j = 0; j < i; j++) {
close(child_fds[j][0]);
close(child_fds[j][1]);
PrintError("Cannot create a socket pair");
return 0;
}
} else {
if ((child_fds[i][0] > 2) && (child_fds[i][1] > 2)) {
if (child_in == NULL) {
child_in = child_fds[i];
} else {
child_out = child_fds[i];
for (int j = 0; j < i; j++) {
if (child_fds[j] == child_in) continue;
close(child_fds[j][0]);
close(child_fds[j][1]);
}
break;
}
}
}
}
switch (fork()) {
case -1: {
close(child_in[0]);
close(child_in[1]);
close(child_out[0]);
close(child_out[1]);
PrintError("Unknown error calling fork()");
return 0;
}
case 0: {
close(child_in[1]);
close(child_out[1]);
close(0);
close(1);
if (dup2(child_in[0], 0) == -1) _exit(1);
if (dup2(child_out[0], 1) == -1) _exit(2);
unsetenv("CPUPROFILE");
unsetenv("HEAPPROFILE");
unsetenv("HEAPCHECK");
unsetenv("PERFTOOLS_VERBOSE");
execlp(g_pprof_path->c_str(), g_pprof_path->c_str(),
"--symbols", argv0, NULL);
_exit(3);
}
default: {
close(child_in[0]);
close(child_out[0]);
#ifdef HAVE_POLL_H
poll(0, 0, 1);
struct pollfd pfd = { child_in[1], POLLOUT, 0 };
if (!poll(&pfd, 1, 0) || !(pfd.revents & POLLOUT) ||
(pfd.revents & (POLLHUP|POLLERR))) {
PrintError("Cannot run 'pprof' (is PPROF_PATH set correctly?)");
return 0;
}
#endif
#if defined(__CYGWIN__) || defined(__CYGWIN32__)
const HANDLE symbols_handle = (HANDLE) get_osfhandle(child_in[1]);
DumpProcSelfMaps(symbols_handle);
#else
DumpProcSelfMaps(child_in[1]);
#endif
const int kOutBufSize = 24 * symbolization_table_.size();
char *pprof_buffer = new char[kOutBufSize];
int written = 0;
for (SymbolMap::const_iterator iter = symbolization_table_.begin();
iter != symbolization_table_.end(); ++iter) {
written += snprintf(pprof_buffer + written, kOutBufSize - written,
"0x%"PRIxPTR"\n", reinterpret_cast<uintptr_t>(iter->first));
}
write(child_in[1], pprof_buffer, strlen(pprof_buffer));
close(child_in[1]);
const int kSymbolBufferSize = kSymbolSize * symbolization_table_.size();
int total_bytes_read = 0;
delete[] symbol_buffer_;
symbol_buffer_ = new char[kSymbolBufferSize];
memset(symbol_buffer_, '\0', kSymbolBufferSize);
while (1) {
int bytes_read = read(child_out[1], symbol_buffer_ + total_bytes_read,
kSymbolBufferSize - total_bytes_read);
if (bytes_read < 0) {
close(child_out[1]);
PrintError("Cannot read data from pprof");
return 0;
} else if (bytes_read == 0) {
close(child_out[1]);
wait(NULL);
break;
} else {
total_bytes_read += bytes_read;
}
}
if (total_bytes_read == 0 || symbol_buffer_[total_bytes_read - 1] != '\n')
return 0;
SymbolMap::iterator fill = symbolization_table_.begin();
int num_symbols = 0;
const char *current_name = symbol_buffer_;
for (int i = 0; i < total_bytes_read; i++) {
if (symbol_buffer_[i] == '\n') {
fill->second = current_name;
symbol_buffer_[i] = '\0';
current_name = symbol_buffer_ + i + 1;
fill++;
num_symbols++;
}
}
return num_symbols;
}
}
PrintError("Unkown error (should never occur!)");
return 0;
#endif
}