15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h> 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (defined(_WIN32) || defined(__MINGW32__)) && !defined(__CYGWIN__) && !defined(__CYGWIN32) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define PLATFORM_WINDOWS 1 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> // for getenv() 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> // for snprintf(), sscanf() 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> // for memmove(), memchr(), etc. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> // for open() 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> // for errno 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_UNISTD_H 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> // for read() 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined __MACH__ // Mac OS X, almost certainly 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach-o/dyld.h> // for iterating over dll's in ProcMapsIter 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach-o/loader.h> // for iterating over dll's in ProcMapsIter 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/sysctl.h> // how we figure out numcpu's on OS X 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined __FreeBSD__ 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/sysctl.h> 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined __sun__ // Solaris 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <procfs.h> // for, e.g., prmap_t 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(PLATFORM_WINDOWS) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <process.h> // for getpid() (actually, _getpid()) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlwapi.h> // for SHGetValueA() 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <tlhelp32.h> // for Module32First() 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h" 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/commandlineflags.h" 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/dynamic_annotations.h" // for RunningOnValgrind 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/cycleclock.h" 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PLATFORM_WINDOWS 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef MODULEENTRY32 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In a change from the usual W-A pattern, there is no A variant of 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MODULEENTRY32W. These #undefs are the only way I see to get back 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// access to the original, ascii struct (and related functions). 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef MODULEENTRY32 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef Module32First 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef Module32Next 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef PMODULEENTRY32 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef LPMODULEENTRY32 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* MODULEENTRY32 */ 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MinGW doesn't seem to define this, perhaps some windowsen don't either. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef TH32CS_SNAPMODULE32 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TH32CS_SNAPMODULE32 0 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* TH32CS_SNAPMODULE32 */ 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* PLATFORM_WINDOWS */ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Re-run fn until it doesn't cause EINTR. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// open/read/close can set errno, which may be illegal at this 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time, so prefer making the syscalls directly if we can. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_SYS_SYSCALL_H 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include <sys/syscall.h> 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SYS_open // solaris 11, at least sometimes, only defines SYS_openat 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define safeopen(filename, mode) syscall(SYS_open, filename, mode) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define safeopen(filename, mode) open(filename, mode) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SYS_read 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define saferead(fd, buffer, size) syscall(SYS_read, fd, buffer, size) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define saferead(fd, buffer, size) read(fd, buffer, size) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SYS_close 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define safeclose(fd) syscall(SYS_close, fd) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define safeclose(fd) close(fd) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetenvBeforeMain() 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetUniquePathFromEnv() 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some non-trivial getenv-related functions. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It's not safe to call getenv() in the malloc hooks, because they 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// might be called extremely early, before libc is done setting up 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// correctly. In particular, the thread library may not be done 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// setting up errno. So instead, we use the built-in __environ array 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if it exists, and otherwise read /proc/self/environ directly, using 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// system calls to read the file, and thus avoid setting errno. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /proc/self/environ has a limit of how much data it exports (around 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 8K), so it's not an ideal solution. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* GetenvBeforeMain(const char* name) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (__environ) { // can exist but be NULL, if statically linked 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int namelen = strlen(name); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (char** p = __environ; *p; p++) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *p + namelen+1; // point after = 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(PLATFORM_WINDOWS) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mbelshe) - repeated calls to this function will overwrite the 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // contents of the static buffer. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static char envvar_buf[1024]; // enough to hold any envvar we care about 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetEnvironmentVariableA(name, envvar_buf, sizeof(envvar_buf)-1)) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return envvar_buf; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // static is ok because this function should only be called before 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // main(), when we're single-threaded. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static char envbuf[16<<10]; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*envbuf == '\0') { // haven't read the environ yet 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd = safeopen("/proc/self/environ", O_RDONLY); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The -2 below guarantees the last two bytes of the buffer will be \0\0 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd == -1 || // unable to open the file, fall back onto libc 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "on getenv(\"%s\"), which may not work", name); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd != -1) safeclose(fd); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return getenv(name); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safeclose(fd); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int namelen = strlen(name); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* p = envbuf; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*p != '\0') { // will happen at the \0\0 that terminates the buffer 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // proc file has the format NAME=value\0NAME=value\0NAME=value\0... 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (endp == NULL) // this entry isn't NUL terminated 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p + namelen+1; // point after = 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = endp + 1; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; // env var never found 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This takes as an argument an environment-variable name (like 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CPUPROFILE) whose value is supposed to be a file-path, and sets 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// path to that path, and returns true. If the env var doesn't exist, 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or is the empty string, leave path unchanged and returns false. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The reason this is non-trivial is that this function handles munged 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pathnames. Here's why: 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If we're a child process of the 'main' process, we can't just use 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// getenv("CPUPROFILE") -- the parent process will be using that path. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Instead we append our pid to the pathname. How do we tell if we're a 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// child process? Ideally we'd set an environment variable that all 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// our children would inherit. But -- and this is seemingly a bug in 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// gcc -- if you do a setenv() in a shared libarary in a global 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// constructor, the environment setting is lost by the time main() is 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called. The only safe thing we can do in such a situation is to 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modify the existing envvar. So we do a hack: in the parent, we set 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the high bit of the 1st char of CPUPROFILE. In the child, we 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice the high bit is set and append the pid(). This works 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// assuming cpuprofile filenames don't normally have the high bit set 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in their first character! If that assumption is violated, we'll 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// still get a profile, but one with an unexpected name. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(csilvers): set an envvar instead when we can do it reliably. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetUniquePathFromEnv(const char* env_name, char* path) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* envval = getenv(env_name); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (envval == NULL || *envval == '\0') 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (envval[0] & 128) { // high bit is set 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(path, PATH_MAX, "%c%s_%u", // add pid and clear high bit 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) envval[0] & 127, envval+1, (unsigned int)(getpid())); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(path, PATH_MAX, "%s", envval); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) envval[0] |= 128; // set high bit for kids to see 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CyclesPerSecond() 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NumCPUs() 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It's important this not call malloc! -- they may be called at 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// global-construct time, before we've set up all our proper malloc 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// hooks and such. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static double cpuinfo_cycles_per_second = 1.0; // 0.0 might be dangerous 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int cpuinfo_num_cpus = 1; // Conservative guess 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SleepForMilliseconds(int milliseconds) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PLATFORM_WINDOWS 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _sleep(milliseconds); // Windows's _sleep takes milliseconds argument 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sleep for a few milliseconds 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct timespec sleep_time; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sleep_time.tv_sec = milliseconds / 1000; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sleep_time.tv_nsec = (milliseconds % 1000) * 1000000; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ; // Ignore signals and wait for the full interval to elapse. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function estimates cycles/sec by observing cycles elapsed during 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sleep(). Using small sleep time decreases accuracy significantly. 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(estimate_time_ms > 0); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (estimate_time_ms <= 0) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double multiplier = 1000.0 / (double)estimate_time_ms; // scale by this much 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 start_ticks = CycleClock::Now(); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SleepForMilliseconds(estimate_time_ms); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 guess = int64(multiplier * (CycleClock::Now() - start_ticks)); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return guess; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ReadIntFromFile is only called on linux and cygwin platforms. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function for reading an int from a file. Returns true if successful 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and the memory location pointed to by value is set to the value read. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool ReadIntFromFile(const char *file, int *value) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ret = false; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd = open(file, O_RDONLY); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd != -1) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char line[1024]; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* err; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(line, '\0', sizeof(line)); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read(fd, line, sizeof(line) - 1); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int temp_value = strtol(line, &err, 10); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *value = temp_value; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret = true; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WARNING: logging calls back to InitializeSystemInfo() so it must 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not invoke any logging code. Also, InitializeSystemInfo() can be 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called before main() -- in fact it *must* be since already_called 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// isn't protected -- before malloc hooks are properly set up, so 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we make an effort not to call any routines which might allocate 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// memory. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void InitializeSystemInfo() { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool already_called = false; // safe if we run before threads 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (already_called) return; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) already_called = true; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool saw_mhz = false; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (RunningOnValgrind()) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Valgrind may slow the progress of time artificially (--scale-time=N 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // option). We thus can't rely on CPU Mhz info stored in /sys or /proc 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // files. Thus, actually measure the cps. 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(100); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_mhz = true; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char line[1024]; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* err; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int freq; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the kernel is exporting the tsc frequency use that. There are issues 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // where cpuinfo_max_freq cannot be relied on because the BIOS may be 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exporintg an invalid p-state (on x86) or p-states may be used to put the 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // processor in a new mode (turbo mode). Essentially, those frequencies 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // well. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_mhz && 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The value is in kHz (as the file name suggests). For example, on a 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2GHz warpstation, the file contains the value "2000000". 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = freq * 1000.0; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_mhz = true; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If CPU scaling is in effect, we want to use the *maximum* frequency, 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not whatever CPU speed some random processor happens to be using now. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_mhz && 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &freq)) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The value is in kHz. For example, on a 2GHz machine, the file 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // contains the value "2000000". 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = freq * 1000.0; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_mhz = true; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* pname = "/proc/cpuinfo"; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd = open(pname, O_RDONLY); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd == -1) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror(pname); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_mhz) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // TODO: use generic tester instead? 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double bogo_clock = 1.0; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool saw_bogo = false; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_cpus = 0; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line[0] = line[1] = '\0'; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int chars_read = 0; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { // we'll exit when the last read didn't read anything 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move the next line to the beginning of the buffer 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int oldlinelen = strlen(line); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line[0] = '\0'; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else // still other lines left to save 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove(line, line + oldlinelen+1, sizeof(line) - (oldlinelen+1)); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Terminate the new line, reading more if we can't find the newline 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* newline = strchr(line, '\n'); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newline == NULL) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int linelen = strlen(line); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bytes_to_read = sizeof(line)-1 - linelen; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(bytes_to_read > 0); // because the memmove recovered >=1 bytes 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chars_read = read(fd, line + linelen, bytes_to_read); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line[linelen + chars_read] = '\0'; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newline = strchr(line, '\n'); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newline != NULL) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *newline = '\0'; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // accept postive values. Some environments (virtual machines) report zero, 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which would cause infinite looping in WallTime_Init. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* freqstr = strchr(line, ':'); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (freqstr) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_mhz = true; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strncasecmp(line, "bogomips", sizeof("bogomips")-1) == 0) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* freqstr = strchr(line, ':'); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (freqstr) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bogo_clock = strtod(freqstr+1, &err) * 1000000.0; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_bogo = true; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strncasecmp(line, "processor", sizeof("processor")-1) == 0) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_cpus++; // count up every time we see an "processor :" entry 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (chars_read > 0); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_mhz) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (saw_bogo) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we didn't find anything better, we'll use bogomips, but 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we're not happy about it. 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = bogo_clock; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't even have bogomips, we'll use the slow estimation. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cpuinfo_cycles_per_second == 0.0) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = 1.0; // maybe unnecessary, but safe 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_cpus > 0) { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_num_cpus = num_cpus; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined __FreeBSD__ 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For this sysctl to work, the machine must be configured without 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and later. Before that, it's a 32-bit quantity (and gives the 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wrong answer on machines faster than 2^32 Hz). See 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // But also compare FreeBSD 7.0: 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 231 error = sysctl_handle_quad(oidp, &freq, 0, req); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To FreeBSD 6.3 (it's the same in 6-STABLE): 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __FreeBSD__ >= 7 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64_t hz = 0; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int hz = 0; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t sz = sizeof(hz); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *sysctl_path = "machdep.tsc_freq"; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ( sysctlbyname(sysctl_path, &hz, &sz, NULL, 0) != 0 ) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sysctl_path, strerror(errno)); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = hz; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(csilvers): also figure out cpuinfo_num_cpus 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(PLATFORM_WINDOWS) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pragma comment(lib, "shlwapi.lib") // for SHGetValue() 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In NT, read MHz from the registry. If we fail to do so or we're in win9x 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then make a crude estimate. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSVERSIONINFO os; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.dwOSVersionInfoSize = sizeof(os); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD data, data_size = sizeof(data); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetVersionEx(&os) && 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.dwPlatformId == VER_PLATFORM_WIN32_NT && 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SUCCEEDED(SHGetValueA(HKEY_LOCAL_MACHINE, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "~MHz", NULL, &data, &data_size))) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = (int64)data * (int64)(1000 * 1000); // was mhz 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(500); // TODO <500? 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the number of processors. 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SYSTEM_INFO info; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSystemInfo(&info); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_num_cpus = info.dwNumberOfProcessors; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__MACH__) && defined(__APPLE__) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returning "mach time units" per second. the current number of elapsed 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mach time units can be found by calling uint64 mach_absolute_time(); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while not as precise as actual CPU cycles, it is accurate in the face 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of CPU frequency scaling and multi-cpu/core machines. 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Our mac users have these types of machines, and accuracy 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (i.e. correctness) trumps precision. 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See cycleclock.h: CycleClock::Now(), which returns number of mach time 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // units on Mac OS X. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mach_timebase_info_data_t timebase_info; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mach_timebase_info(&timebase_info); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double mach_time_units_per_nanosecond = 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(timebase_info.denom) / 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(timebase_info.numer); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = mach_time_units_per_nanosecond * 1e9; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_cpus = 0; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size = sizeof(num_cpus); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int numcpus_name[] = { CTL_HW, HW_NCPU }; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::sysctl(numcpus_name, arraysize(numcpus_name), &num_cpus, &size, 0, 0) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) == 0 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) && (size == sizeof(num_cpus))) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_num_cpus = num_cpus; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generic cycles per second counter 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double CyclesPerSecond(void) { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeSystemInfo(); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cpuinfo_cycles_per_second; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int NumCPUs(void) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeSystemInfo(); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cpuinfo_num_cpus; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HasPosixThreads() 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if we're running POSIX (e.g., NPTL on Linux) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// threads, as opposed to a non-POSIX thread libary. The thing 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that we care about is whether a thread's pid is the same as 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the thread that spawned it. If so, this function returns 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// true. 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasPosixThreads() { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _CS_GNU_LIBPTHREAD_VERSION 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _CS_GNU_LIBPTHREAD_VERSION 3 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[32]; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We assume that, if confstr() doesn't know about this name, then 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the same glibc is providing LinuxThreads. 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf)) == 0) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return strncmp(buf, "NPTL", 4) == 0; 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(PLATFORM_WINDOWS) || defined(__CYGWIN__) || defined(__CYGWIN32__) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // other OS 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Assume that everything else has Posix 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // else OS_LINUX 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------------------------------------------------------- 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYGWIN__ || defined __CYGWIN32__ 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ConstructFilename(const char* spec, pid_t pid, 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* buf, int buf_size) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LT(snprintf(buf, buf_size, 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spec, 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(pid ? pid : getpid())), buf_size); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A templatized helper function instantiated for Mach (OS X) only. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It can handle finding info for both 32 bits and 64 bits. 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if it successfully handled the hdr, false else. 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __MACH__ // Mac OS X, almost certainly 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<uint32_t kMagic, uint32_t kLCSegment, 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typename MachHeader, typename SegmentCommand> 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool NextExtMachHelper(const mach_header* hdr, 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int current_image, int current_load_cmd, 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *start, uint64 *end, char **flags, 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *offset, int64 *inode, char **filename, 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *file_mapping, uint64 *file_pages, 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *anon_mapping, uint64 *anon_pages, 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev_t *dev) { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static char kDefaultPerms[5] = "r-xp"; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hdr->magic != kMagic) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* lc = (const char *)hdr + sizeof(MachHeader); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(csilvers): make this not-quadradic (increment and hold state) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lc += ((const load_command *)lc)->cmdsize; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((const load_command *)lc)->cmd == kLCSegment) { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SegmentCommand* sc = (const SegmentCommand *)lc; 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start) *start = sc->vmaddr + dlloff; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end) *end = sc->vmaddr + sc->vmsize + dlloff; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags) *flags = kDefaultPerms; // can we do better? 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset) *offset = sc->fileoff; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (inode) *inode = 0; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *filename = const_cast<char*>(_dyld_get_image_name(current_image)); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_mapping) *file_mapping = 0; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_pages) *file_pages = 0; // could we use sc->filesize? 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_mapping) *anon_mapping = 0; 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_pages) *anon_pages = 0; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dev) *dev = 0; 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcMapsIterator::ProcMapsIterator(pid_t pid) { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(pid, NULL, false); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) { 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(pid, buffer, false); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool use_maps_backing) { 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(pid, buffer, use_maps_backing); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool use_maps_backing) { 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pid_ = pid; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_maps_backing_ = use_maps_backing; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dynamic_buffer_ = NULL; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!buffer) { 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the user didn't pass in any buffer storage, allocate it 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now. This is the normal case; the signal handler passes in a 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // static buffer. 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer = dynamic_buffer_ = new Buffer; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dynamic_buffer_ = NULL; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ibuf_ = buffer->buf_; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stext_ = etext_ = nextline_ = ibuf_; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ebuf_ = ibuf_ + Buffer::kBufSize - 1; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nextline_ = ibuf_; 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (use_maps_backing) { // don't bother with clever "self" stuff in this case 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/%d/maps_backing", pid, ibuf_, Buffer::kBufSize); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (pid == 0) { 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to kludge a bit to deal with the args ConstructFilename 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // expects. The 1 is never used -- it's only impt. that it's not 0. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/self/maps", 1, ibuf_, Buffer::kBufSize); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/%d/maps", pid, ibuf_, Buffer::kBufSize); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No error logging since this can be called from the crash dump 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handler at awkward moments. Users should call Valid() before 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // using. 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_INTR(fd_ = open(ibuf_, O_RDONLY)); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__FreeBSD__) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't support maps_backing on freebsd 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pid == 0) { 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/curproc/map", 1, ibuf_, Buffer::kBufSize); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_INTR(fd_ = open(ibuf_, O_RDONLY)); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__sun__) 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pid == 0) { 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/self/map", 1, ibuf_, Buffer::kBufSize); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_INTR(fd_ = open(ibuf_, O_RDONLY)); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__MACH__) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_image_ = _dyld_image_count(); // count down from the top 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_load_cmd_ = -1; 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(PLATFORM_WINDOWS) 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TH32CS_SNAPMODULE32, 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetCurrentProcessId()); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&module_, 0, sizeof(module_)); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_ = -1; // so Valid() is always false 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcMapsIterator::~ProcMapsIterator() { 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(PLATFORM_WINDOWS) 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (snapshot_ != INVALID_HANDLE_VALUE) CloseHandle(snapshot_); 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__MACH__) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // no cleanup necessary! 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd_ >= 0) NO_INTR(close(fd_)); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete dynamic_buffer_; 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcMapsIterator::Valid() const { 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(PLATFORM_WINDOWS) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return snapshot_ != INVALID_HANDLE_VALUE; 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__MACH__) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return fd_ != -1; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcMapsIterator::Next(uint64 *start, uint64 *end, char **flags, 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *offset, int64 *inode, char **filename) { 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NextExt(start, end, flags, offset, inode, filename, NULL, NULL, 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, NULL); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This has too many arguments. It should really be building 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a map object and returning it. The problem is that this is called 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when the memory allocator state is undefined, hence the arguments. 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *offset, int64 *inode, char **filename, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *file_mapping, uint64 *file_pages, 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 *anon_mapping, uint64 *anon_pages, 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev_t *dev) { 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__CYGWIN32__) 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Advance to the start of the next line 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stext_ = nextline_; 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See if we have a complete line in the buffer already 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ - stext_)); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nextline_) { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Shift/fill the buffer so we do have a line 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = etext_ - stext_; 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move the current text to the start of the buffer 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove(ibuf_, stext_, count); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stext_ = ibuf_; 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) etext_ = ibuf_ + count; 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nread = 0; // fill up buffer with text 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (etext_ < ebuf_) { 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_INTR(nread = read(fd_, etext_, ebuf_ - etext_)); 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nread > 0) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) etext_ += nread; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Zero out remaining characters in buffer at EOF to avoid returning 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // garbage from subsequent calls. 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (etext_ != ebuf_ && nread == 0) { 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(etext_, 0, ebuf_ - etext_); 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *etext_ = '\n'; // sentinel; safe because ibuf extends 1 char beyond ebuf 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ + 1 - stext_)); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *nextline_ = 0; // turn newline into nul 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nextline_ += ((nextline_ < etext_)? 1 : 0); // skip nul if not end of text 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stext_ now points at a nul-terminated line 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 tmpstart, tmpend, tmpoffset; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 tmpinode; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int major, minor; 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned filename_offset = 0; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for now, assume all linuxes have the same format 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(stext_, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n", 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start ? start : &tmpstart, 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end ? end : &tmpend, 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags_, 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset ? offset : &tmpoffset, 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &major, &minor, 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode ? inode : &tmpinode, &filename_offset) != 7) continue; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__CYGWIN__) || defined(__CYGWIN32__) 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cygwin is like linux, except the third field is the "entry point" 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rather than the offset (see format_process_maps at 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/fhandler_process.cc?rev=1.89&content-type=text/x-cvsweb-markup&cvsroot=src 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Offset is always be 0 on cygwin: cygwin implements an mmap 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // by loading the whole file and then calling NtMapViewOfSection. 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cygwin also seems to set its flags kinda randomly; use windows default. 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char tmpflags[5]; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *offset = 0; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(flags_, "r-xp"); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(stext_, "%llx-%llx %4s %llx %x:%x %lld %n", 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start ? start : &tmpstart, 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end ? end : &tmpend, 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmpflags, 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &tmpoffset, 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &major, &minor, 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode ? inode : &tmpinode, &filename_offset) != 7) continue; 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__FreeBSD__) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the format, see http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/fs/procfs/procfs_map.c?rev=1.31&content-type=text/x-cvsweb-markup 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmpstart = tmpend = tmpoffset = 0; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmpinode = 0; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) major = minor = 0; // can't get this info in freebsd 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (inode) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *inode = 0; // nor this 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset) 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *offset = 0; // seems like this should be in there, but maybe not 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start end resident privateresident obj(?) prot refcnt shadowcnt 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // flags copy_on_write needs_copy type filename: 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 0x8048000 0x804a000 2 0 0xc104ce70 r-x 1 0 0x0 COW NC vnode /bin/cat 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(stext_, "0x%"SCNx64" 0x%"SCNx64" %*d %*d %*p %3s %*d %*d 0x%*x %*s %*s %*s %n", 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start ? start : &tmpstart, 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end ? end : &tmpend, 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags_, 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &filename_offset) != 3) continue; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Depending on the Linux kernel being used, there may or may not be a space 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // after the inode if there is no filename. sscanf will in such situations 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nondeterministically either fill in filename_offset or not (the results 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // differ on multiple calls in the same run even with identical arguments). 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't want to wander off somewhere beyond the end of the string. 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t stext_length = strlen(stext_); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename_offset == 0 || filename_offset > stext_length) 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_offset = stext_length; 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We found an entry 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags) *flags = flags_; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename) *filename = stext_ + filename_offset; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dev) *dev = minor | (major << 8); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (using_maps_backing_) { 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract and parse physical page backing info. 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *backing_ptr = stext_ + filename_offset + 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlen(stext_+filename_offset); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // find the second '(' 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int paren_count = 0; 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (--backing_ptr > stext_) { 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*backing_ptr == '(') { 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++paren_count; 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (paren_count >= 2) { 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 tmp_file_mapping; 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 tmp_file_pages; 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 tmp_anon_mapping; 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 tmp_anon_pages; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sscanf(backing_ptr+1, "F %"SCNx64" %"SCNd64") (A %"SCNx64" %"SCNd64")", 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_mapping ? file_mapping : &tmp_file_mapping, 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_pages ? file_pages : &tmp_file_pages, 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anon_mapping ? anon_mapping : &tmp_anon_mapping, 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anon_pages ? anon_pages : &tmp_anon_pages); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // null terminate the file name (there is a space 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before the first (. 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) backing_ptr[-1] = 0; 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (etext_ > ibuf_); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__sun__) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static char kPerms[8][4] = { "---", "--x", "-w-", "-wx", 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "r--", "r-x", "rw-", "rwx" }; 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Buffer object_path; 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nread = 0; // fill up buffer with text 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nread == sizeof(prmap_t)) { 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long inode_from_mapname = 0; 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prmap_t* mapinfo = reinterpret_cast<prmap_t*>(ibuf_); 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Best-effort attempt to get the inode from the filename. I think the 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // two middle ints are major and minor device numbers, but I'm not sure. 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pid_ == 0) { 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "/proc/self/path/%s", mapinfo->pr_mapname), 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Buffer::kBufSize); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "/proc/%d/path/%s", 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(pid_), mapinfo->pr_mapname), 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Buffer::kBufSize); 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LT(len, PATH_MAX); 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len < 0) 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_filename_[len] = '\0'; 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start) *start = mapinfo->pr_vaddr; 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset) *offset = mapinfo->pr_offset; 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (inode) *inode = inode_from_mapname; 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename) *filename = current_filename_; 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_mapping) *file_mapping = 0; 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_pages) *file_pages = 0; 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_mapping) *anon_mapping = 0; 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_pages) *anon_pages = 0; 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dev) *dev = 0; 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__MACH__) 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We return a separate entry for each segment in the DLL. (TODO(csilvers): 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can we do better?) A DLL ("image") has load-commands, some of which 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // talk about segment boundaries. 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/minivoicemail/dlfcn.c?revision=53912 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; current_image_ >= 0; current_image_--) { 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const mach_header* hdr = _dyld_get_image_header(current_image_); 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!hdr) continue; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_load_cmd_ < 0) // set up for this image 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_load_cmd_ = hdr->ncmds; // again, go from the top down 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We start with the next load command (we've already looked at this one). 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef MH_MAGIC_64 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64, 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mach_header_64, struct segment_command_64>( 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr, current_image_, current_load_cmd_, 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, end, flags, offset, inode, filename, 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_mapping, file_pages, anon_mapping, 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anon_pages, dev)) { 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT, 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mach_header, struct segment_command>( 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr, current_image_, current_load_cmd_, 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, end, flags, offset, inode, filename, 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_mapping, file_pages, anon_mapping, 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anon_pages, dev)) { 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we get here, no more load_cmd's in this image talk about 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // segments. Go on to the next image. 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(PLATFORM_WINDOWS) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static char kDefaultPerms[5] = "r-xp"; 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok; 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (module_.dwSize == 0) { // only possible before first call 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) module_.dwSize = sizeof(module_); 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = Module32First(snapshot_, &module_); 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = Module32Next(snapshot_, &module_); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ok) { 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 base_addr = reinterpret_cast<DWORD_PTR>(module_.modBaseAddr); 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start) *start = base_addr; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end) *end = base_addr + module_.modBaseSize; 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags) *flags = kDefaultPerms; 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset) *offset = 0; 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (inode) *inode = 0; 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename) *filename = module_.szExePath; 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_mapping) *file_mapping = 0; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_pages) *file_pages = 0; 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_mapping) *anon_mapping = 0; 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (anon_pages) *anon_pages = 0; 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dev) *dev = 0; 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We didn't find anything 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ProcMapsIterator::FormatLine(char* buffer, int bufsize, 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 start, uint64 end, const char *flags, 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 offset, int64 inode, 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *filename, dev_t dev) { 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We assume 'flags' looks like 'rwxp' or 'rwx'. 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char r = (flags && flags[0] == 'r') ? 'r' : '-'; 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char w = (flags && flags[0] && flags[1] == 'w') ? 'w' : '-'; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char x = (flags && flags[0] && flags[1] && flags[2] == 'x') ? 'x' : '-'; 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // p always seems set on linux, so we set the default to 'p', not '-' 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char p = (flags && flags[0] && flags[1] && flags[2] && flags[3] != 'p') 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ? '-' : 'p'; 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int rc = snprintf(buffer, bufsize, 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%08"PRIx64"-%08"PRIx64" %c%c%c%c %08"PRIx64" %02x:%02x %-11"PRId64" %s\n", 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, end, r,w,x,p, offset, 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(dev/256), static_cast<int>(dev%256), 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode, filename); 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (rc < 0 || rc >= bufsize) ? 0 : rc; 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace tcmalloc { 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper to add the list of mapped shared libraries to a profile. 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size' 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and return the actual size occupied in 'buf'. We fill wrote_all to true 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if we successfully wrote all proc lines to buf, false else. 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We do not provision for 0-terminating 'buf'. 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FillProcSelfMaps(char buf[], int size, bool* wrote_all) { 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcMapsIterator::Buffer iterbuf; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 start, end, offset; 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 inode; 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *flags, *filename; 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bytes_written = 0; 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *wrote_all = true; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int line_length = it.FormatLine(buf + bytes_written, 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size - bytes_written, 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, end, flags, offset, 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode, filename, 0); 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line_length == 0) 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *wrote_all = false; // failed to write this line out 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes_written += line_length; 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bytes_written; 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dump the same data as FillProcSelfMaps reads to fd. 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It seems easier to repeat parts of FillProcSelfMaps here than to 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reuse it via a call. 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DumpProcSelfMaps(RawFD fd) { 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcMapsIterator::Buffer iterbuf; 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 start, end, offset; 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 inode; 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *flags, *filename; 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcMapsIterator::Buffer linebuf; 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, end, flags, offset, inode, filename, 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, linebuf.buf_, written); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace tcmalloc 986