summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsgk@chromium.org <sgk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-25 17:09:19 +0000
committersgk@chromium.org <sgk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-25 17:09:19 +0000
commit720b133970287eacc348977323e1d6c3ff29cefc (patch)
tree1ff16c73e78f8dbfd12acd6f6524d5ac11589de4
parentc52933bcaaed2c5c28685d8399536c3b472dca53 (diff)
downloadchromium_src-720b133970287eacc348977323e1d6c3ff29cefc.zip
chromium_src-720b133970287eacc348977323e1d6c3ff29cefc.tar.gz
chromium_src-720b133970287eacc348977323e1d6c3ff29cefc.tar.bz2
Merge r33049 (symbolize_linux.cc) to new allocator structure.
BUG=27911 TEST=none git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33074 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/allocator/allocator.gyp4
-rw-r--r--third_party/tcmalloc/chromium/src/symbolize_linux.cc188
-rw-r--r--third_party/tcmalloc/chromium/src/tcmalloc_linux.cc4
3 files changed, 194 insertions, 2 deletions
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
index 49b63ec..1e65bca 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -99,6 +99,7 @@
'<(tcmalloc_dir)/src/maybe_threads.cc',
'<(tcmalloc_dir)/src/maybe_threads.h',
'<(tcmalloc_dir)/src/symbolize.cc',
+ '<(tcmalloc_dir)/src/symbolize_linux.cc',
'<(tcmalloc_dir)/src/symbolize.h',
'<(tcmalloc_dir)/src/system-alloc.cc',
'<(tcmalloc_dir)/src/system-alloc.h',
@@ -138,6 +139,7 @@
'win_allocator.cc',
'<(tcmalloc_dir)/src/tcmalloc.cc',
+ '<(tcmalloc_dir)/src/symbolize.cc',
],
'msvs_settings': {
# TODO(sgk): merge this with build/common.gypi settings
@@ -177,13 +179,13 @@
'<(tcmalloc_dir)/src/base/vdso_support.h',
'<(tcmalloc_dir)/src/maybe_threads.cc',
'<(tcmalloc_dir)/src/maybe_threads.h',
- '<(tcmalloc_dir)/src/symbolize.cc',
'<(tcmalloc_dir)/src/symbolize.h',
'<(tcmalloc_dir)/src/system-alloc.cc',
'<(tcmalloc_dir)/src/system-alloc.h',
# don't use linux forked version
'<(tcmalloc_dir)/src/tcmalloc_linux.cc',
+ '<(tcmalloc_dir)/src/symbolize_linux.cc',
# heap-profiler/checker/cpuprofiler
'<(tcmalloc_dir)/src/base/thread_lister.c',
diff --git a/third_party/tcmalloc/chromium/src/symbolize_linux.cc b/third_party/tcmalloc/chromium/src/symbolize_linux.cc
new file mode 100644
index 0000000..9c15e02
--- /dev/null
+++ b/third_party/tcmalloc/chromium/src/symbolize_linux.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2009, 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: Craig Silverstein
+//
+// This forks out to pprof to do the actual symbolizing. We might
+// be better off writing our own in C++.
+
+#include "config.h"
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include "symbolize.h"
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> // for write()
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> // for socketpair() -- needed by Symbolize
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h> // for wait() -- needed by Symbolize
+#endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#include <string>
+#include "base/commandlineflags.h"
+#include "base/sysinfo.h"
+
+using std::string;
+using tcmalloc::DumpProcSelfMaps; // from sysinfo.h
+
+
+DEFINE_string(symbolize_pprof,
+ EnvToString("PPROF_PATH", "pprof"),
+ "Path to pprof to call for reporting function names.");
+
+// heap_profile_table_pprof may be referenced after destructors are
+// called (since that's when leak-checking is done), so we make
+// a more-permanent copy that won't ever get destroyed.
+static string* g_pprof_path = new string(FLAGS_symbolize_pprof);
+
+// Updates symbolization_table with the pointers to symbol names corresponding
+// to its keys. The symbol names are stored in out, which is allocated and
+// freed by the caller of this routine.
+// Note that the forking/etc is not thread-safe or re-entrant. That's
+// ok for the purpose we need -- reporting leaks detected by heap-checker
+// -- but be careful if you decide to use this routine for other purposes.
+extern bool Symbolize(char *out, int out_size,
+ SymbolMap *symbolization_table) {
+#if !defined(HAVE_UNISTD_H) || !defined(HAVE_SYS_SOCKET_H) || !defined(HAVE_SYS_WAIT_H)
+ return false;
+#elif !defined(HAVE_PROGRAM_INVOCATION_NAME)
+ return false; // TODO(csilvers): get argv[0] somehow
+#else
+ // All this work is to do two-way communication. ugh.
+ extern char* program_invocation_name; // gcc provides this
+ int child_in[2]; // file descriptors
+ int child_out[2]; // for now, we don't worry about child_err
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_in) == -1) {
+ return false;
+ }
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_out) == -1) {
+ close(child_in[0]);
+ close(child_in[1]);
+ return false;
+ }
+ switch (fork()) {
+ case -1: { // error
+ close(child_in[0]);
+ close(child_in[1]);
+ close(child_out[0]);
+ close(child_out[1]);
+ return false;
+ }
+ case 0: { // child
+ close(child_in[1]); // child uses the 0's, parent uses the 1's
+ close(child_out[1]); // child uses the 0's, parent uses the 1's
+ close(0);
+ close(1);
+ if (dup2(child_in[0], 0) == -1) _exit(1);
+ if (dup2(child_out[0], 1) == -1) _exit(2);
+ // Unset vars that might cause trouble when we fork
+ unsetenv("CPUPROFILE");
+ unsetenv("HEAPPROFILE");
+ unsetenv("HEAPCHECK");
+ unsetenv("PERFTOOLS_VERBOSE");
+ execlp(g_pprof_path->c_str(), g_pprof_path->c_str(),
+ "--symbols", program_invocation_name, NULL);
+ _exit(3); // if execvp fails, it's bad news for us
+ }
+ default: { // parent
+ close(child_in[0]); // child uses the 0's, parent uses the 1's
+ close(child_out[0]); // child uses the 0's, parent uses the 1's
+#ifdef HAVE_POLL_H
+ // For maximum safety, we check to make sure the execlp
+ // succeeded before trying to write. (Otherwise we'll get a
+ // SIGPIPE.) For systems without poll.h, we'll just skip this
+ // check, and trust that the user set PPROF_PATH correctly!
+ struct pollfd pfd = { child_in[1], POLLOUT, 0 };
+ if (!poll(&pfd, 1, 0) || !(pfd.revents & POLLOUT) ||
+ (pfd.revents & (POLLHUP|POLLERR))) {
+ return false;
+ }
+#endif
+ DumpProcSelfMaps(child_in[1]); // what pprof expects on stdin
+
+ char pcstr[64]; // enough for a single address
+ for (SymbolMap::const_iterator iter = symbolization_table->begin();
+ iter != symbolization_table->end(); ++iter) {
+ snprintf(pcstr, sizeof(pcstr), // pprof expects format to be 0xXXXXXX
+ "0x%" PRIxPTR "\n", iter->first);
+ // TODO(glider): the number of write()s can be reduced by using
+ // snprintf() here.
+ ssize_t size = write(child_in[1], pcstr, strlen(pcstr));
+ // Use size so we don't get an unused variable warning.
+ CHECK(size);
+ }
+ close(child_in[1]); // that's all we need to write
+
+ int total_bytes_read = 0;
+ memset(out, '\0', out_size);
+ while (1) {
+ int bytes_read = read(child_out[1], out + total_bytes_read,
+ out_size - total_bytes_read);
+ if (bytes_read < 0) {
+ close(child_out[1]);
+ return false;
+ } else if (bytes_read == 0) {
+ close(child_out[1]);
+ wait(NULL);
+ break;
+ } else {
+ total_bytes_read += bytes_read;
+ }
+ }
+ // We have successfully read the output of pprof into out. Make sure
+ // the last symbol is full (we can tell because it ends with a \n).
+ // TODO(glider): even when the last symbol is full, the list of symbols
+ // may be incomplete. We should check for that and return the number of
+ // symbols we actually get from pprof.
+ if (total_bytes_read == 0 || out[total_bytes_read - 1] != '\n')
+ return false;
+ // make the symbolization_table values point to the output vector
+ SymbolMap::iterator fill = symbolization_table->begin();
+ char *current_name = out;
+ for (int i = 0; i < total_bytes_read; i++) {
+ if (out[i] == '\n') {
+ fill->second = current_name;
+ out[i] = '\0';
+ current_name = out + i + 1;
+ fill++;
+ }
+ }
+ return true;
+ }
+ }
+ return false; // shouldn't be reachable
+#endif
+}
diff --git a/third_party/tcmalloc/chromium/src/tcmalloc_linux.cc b/third_party/tcmalloc/chromium/src/tcmalloc_linux.cc
index 104520e..5b8e54a 100644
--- a/third_party/tcmalloc/chromium/src/tcmalloc_linux.cc
+++ b/third_party/tcmalloc/chromium/src/tcmalloc_linux.cc
@@ -488,7 +488,9 @@ static void PrintStats(int level) {
char* buffer = new char[kBufferSize];
TCMalloc_Printer printer(buffer, kBufferSize);
DumpStats(&printer, level);
- write(STDERR_FILENO, buffer, strlen(buffer));
+ ssize_t size = write(STDERR_FILENO, buffer, strlen(buffer));
+ // Use size so we don't get an unused variable warning.
+ CHECK(size);
delete[] buffer;
}