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) * ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Maxim Lifantsev
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_MEMORY_REGION_MAP_H_
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_MEMORY_REGION_MAP_H_
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h>
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_PTHREAD
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_allocator.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/thread_annotations.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/low_level_alloc.h"
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "heap-profile-stats.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(maxim): add a unittest:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  execute a bunch of mmaps and compare memory map what strace logs
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  execute a bunch of mmap/munmup and compare memory map with
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  own accounting of what those mmaps generated
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Thread-safe class to collect and query the map of all memory regions
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in a process that have been created with mmap, munmap, mremap, sbrk.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For each memory region, we keep track of (and provide to users)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the stack trace that allocated that memory region.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The recorded stack trace depth is bounded by
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a user-supplied max_stack_depth parameter of Init().
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After initialization with Init()
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (which can happened even before global object constructor execution)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we collect the map by installing and monitoring MallocHook-s
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to mmap, munmap, mremap, sbrk.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// At any time one can query this map via provided interface.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For more details on the design of MemoryRegionMap
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// see the comment at the top of our .cc file.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryRegionMap {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Max call stack recording depth supported by Init().  Set it to be
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // high enough for all our clients.  Note: we do not define storage
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for this (doing that requires special handling in windows), so
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't take the address of it!
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kMaxStackDepth = 32;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Size of the hash table of buckets.  A structure of the bucket table is
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // described in heap-profile-stats.h.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kHashTableSize = 179999;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // interface ================================================================
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Every client of MemoryRegionMap must call Init() before first use,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and Shutdown() after last use.  This allows us to reference count
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this (singleton) class properly.  MemoryRegionMap assumes it's the
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only client of MallocHooks, so a client can only register other
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MallocHooks after calling Init() and must unregister them before
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // calling Shutdown().
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize this module to record memory allocation stack traces.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stack traces that have more than "max_stack_depth" frames
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are automatically shrunk to "max_stack_depth" when they are recorded.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Init() can be called more than once w/o harm, largest max_stack_depth
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be the effective one.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When "use_buckets" is true, then counts of mmap and munmap sizes will be
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // recorded with each stack trace.  If Init() is called more than once, then
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // counting will be effective after any call contained "use_buckets" of true.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It will install mmap, munmap, mremap, sbrk hooks
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and initialize arena_ and our hook and locks, hence one can use
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MemoryRegionMap::Lock()/Unlock() to manage the locks.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Uses Lock/Unlock inside.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void Init(int max_stack_depth, bool use_buckets);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to shutdown this module undoing what Init() did.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true iff could do full shutdown (or it was not attempted).
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Full shutdown is attempted when the number of Shutdown() calls equals
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the number of Init() calls.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool Shutdown();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Return true if MemoryRegionMap is initialized and recording, i.e. when
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // then number of Init() calls are more than the number of Shutdown() calls.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool IsRecordingLocked();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locks to protect our internal data structures.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These also protect use of arena_ if our Init() has been done.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The lock is recursive.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void Unlock() UNLOCK_FUNCTION(lock_);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true when the lock is held by this thread (for use in RAW_CHECK-s).
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool LockIsHeld();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locker object that acquires the MemoryRegionMap::Lock
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the duration of its lifetime (a C++ scope).
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class LockHolder {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LockHolder() { Lock(); }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~LockHolder() { Unlock(); }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(LockHolder);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A memory region that we know about through malloc_hook-s.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is essentially an interface through which MemoryRegionMap
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exports the collected data to its clients.  Thread-compatible.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Region {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uintptr_t start_addr;  // region start address
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uintptr_t end_addr;  // region end address
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int call_stack_depth;  // number of caller stack frames that we saved
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const void* call_stack[kMaxStackDepth];  // caller address stack array
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             // filled to call_stack_depth size
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_stack;  // does this region contain a thread's stack:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    // a user of MemoryRegionMap supplies this info
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Convenience accessor for call_stack[0],
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // i.e. (the program counter of) the immediate caller
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // of this region's allocation function,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // but it also returns NULL when call_stack_depth is 0,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // i.e whe we weren't able to get the call stack.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This usually happens in recursive calls, when the stack-unwinder
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // calls mmap() which in turn calls the stack-unwinder.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uintptr_t caller() const {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return reinterpret_cast<uintptr_t>(call_stack_depth >= 1
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         ? call_stack[0] : NULL);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Return true iff this region overlaps region x.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool Overlaps(const Region& x) const {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return start_addr < x.end_addr  &&  end_addr > x.start_addr;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:  // helpers for MemoryRegionMap
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    friend class MemoryRegionMap;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ways we create Region-s:
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void Create(const void* start, size_t size) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_addr = reinterpret_cast<uintptr_t>(start);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      end_addr = start_addr + size;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_stack = false;  // not a stack till marked such
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      call_stack_depth = 0;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AssertIsConsistent();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_call_stack_depth(int depth) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RAW_DCHECK(call_stack_depth == 0, "");  // only one such set is allowed
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      call_stack_depth = depth;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AssertIsConsistent();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ways we modify Region-s:
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_is_stack() { is_stack = true; }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_start_addr(uintptr_t addr) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_addr = addr;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AssertIsConsistent();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_end_addr(uintptr_t addr) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      end_addr = addr;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AssertIsConsistent();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verifies that *this contains consistent data, crashes if not the case.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void AssertIsConsistent() const {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RAW_DCHECK(start_addr < end_addr, "");
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RAW_DCHECK(call_stack_depth >= 0  &&
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 call_stack_depth <= kMaxStackDepth, "");
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Post-default construction helper to make a Region suitable
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for searching in RegionSet regions_.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void SetRegionSetKey(uintptr_t addr) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // make sure *this has no usable data:
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (DEBUG_MODE) memset(this, 0xFF, sizeof(*this));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      end_addr = addr;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: call_stack[kMaxStackDepth] as a member lets us make Region
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a simple self-contained struct with correctly behaving bit-vise copying.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This simplifies the code of this module but wastes some memory:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in most-often use case of this module (leak checking)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only one call_stack element out of kMaxStackDepth is actually needed.
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Making the storage for call_stack variable-sized,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // substantially complicates memory management for the Region-s:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // as they need to be created and manipulated for some time
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // w/o any memory allocations, yet are also given out to the users.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the region that covers addr and write its data into *result if found,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in which case *result gets filled so that it stays fully functional
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // even when the underlying region gets removed from MemoryRegionMap.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns success. Uses Lock/Unlock inside.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool FindRegion(uintptr_t addr, Region* result);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the region that contains stack_top, mark that region as
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a stack region, and write its data into *result if found,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in which case *result gets filled so that it stays fully functional
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // even when the underlying region gets removed from MemoryRegionMap.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns success. Uses Lock/Unlock inside.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool FindAndMarkStackRegion(uintptr_t stack_top, Region* result);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Iterate over the buckets which store mmap and munmap counts per stack
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // trace.  It calls "callback" for each bucket, and passes "arg" to it.
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  template<class Type>
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void IterateBuckets(void (*callback)(const HeapProfileBucket*, Type),
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             Type arg);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get the bucket whose caller stack trace is "key".  The stack trace is
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // used to a depth of "depth" at most.  The requested bucket is created if
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // needed.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The bucket table is described in heap-profile-stats.h.
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static HeapProfileBucket* GetBucket(int depth, const void* const key[]);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:  // our internal types ==============================================
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Region comparator for sorting with STL
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct RegionCmp {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool operator()(const Region& x, const Region& y) const {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return x.end_addr < y.end_addr;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We allocate STL objects in our own arena.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct MyAllocator {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static void *Allocate(size_t n) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return LowLevelAlloc::AllocWithArena(n, arena_);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static void Free(const void *p, size_t /* n */) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LowLevelAlloc::Free(const_cast<void*>(p));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set of the memory regions
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::set<Region, RegionCmp,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              STL_Allocator<Region, MyAllocator> > RegionSet;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:  // more in-depth interface ==========================================
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // STL iterator with values of Region
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef RegionSet::const_iterator RegionIterator;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return the begin/end iterators to all the regions.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These need Lock/Unlock protection around their whole usage (loop).
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Even when the same thread causes modifications during such a loop
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (which are permitted due to recursive locking)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the loop iterator will still be valid as long as its region
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has not been deleted, but EndRegionLocked should be
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // re-evaluated whenever the set of regions has changed.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static RegionIterator BeginRegionLocked();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static RegionIterator EndRegionLocked();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return the accumulated sizes of mapped and unmapped regions.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int64 MapSize() { return map_size_; }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int64 UnmapSize() { return unmap_size_; }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Effectively private type from our .cc =================================
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // public to let us declare global objects:
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  union RegionSetRep;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // representation ===========================================================
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Counter of clients of this module that have called Init().
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int client_count_;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Maximal number of caller stack frames to save (>= 0).
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int max_stack_depth_;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Arena used for our allocations in regions_.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LowLevelAlloc::Arena* arena_;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set of the mmap/sbrk/mremap-ed memory regions
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To be accessed *only* when Lock() is held.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hence we protect the non-recursive lock used inside of arena_
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with our recursive Lock(). This lets a user prevent deadlocks
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when threads are stopped by ListAllProcessThreads at random spots
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // simply by acquiring our recursive Lock() before that.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static RegionSet* regions_;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Lock to protect regions_ and buckets_ variables and the data behind.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SpinLock lock_;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lock to protect the recursive lock itself.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SpinLock owner_lock_;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Recursion count for the recursive lock.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int recursion_count_;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The thread id of the thread that's inside the recursive lock.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static pthread_t lock_owner_tid_;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Total size of all mapped pages so far
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int64 map_size_;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Total size of all unmapped pages so far
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int64 unmap_size_;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Bucket hash table which is described in heap-profile-stats.h.
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static HeapProfileBucket** bucket_table_ GUARDED_BY(lock_);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static int num_buckets_ GUARDED_BY(lock_);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The following members are local to MemoryRegionMap::GetBucket()
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and MemoryRegionMap::HandleSavedBucketsLocked()
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and are file-level to ensure that they are initialized at load time.
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // These are used as temporary storage to break the infinite cycle of mmap
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // calling our hook which (sometimes) causes mmap.  It must be a static
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // fixed-size array.  The size 20 is just an expected value for safety.
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The details are described in memory_region_map.cc.
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Number of unprocessed bucket inserts.
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static int saved_buckets_count_ GUARDED_BY(lock_);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Unprocessed inserts (must be big enough to hold all mmaps that can be
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // caused by a GetBucket call).
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Bucket has no constructor, so that c-tor execution does not interfere
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // with the any-time use of the static memory behind saved_buckets.
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static HeapProfileBucket saved_buckets_[20] GUARDED_BY(lock_);
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const void* saved_buckets_keys_[20][kMaxStackDepth] GUARDED_BY(lock_);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // helpers ==================================================================
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for FindRegion and FindAndMarkStackRegion:
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returns the region covering 'addr' or NULL; assumes our lock_ is held.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const Region* DoFindRegionLocked(uintptr_t addr);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verifying wrapper around regions_->insert(region)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To be called to do InsertRegionLocked's work only!
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline static void DoInsertRegionLocked(const Region& region);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle regions saved by InsertRegionLocked into a tmp static array
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by calling insert_func on them.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline static void HandleSavedRegionsLocked(
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       void (*insert_func)(const Region& region));
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Restore buckets saved in a tmp static array by GetBucket to the bucket
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // table where all buckets eventually should be.
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void RestoreSavedBucketsLocked();
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
364b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Initialize RegionSet regions_.
365b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  inline static void InitRegionSetLocked();
366b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrapper around DoInsertRegionLocked
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that handles the case of recursive allocator calls.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline static void InsertRegionLocked(const Region& region);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record addition of a memory region at address "start" of size "size"
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (called from our mmap/mremap/sbrk hooks).
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void RecordRegionAddition(const void* start, size_t size);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record deletion of a memory region at address "start" of size "size"
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (called from our munmap/mremap/sbrk hooks).
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void RecordRegionRemoval(const void* start, size_t size);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Record deletion of a memory region of size "size" in a bucket whose
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // caller stack trace is "key".  The stack trace is used to a depth of
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // "depth" at most.
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void RecordRegionRemovalInBucket(int depth,
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const void* const key[],
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          size_t size);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hooks for MallocHook
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void MmapHook(const void* result,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const void* start, size_t size,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int prot, int flags,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int fd, off_t offset);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void MunmapHook(const void* ptr, size_t size);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void MremapHook(const void* result, const void* old_addr,
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         size_t old_size, size_t new_size, int flags,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const void* new_addr);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void SbrkHook(const void* result, ptrdiff_t increment);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Log all memory regions; Useful for debugging only.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Assumes Lock() is held
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void LogAllLocked();
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MemoryRegionMap);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <class Type>
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MemoryRegionMap::IterateBuckets(
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void (*callback)(const HeapProfileBucket*, Type), Type callback_arg) {
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int index = 0; index < kHashTableSize; index++) {
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (HeapProfileBucket* bucket = bucket_table_[index];
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         bucket != NULL;
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         bucket = bucket->next) {
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback(bucket, callback_arg);
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_MEMORY_REGION_MAP_H_
416