1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PHC_h
#define PHC_h
#include "mozilla/Maybe.h"
#include <stdint.h>
#include <stdlib.h>
#include "mozmemory_wrap.h"
namespace mozilla {
namespace phc {
// Note: a stack trace may have no frames due to a collection problem.
//
// Also note: a more compact stack trace representation could be achieved with
// some effort.
struct StackTrace {
public:
static const size_t kMaxFrames = 16;
// The number of PCs in the stack trace.
size_t mLength;
// The PCs in the stack trace. Only the first mLength are initialized.
const void* mPcs[kMaxFrames];
public:
StackTrace() : mLength(0) {}
};
// Info from PHC about an address in memory.
class AddrInfo {
public:
enum class Kind {
// The address is not in PHC-managed memory.
Unknown = 0,
// The address is within a PHC page that has never been allocated. A crash
// involving such an address is unlikely in practice, because it would
// require the crash to happen quite early.
NeverAllocatedPage = 1,
// The address is within a PHC page that is in use.
InUsePage = 2,
// The address is within a PHC page that has been allocated and then freed.
// A crash involving such an address most likely indicates a
// use-after-free. (A sufficiently wild write -- e.g. a large buffer
// overflow -- could also trigger it, but this is less likely.)
FreedPage = 3,
// The address is within a PHC guard page. A crash involving such an
// address most likely indicates a buffer overflow. (Again, a sufficiently
// wild write could unluckily trigger it, but this is less likely.)
GuardPage = 4,
};
// The page kind.
Kind mKind;
// The starting address of the allocation.
// - Unknown | NeverAllocatedPage: nullptr.
// - InUsePage | FreedPage: the address of the allocation within the page.
// - GuardPage: the mBaseAddr value from the preceding allocation page.
const void* mBaseAddr;
// The usable size, which could be bigger than the requested size.
// - Unknown | NeverAllocatePage: 0.
// - InUsePage | FreedPage: the usable size of the allocation within the page.
// - GuardPage: the mUsableSize value from the preceding allocation page.
size_t mUsableSize;
// The allocation stack.
// - Unknown | NeverAllocatedPage: Nothing.
// - InUsePage | FreedPage: Some.
// - GuardPage: the mAllocStack value from the preceding allocation page.
mozilla::Maybe<StackTrace> mAllocStack;
// The free stack.
// - Unknown | NeverAllocatedPage | InUsePage: Nothing.
// - FreedPage: Some.
// - GuardPage: the mFreeStack value from the preceding allocation page.
mozilla::Maybe<StackTrace> mFreeStack;
// True if PHC was locked and therefore we couldn't retrive some infomation.
bool mPhcWasLocked = false;
// Default to no PHC info.
AddrInfo() : mKind(Kind::Unknown), mBaseAddr(nullptr), mUsableSize(0) {}
};
// Global instance that is retrieved by the process generating the crash report
extern AddrInfo gAddrInfo;
// If this is a PHC-handled address, return true, and if an AddrInfo is
// provided, fill in all of its fields. Otherwise, return false and leave
// AddrInfo unchanged.
MOZ_JEMALLOC_API bool IsPHCAllocation(const void*, AddrInfo*);
// Disable PHC allocations on the current thread. Only useful for tests. Note
// that PHC deallocations will still occur as needed.
MOZ_JEMALLOC_API void DisablePHCOnCurrentThread();
// Re-enable PHC allocations on the current thread. Only useful for tests.
MOZ_JEMALLOC_API void ReenablePHCOnCurrentThread();
// Test whether PHC allocations are enabled on the current thread. Only
// useful for tests.
MOZ_JEMALLOC_API bool IsPHCEnabledOnCurrentThread();
// PHC has three different states:
// * Not compiled in
// * OnlyFree - The memory allocator is hooked but new allocations
// requests will be forwarded to mozjemalloc, free() will
// correctly free any PHC allocations and realloc() will
// "move" PHC allocations to mozjemalloc allocations.
// * Enabled - Full use.
enum PHCState {
OnlyFree,
Enabled,
};
MOZ_JEMALLOC_API void SetPHCState(PHCState aState);
// Set the maximum allowed memory usage of PHC, including fragmentation and
// metadata.
MOZ_JEMALLOC_API void SetPHCSize(size_t aNumPHCBytes);
MOZ_JEMALLOC_API void SetPHCProbabilities(int64_t aAvgDelayFirst,
int64_t aAvgDelayNormal,
int64_t aAvgDelayPageReuse);
struct MemoryUsage {
// The amount of memory used for PHC metadata, eg information about each
// allocation including stacks.
size_t mMetadataBytes = 0;
// The amount of memory lost due to rounding allocation sizes up to the
// nearest page. AKA internal fragmentation.
size_t mFragmentationBytes = 0;
// The amount of memory allocated from PHC.
size_t mAllocatedBytes = 0;
};
MOZ_JEMALLOC_API void PHCMemoryUsage(MemoryUsage& aMemoryUsage);
struct PHCStats {
size_t mSlotsAllocated = 0;
size_t mSlotsFreed = 0;
size_t mSlotsUnused = 0;
};
// Return PHC memory usage information by filling in the supplied structure.
MOZ_JEMALLOC_API void GetPHCStats(PHCStats& aStats);
} // namespace phc
} // namespace mozilla
// Initialise PHC (called from mozjemalloc's initialisation.
void phc_init();
#endif /* PHC_h */
|