summaryrefslogtreecommitdiffstats
path: root/third_party/tcmalloc/chromium/src/base/sysinfo.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/tcmalloc/chromium/src/base/sysinfo.cc')
-rw-r--r--third_party/tcmalloc/chromium/src/base/sysinfo.cc128
1 files changed, 99 insertions, 29 deletions
diff --git a/third_party/tcmalloc/chromium/src/base/sysinfo.cc b/third_party/tcmalloc/chromium/src/base/sysinfo.cc
index a2bc2a9..7af0495 100644
--- a/third_party/tcmalloc/chromium/src/base/sysinfo.cc
+++ b/third_party/tcmalloc/chromium/src/base/sysinfo.cc
@@ -100,11 +100,33 @@
// Some non-trivial getenv-related functions.
// ----------------------------------------------------------------------
+// It's not safe to call getenv() in the malloc hooks, because they
+// might be called extremely early, before libc is done setting up
+// correctly. In particular, the thread library may not be done
+// setting up errno. So instead, we use the built-in __environ array
+// if it exists, and otherwise read /proc/self/environ directly, using
+// system calls to read the file, and thus avoid setting errno.
+// /proc/self/environ has a limit of how much data it exports (around
+// 8K), so it's not an ideal solution.
const char* GetenvBeforeMain(const char* name) {
+#if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h
+ const int namelen = strlen(name);
+ for (char** p = __environ; *p; p++) {
+ if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match
+ return *p + namelen+1; // point after =
+ }
+ return NULL;
+#elif defined(PLATFORM_WINDOWS)
+ // TODO(mbelshe) - repeated calls to this function will overwrite the
+ // contents of the static buffer.
+ static char envbuf[1024]; // enough to hold any envvar we care about
+ if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1))
+ return NULL;
+ return envbuf;
+#else
// static is ok because this function should only be called before
// main(), when we're single-threaded.
static char envbuf[16<<10];
-#ifndef PLATFORM_WINDOWS
if (*envbuf == '\0') { // haven't read the environ yet
int fd = safeopen("/proc/self/environ", O_RDONLY);
// The -2 below guarantees the last two bytes of the buffer will be \0\0
@@ -129,12 +151,6 @@ const char* GetenvBeforeMain(const char* name) {
p = endp + 1;
}
return NULL; // env var never found
-#else
- // TODO(mbelshe) - repeated calls to this function will overwrite the
- // contents of the static buffer.
- if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1))
- return NULL;
- return envbuf;
#endif
}
@@ -441,6 +457,48 @@ static void ConstructFilename(const char* spec, pid_t pid,
}
#endif
+// A templatized helper function instantiated for Mach (OS X) only.
+// It can handle finding info for both 32 bits and 64 bits.
+// Returns true if it successfully handled the hdr, false else.
+#ifdef __MACH__ // Mac OS X, almost certainly
+template<uint32_t kMagic, uint32_t kLCSegment,
+ typename MachHeader, typename SegmentCommand>
+static bool NextExtMachHelper(const mach_header* hdr,
+ int current_image, int current_load_cmd,
+ uint64 *start, uint64 *end, char **flags,
+ uint64 *offset, int64 *inode, char **filename,
+ uint64 *file_mapping, uint64 *file_pages,
+ uint64 *anon_mapping, uint64 *anon_pages,
+ dev_t *dev) {
+ static char kDefaultPerms[5] = "r-xp";
+ if (hdr->magic != kMagic)
+ return false;
+ const char* lc = (const char *)hdr + sizeof(MachHeader);
+ // TODO(csilvers): make this not-quadradic (increment and hold state)
+ for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd
+ lc += ((const load_command *)lc)->cmdsize;
+ if (((const load_command *)lc)->cmd == kLCSegment) {
+ const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image);
+ const SegmentCommand* sc = (const SegmentCommand *)lc;
+ if (start) *start = sc->vmaddr + dlloff;
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+ if (flags) *flags = kDefaultPerms; // can we do better?
+ if (offset) *offset = sc->fileoff;
+ if (inode) *inode = 0;
+ if (filename)
+ *filename = const_cast<char*>(_dyld_get_image_name(current_image));
+ if (file_mapping) *file_mapping = 0;
+ if (file_pages) *file_pages = 0; // could we use sc->filesize?
+ if (anon_mapping) *anon_mapping = 0;
+ if (anon_pages) *anon_pages = 0;
+ if (dev) *dev = 0;
+ return true;
+ }
+
+ return false;
+}
+#endif
+
ProcMapsIterator::ProcMapsIterator(pid_t pid) {
Init(pid, NULL, false);
}
@@ -456,6 +514,7 @@ ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer,
void ProcMapsIterator::Init(pid_t pid, Buffer *buffer,
bool use_maps_backing) {
+ pid_ = pid;
using_maps_backing_ = use_maps_backing;
dynamic_buffer_ = NULL;
if (!buffer) {
@@ -691,6 +750,7 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4);
COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2);
COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1);
+ Buffer object_path;
int nread = 0; // fill up buffer with text
NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t)));
if (nread == sizeof(prmap_t)) {
@@ -700,13 +760,27 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
// two middle ints are major and minor device numbers, but I'm not sure.
sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname);
+ if (pid_ == 0) {
+ CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize,
+ "/proc/self/path/%s", mapinfo->pr_mapname),
+ Buffer::kBufSize);
+ } else {
+ CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize,
+ "/proc/%d/path/%s", pid_, mapinfo->pr_mapname),
+ Buffer::kBufSize);
+ }
+ ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX);
+ CHECK_LT(len, PATH_MAX);
+ if (len < 0)
+ len = 0;
+ current_filename_[len] = '\0';
+
if (start) *start = mapinfo->pr_vaddr;
if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size;
if (flags) *flags = kPerms[mapinfo->pr_mflags & 7];
if (offset) *offset = mapinfo->pr_offset;
if (inode) *inode = inode_from_mapname;
- // TODO(csilvers): How to map from /proc/map/object to filename?
- if (filename) *filename = mapinfo->pr_mapname; // format is ufs.?.?.inode
+ if (filename) *filename = current_filename_;
if (file_mapping) *file_mapping = 0;
if (file_pages) *file_pages = 0;
if (anon_mapping) *anon_mapping = 0;
@@ -715,7 +789,6 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
return true;
}
#elif defined(__MACH__)
- static char kDefaultPerms[5] = "r-xp";
// We return a separate entry for each segment in the DLL. (TODO(csilvers):
// can we do better?) A DLL ("image") has load-commands, some of which
// talk about segment boundaries.
@@ -728,25 +801,22 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
// We start with the next load command (we've already looked at this one).
for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) {
- const char* lc = ((const char *)hdr + sizeof(struct mach_header));
- // TODO(csilvers): make this not-quadradic (increment and hold state)
- for (int j = 0; j < current_load_cmd_; j++) // advance to *our* load_cmd
- lc += ((const load_command *)lc)->cmdsize;
- if (((const load_command *)lc)->cmd == LC_SEGMENT) {
- const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image_);
- const segment_command* sc = (const segment_command *)lc;
- if (start) *start = sc->vmaddr + dlloff;
- if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
- if (flags) *flags = kDefaultPerms; // can we do better?
- if (offset) *offset = sc->fileoff;
- if (inode) *inode = 0;
- if (filename)
- *filename = const_cast<char*>(_dyld_get_image_name(current_image_));
- if (file_mapping) *file_mapping = 0;
- if (file_pages) *file_pages = 0; // could we use sc->filesize?
- if (anon_mapping) *anon_mapping = 0;
- if (anon_pages) *anon_pages = 0;
- if (dev) *dev = 0;
+#ifdef MH_MAGIC_64
+ if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64,
+ struct mach_header_64, struct segment_command_64>(
+ hdr, current_image_, current_load_cmd_,
+ start, end, flags, offset, inode, filename,
+ file_mapping, file_pages, anon_mapping,
+ anon_pages, dev)) {
+ return true;
+ }
+#endif
+ if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT,
+ struct mach_header, struct segment_command>(
+ hdr, current_image_, current_load_cmd_,
+ start, end, flags, offset, inode, filename,
+ file_mapping, file_pages, anon_mapping,
+ anon_pages, dev)) {
return true;
}
}