summaryrefslogtreecommitdiffstats
path: root/memory/build/PHC.h
blob: 78820a5cf3f34ad1a32ad828ac410669c4a70fcd (plain)
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
/* -*- 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/Assertions.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);

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;
};

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

#endif /* PHC_h */