summaryrefslogtreecommitdiffstats
path: root/third_party/tcmalloc/chromium/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/tcmalloc/chromium/src/base')
-rw-r--r--third_party/tcmalloc/chromium/src/base/basictypes.h30
-rw-r--r--third_party/tcmalloc/chromium/src/base/dynamic_annotations.h14
-rw-r--r--third_party/tcmalloc/chromium/src/base/logging.h11
-rw-r--r--third_party/tcmalloc/chromium/src/base/low_level_alloc.cc89
-rw-r--r--third_party/tcmalloc/chromium/src/base/low_level_alloc.h22
-rw-r--r--third_party/tcmalloc/chromium/src/base/spinlock.h2
-rw-r--r--third_party/tcmalloc/chromium/src/base/sysinfo.cc128
-rw-r--r--third_party/tcmalloc/chromium/src/base/sysinfo.h4
8 files changed, 235 insertions, 65 deletions
diff --git a/third_party/tcmalloc/chromium/src/base/basictypes.h b/third_party/tcmalloc/chromium/src/base/basictypes.h
index e4d4140..9991413 100644
--- a/third_party/tcmalloc/chromium/src/base/basictypes.h
+++ b/third_party/tcmalloc/chromium/src/base/basictypes.h
@@ -240,7 +240,7 @@ struct CompileAssert {
# define HAVE_ATTRIBUTE_SECTION_START 1
#elif defined(HAVE___ATTRIBUTE__) && defined(__MACH__)
-# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__DATA, " #name)))
+# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__TEXT, " #name)))
#include <mach-o/getsect.h>
#include <mach-o/dyld.h>
@@ -251,18 +251,32 @@ class AssignAttributeStartEnd {
if (_dyld_present()) {
for (int i = _dyld_image_count() - 1; i >= 0; --i) {
const mach_header* hdr = _dyld_get_image_header(i);
- uint32_t len;
- *pstart = getsectdatafromheader(hdr, "__DATA", name, &len);
- if (*pstart) { // NULL if not defined in this dynamic library
- *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc
- *pend = *pstart + len;
- return;
+#ifdef MH_MAGIC_64
+ if (hdr->magic == MH_MAGIC_64) {
+ uint64_t len;
+ *pstart = getsectdatafromheader_64((mach_header_64*)hdr,
+ "__TEXT", name, &len);
+ if (*pstart) { // NULL if not defined in this dynamic library
+ *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc
+ *pend = *pstart + len;
+ return;
+ }
+ }
+#endif
+ if (hdr->magic == MH_MAGIC) {
+ uint32_t len;
+ *pstart = getsectdatafromheader(hdr, "__TEXT", name, &len);
+ if (*pstart) { // NULL if not defined in this dynamic library
+ *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc
+ *pend = *pstart + len;
+ return;
+ }
}
}
}
// If we get here, not defined in a dll at all. See if defined statically.
unsigned long len; // don't ask me why this type isn't uint32_t too...
- *pstart = getsectdata("__DATA", name, &len);
+ *pstart = getsectdata("__TEXT", name, &len);
*pend = *pstart + len;
}
};
diff --git a/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h b/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h
index 5995ac4..a2a268f 100644
--- a/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h
+++ b/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h
@@ -203,9 +203,16 @@
} while (0)
// Instruct the tool to create a happens-before arc between mu->Unlock() and
- // mu->Lock(). This annotation may slow down the race detector; normally it
- // is used only when it would be difficult to annotate each of the mutex's
- // critical sections individually using the annotations above.
+ // mu->Lock(). This annotation may slow down the race detector and hide real
+ // races. Normally it is used only when it would be difficult to annotate each
+ // of the mutex's critical sections individually using the annotations above.
+ // This annotation makes sense only for hybrid race detectors. For pure
+ // happens-before detectors this is a no-op. For more details see
+ // http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid .
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+ AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu)
+
+ // Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
#define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu)
@@ -357,6 +364,7 @@
#define ANNOTATE_NEW_MEMORY(address, size) // empty
#define ANNOTATE_EXPECT_RACE(address, description) // empty
#define ANNOTATE_BENIGN_RACE(address, description) // empty
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) // empty
#define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) // empty
#define ANNOTATE_TRACE_MEMORY(arg) // empty
#define ANNOTATE_THREAD_NAME(name) // empty
diff --git a/third_party/tcmalloc/chromium/src/base/logging.h b/third_party/tcmalloc/chromium/src/base/logging.h
index 3313d97..4d5e30c 100644
--- a/third_party/tcmalloc/chromium/src/base/logging.h
+++ b/third_party/tcmalloc/chromium/src/base/logging.h
@@ -136,17 +136,26 @@ enum { DEBUG_MODE = 1 };
#define CHECK_GE(val1, val2) CHECK_OP(>=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(> , val1, val2)
-// A synonym for CHECK_* that is used in some unittests.
+// Synonyms for CHECK_* that are used in some unittests.
#define EXPECT_EQ(val1, val2) CHECK_EQ(val1, val2)
#define EXPECT_NE(val1, val2) CHECK_NE(val1, val2)
#define EXPECT_LE(val1, val2) CHECK_LE(val1, val2)
#define EXPECT_LT(val1, val2) CHECK_LT(val1, val2)
#define EXPECT_GE(val1, val2) CHECK_GE(val1, val2)
#define EXPECT_GT(val1, val2) CHECK_GT(val1, val2)
+#define ASSERT_EQ(val1, val2) EXPECT_EQ(val1, val2)
+#define ASSERT_NE(val1, val2) EXPECT_NE(val1, val2)
+#define ASSERT_LE(val1, val2) EXPECT_LE(val1, val2)
+#define ASSERT_LT(val1, val2) EXPECT_LT(val1, val2)
+#define ASSERT_GE(val1, val2) EXPECT_GE(val1, val2)
+#define ASSERT_GT(val1, val2) EXPECT_GT(val1, val2)
// As are these variants.
#define EXPECT_TRUE(cond) CHECK(cond)
#define EXPECT_FALSE(cond) CHECK(!(cond))
#define EXPECT_STREQ(a, b) CHECK(strcmp(a, b) == 0)
+#define ASSERT_TRUE(cond) EXPECT_TRUE(cond)
+#define ASSERT_FALSE(cond) EXPECT_FALSE(cond)
+#define ASSERT_STREQ(a, b) EXPECT_STREQ(a, b)
// Used for (libc) functions that return -1 and set errno
#define CHECK_ERR(invocation) PCHECK((invocation) != -1)
diff --git a/third_party/tcmalloc/chromium/src/base/low_level_alloc.cc b/third_party/tcmalloc/chromium/src/base/low_level_alloc.cc
index 900ae4e..2bbce54 100644
--- a/third_party/tcmalloc/chromium/src/base/low_level_alloc.cc
+++ b/third_party/tcmalloc/chromium/src/base/low_level_alloc.cc
@@ -67,7 +67,7 @@ namespace {
// first. Valid in both allocated and unallocated blocks
intptr_t magic; // kMagicAllocated or kMagicUnallocated xor this
LowLevelAlloc::Arena *arena; // pointer to parent arena
- void *dummy_for_alignment; // aligns regions to 0 mod 2*sizeof(void*)
+ void *dummy_for_alignment; // aligns regions to 0 mod 2*sizeof(void*)
} header;
// Next two fields: in unallocated blocks: freelist skiplist data
@@ -197,15 +197,57 @@ struct LowLevelAlloc::Arena {
// pointer.
static struct LowLevelAlloc::Arena default_arena;
-// A non-malloc-hooked arena: used only to allocate metadata for arenas that
+// Non-malloc-hooked arenas: used only to allocate metadata for arenas that
// do not want malloc hook reporting, so that for them there's no malloc hook
// reporting even during arena creation.
static struct LowLevelAlloc::Arena unhooked_arena;
+static struct LowLevelAlloc::Arena unhooked_async_sig_safe_arena;
// magic numbers to identify allocated and unallocated blocks
static const intptr_t kMagicAllocated = 0x4c833e95;
static const intptr_t kMagicUnallocated = ~kMagicAllocated;
+namespace {
+ class ArenaLock {
+ public:
+ explicit ArenaLock(LowLevelAlloc::Arena *arena) :
+ left_(false), mask_valid_(false), arena_(arena) {
+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+ // We've decided not to support async-signal-safe arena use until
+ // there a demonstrated need. Here's how one could do it though
+ // (would need to be made more portable).
+#if 0
+ sigset_t all;
+ sigfillset(&all);
+ this->mask_valid_ =
+ (pthread_sigmask(SIG_BLOCK, &all, &this->mask_) == 0);
+#else
+ RAW_CHECK(false, "We do not yet support async-signal-safe arena.");
+#endif
+ }
+ this->arena_->mu.Lock();
+ }
+ ~ArenaLock() { RAW_CHECK(this->left_, "haven't left Arena region"); }
+ void Leave() {
+ this->arena_->mu.Unlock();
+#if 0
+ if (this->mask_valid_) {
+ pthread_sigmask(SIG_SETMASK, &this->mask_, 0);
+ }
+#endif
+ this->left_ = true;
+ }
+ private:
+ bool left_; // whether left region
+ bool mask_valid_;
+#if 0
+ sigset_t mask_; // old mask of blocked signals
+#endif
+ LowLevelAlloc::Arena *arena_;
+ DISALLOW_COPY_AND_ASSIGN(ArenaLock);
+ };
+} // anonymous namespace
+
// create an appropriate magic number for an object at "ptr"
// "magic" should be kMagicAllocated or kMagicUnallocated
inline static intptr_t Magic(intptr_t magic, AllocList::Header *ptr) {
@@ -235,6 +277,8 @@ static void ArenaInit(LowLevelAlloc::Arena *arena) {
// Default arena should be hooked, e.g. for heap-checker to trace
// pointer chains through objects in the default arena.
arena->flags = LowLevelAlloc::kCallMallocHook;
+ } else if (arena == &unhooked_async_sig_safe_arena) {
+ arena->flags = LowLevelAlloc::kAsyncSignalSafe;
} else {
arena->flags = 0; // other arenas' flags may be overridden by client,
// but unhooked_arena will have 0 in 'flags'.
@@ -246,9 +290,12 @@ static void ArenaInit(LowLevelAlloc::Arena *arena) {
LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32 flags,
Arena *meta_data_arena) {
RAW_CHECK(meta_data_arena != 0, "must pass a valid arena");
- if (meta_data_arena == &default_arena &&
- (flags & LowLevelAlloc::kCallMallocHook) == 0) {
- meta_data_arena = &unhooked_arena;
+ if (meta_data_arena == &default_arena) {
+ if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+ meta_data_arena = &unhooked_async_sig_safe_arena;
+ } else if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
+ meta_data_arena = &unhooked_arena;
+ }
}
// Arena(0) uses the constructor for non-static contexts
Arena *result =
@@ -262,9 +309,9 @@ LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32 flags,
bool LowLevelAlloc::DeleteArena(Arena *arena) {
RAW_CHECK(arena != 0 && arena != &default_arena && arena != &unhooked_arena,
"may not delete default arena");
- arena->mu.Lock();
+ ArenaLock section(arena);
bool empty = (arena->allocation_count == 0);
- arena->mu.Unlock();
+ section.Leave();
if (empty) {
while (arena->freelist.next[0] != 0) {
AllocList *region = arena->freelist.next[0];
@@ -279,7 +326,13 @@ bool LowLevelAlloc::DeleteArena(Arena *arena) {
"empty arena has non-page-aligned block size");
RAW_CHECK(reinterpret_cast<intptr_t>(region) % arena->pagesize == 0,
"empty arena has non-page-aligned block");
- RAW_CHECK(munmap(region, size) == 0,
+ int munmap_result;
+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
+ munmap_result = munmap(region, size);
+ } else {
+ munmap_result = MallocHook::UnhookedMUnmap(region, size);
+ }
+ RAW_CHECK(munmap_result == 0,
"LowLevelAlloc::DeleteArena: munmap failed address");
}
Free(arena);
@@ -363,21 +416,21 @@ void LowLevelAlloc::Free(void *v) {
if ((arena->flags & kCallMallocHook) != 0) {
MallocHook::InvokeDeleteHook(v);
}
- arena->mu.Lock();
+ ArenaLock section(arena);
AddToFreelist(v, arena);
RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
arena->allocation_count--;
- arena->mu.Unlock();
+ section.Leave();
}
}
// allocates and returns a block of size bytes, to be freed with Free()
// L < arena->mu
-void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
+static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
void *result = 0;
if (request != 0) {
AllocList *s; // will point to region that satisfies request
- arena->mu.Lock();
+ ArenaLock section(arena);
ArenaInit(arena);
// round up with header
size_t req_rnd = RoundUp(request + sizeof (s->header), arena->roundup);
@@ -399,8 +452,14 @@ void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
// mmap generous 64K chunks to decrease
// the chances/impact of fragmentation:
size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
- void *new_pages = mmap(0, new_pages_size,
- PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ void *new_pages;
+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+ new_pages = MallocHook::UnhookedMMap(0, new_pages_size,
+ PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ } else {
+ new_pages = mmap(0, new_pages_size,
+ PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ }
RAW_CHECK(new_pages != MAP_FAILED, "mmap error");
arena->mu.Lock();
s = reinterpret_cast<AllocList *>(new_pages);
@@ -425,7 +484,7 @@ void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
s->header.magic = Magic(kMagicAllocated, &s->header);
RAW_CHECK(s->header.arena == arena, "");
arena->allocation_count++;
- arena->mu.Unlock();
+ section.Leave();
result = &s->levels;
}
ANNOTATE_NEW_MEMORY(result, request);
diff --git a/third_party/tcmalloc/chromium/src/base/low_level_alloc.h b/third_party/tcmalloc/chromium/src/base/low_level_alloc.h
index 0df1298..393b3d2 100644
--- a/third_party/tcmalloc/chromium/src/base/low_level_alloc.h
+++ b/third_party/tcmalloc/chromium/src/base/low_level_alloc.h
@@ -72,14 +72,20 @@ class LowLevelAlloc {
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
// These values may be ored into flags:
enum {
- // Calls to Alloc() and Free() will be reported
- // via the MallocHook interface.
- // The DefaultArena() has this flag on.
- // NewArena(flags, DefaultArena()) w/o this bit in 'flags',
- // on the other hand, will not cause any MallocHook
- // calls even during the NewArena call itself
- // (it will in fact use meta_data_arena different from DefaultArena()).
- kCallMallocHook = 0x0001
+ // Report calls to Alloc() and Free() via the MallocHook interface.
+ // Set in the DefaultArena.
+ kCallMallocHook = 0x0001,
+
+ // Make calls to Alloc(), Free() be async-signal-safe. Not set in
+ // DefaultArena().
+ kAsyncSignalSafe = 0x0002,
+
+ // When used with DefaultArena(), the NewArena() and DeleteArena() calls
+ // obey the flags given explicitly in the NewArena() call, even if those
+ // flags differ from the settings in DefaultArena(). So the call
+ // NewArena(kAsyncSignalSafe, DefaultArena()) is itself async-signal-safe,
+ // as well as generatating an arena that provides async-signal-safe
+ // Alloc/Free.
};
static Arena *NewArena(int32 flags, Arena *meta_data_arena);
diff --git a/third_party/tcmalloc/chromium/src/base/spinlock.h b/third_party/tcmalloc/chromium/src/base/spinlock.h
index dda59a6..9e633c4 100644
--- a/third_party/tcmalloc/chromium/src/base/spinlock.h
+++ b/third_party/tcmalloc/chromium/src/base/spinlock.h
@@ -134,7 +134,7 @@ class LOCKABLE SpinLock {
void SlowLock();
void SlowUnlock(int64 wait_timestamp);
- DISALLOW_EVIL_CONSTRUCTORS(SpinLock);
+ DISALLOW_COPY_AND_ASSIGN(SpinLock);
};
// Corresponding locker object that arranges to acquire a spinlock for
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;
}
}
diff --git a/third_party/tcmalloc/chromium/src/base/sysinfo.h b/third_party/tcmalloc/chromium/src/base/sysinfo.h
index b4b5c9f..0bcc1f5 100644
--- a/third_party/tcmalloc/chromium/src/base/sysinfo.h
+++ b/third_party/tcmalloc/chromium/src/base/sysinfo.h
@@ -209,9 +209,13 @@ class ProcMapsIterator {
#elif defined(__MACH__)
int current_image_; // dll's are called "images" in macos parlance
int current_load_cmd_; // the segment of this dll we're examining
+#elif defined(__sun__) // Solaris
+ int fd_;
+ char current_filename_[PATH_MAX];
#else
int fd_; // filehandle on /proc/*/maps
#endif
+ pid_t pid_;
char flags_[10];
Buffer* dynamic_buffer_; // dynamically-allocated Buffer
bool using_maps_backing_; // true if we are looking at maps_backing instead of maps.