1*810390e3Srobert #include <stdint.h>
2*810390e3Srobert #include <stdlib.h>
3*810390e3Srobert #include <string.h>
4*810390e3Srobert
5*810390e3Srobert #include "memprof_rawprofile.h"
6*810390e3Srobert #include "profile/MemProfData.inc"
7*810390e3Srobert #include "sanitizer_common/sanitizer_allocator_internal.h"
8*810390e3Srobert #include "sanitizer_common/sanitizer_common.h"
9*810390e3Srobert #include "sanitizer_common/sanitizer_linux.h"
10*810390e3Srobert #include "sanitizer_common/sanitizer_procmaps.h"
11*810390e3Srobert #include "sanitizer_common/sanitizer_stackdepot.h"
12*810390e3Srobert #include "sanitizer_common/sanitizer_stackdepotbase.h"
13*810390e3Srobert #include "sanitizer_common/sanitizer_stacktrace.h"
14*810390e3Srobert #include "sanitizer_common/sanitizer_vector.h"
15*810390e3Srobert
16*810390e3Srobert namespace __memprof {
17*810390e3Srobert using ::__sanitizer::Vector;
18*810390e3Srobert using ::llvm::memprof::MemInfoBlock;
19*810390e3Srobert using SegmentEntry = ::llvm::memprof::SegmentEntry;
20*810390e3Srobert using Header = ::llvm::memprof::Header;
21*810390e3Srobert
22*810390e3Srobert namespace {
WriteBytes(T Pod,char * & Buffer)23*810390e3Srobert template <class T> char *WriteBytes(T Pod, char *&Buffer) {
24*810390e3Srobert *(T *)Buffer = Pod;
25*810390e3Srobert return Buffer + sizeof(T);
26*810390e3Srobert }
27*810390e3Srobert
RecordStackId(const uptr Key,UNUSED LockedMemInfoBlock * const & MIB,void * Arg)28*810390e3Srobert void RecordStackId(const uptr Key, UNUSED LockedMemInfoBlock *const &MIB,
29*810390e3Srobert void *Arg) {
30*810390e3Srobert // No need to touch the MIB value here since we are only recording the key.
31*810390e3Srobert auto *StackIds = reinterpret_cast<Vector<u64> *>(Arg);
32*810390e3Srobert StackIds->PushBack(Key);
33*810390e3Srobert }
34*810390e3Srobert } // namespace
35*810390e3Srobert
SegmentSizeBytes(MemoryMappingLayoutBase & Layout)36*810390e3Srobert u64 SegmentSizeBytes(MemoryMappingLayoutBase &Layout) {
37*810390e3Srobert u64 NumSegmentsToRecord = 0;
38*810390e3Srobert MemoryMappedSegment segment;
39*810390e3Srobert for (Layout.Reset(); Layout.Next(&segment);)
40*810390e3Srobert if (segment.IsReadable() && segment.IsExecutable())
41*810390e3Srobert NumSegmentsToRecord++;
42*810390e3Srobert
43*810390e3Srobert return sizeof(u64) // A header which stores the number of records.
44*810390e3Srobert + sizeof(SegmentEntry) * NumSegmentsToRecord;
45*810390e3Srobert }
46*810390e3Srobert
47*810390e3Srobert // The segment section uses the following format:
48*810390e3Srobert // ---------- Segment Info
49*810390e3Srobert // Num Entries
50*810390e3Srobert // ---------- Segment Entry
51*810390e3Srobert // Start
52*810390e3Srobert // End
53*810390e3Srobert // Offset
54*810390e3Srobert // BuildID 32B
55*810390e3Srobert // ----------
56*810390e3Srobert // ...
SerializeSegmentsToBuffer(MemoryMappingLayoutBase & Layout,const u64 ExpectedNumBytes,char * & Buffer)57*810390e3Srobert void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
58*810390e3Srobert const u64 ExpectedNumBytes, char *&Buffer) {
59*810390e3Srobert char *Ptr = Buffer;
60*810390e3Srobert // Reserve space for the final count.
61*810390e3Srobert Ptr += sizeof(u64);
62*810390e3Srobert
63*810390e3Srobert u64 NumSegmentsRecorded = 0;
64*810390e3Srobert MemoryMappedSegment segment;
65*810390e3Srobert
66*810390e3Srobert for (Layout.Reset(); Layout.Next(&segment);) {
67*810390e3Srobert if (segment.IsReadable() && segment.IsExecutable()) {
68*810390e3Srobert // TODO: Record segment.uuid when it is implemented for Linux-Elf.
69*810390e3Srobert SegmentEntry Entry(segment.start, segment.end, segment.offset);
70*810390e3Srobert memcpy(Ptr, &Entry, sizeof(SegmentEntry));
71*810390e3Srobert Ptr += sizeof(SegmentEntry);
72*810390e3Srobert NumSegmentsRecorded++;
73*810390e3Srobert }
74*810390e3Srobert }
75*810390e3Srobert
76*810390e3Srobert // Store the number of segments we recorded in the space we reserved.
77*810390e3Srobert *((u64 *)Buffer) = NumSegmentsRecorded;
78*810390e3Srobert CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
79*810390e3Srobert "Expected num bytes != actual bytes written");
80*810390e3Srobert }
81*810390e3Srobert
StackSizeBytes(const Vector<u64> & StackIds)82*810390e3Srobert u64 StackSizeBytes(const Vector<u64> &StackIds) {
83*810390e3Srobert u64 NumBytesToWrite = sizeof(u64);
84*810390e3Srobert
85*810390e3Srobert const u64 NumIds = StackIds.Size();
86*810390e3Srobert for (unsigned k = 0; k < NumIds; ++k) {
87*810390e3Srobert const u64 Id = StackIds[k];
88*810390e3Srobert // One entry for the id and then one more for the number of stack pcs.
89*810390e3Srobert NumBytesToWrite += 2 * sizeof(u64);
90*810390e3Srobert const StackTrace St = StackDepotGet(Id);
91*810390e3Srobert
92*810390e3Srobert CHECK(St.trace != nullptr && St.size > 0 && "Empty stack trace");
93*810390e3Srobert for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
94*810390e3Srobert NumBytesToWrite += sizeof(u64);
95*810390e3Srobert }
96*810390e3Srobert }
97*810390e3Srobert return NumBytesToWrite;
98*810390e3Srobert }
99*810390e3Srobert
100*810390e3Srobert // The stack info section uses the following format:
101*810390e3Srobert //
102*810390e3Srobert // ---------- Stack Info
103*810390e3Srobert // Num Entries
104*810390e3Srobert // ---------- Stack Entry
105*810390e3Srobert // Num Stacks
106*810390e3Srobert // PC1
107*810390e3Srobert // PC2
108*810390e3Srobert // ...
109*810390e3Srobert // ----------
SerializeStackToBuffer(const Vector<u64> & StackIds,const u64 ExpectedNumBytes,char * & Buffer)110*810390e3Srobert void SerializeStackToBuffer(const Vector<u64> &StackIds,
111*810390e3Srobert const u64 ExpectedNumBytes, char *&Buffer) {
112*810390e3Srobert const u64 NumIds = StackIds.Size();
113*810390e3Srobert char *Ptr = Buffer;
114*810390e3Srobert Ptr = WriteBytes(static_cast<u64>(NumIds), Ptr);
115*810390e3Srobert
116*810390e3Srobert for (unsigned k = 0; k < NumIds; ++k) {
117*810390e3Srobert const u64 Id = StackIds[k];
118*810390e3Srobert Ptr = WriteBytes(Id, Ptr);
119*810390e3Srobert Ptr += sizeof(u64); // Bump it by u64, we will fill this in later.
120*810390e3Srobert u64 Count = 0;
121*810390e3Srobert const StackTrace St = StackDepotGet(Id);
122*810390e3Srobert for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
123*810390e3Srobert // PCs in stack traces are actually the return addresses, that is,
124*810390e3Srobert // addresses of the next instructions after the call.
125*810390e3Srobert uptr pc = StackTrace::GetPreviousInstructionPc(St.trace[i]);
126*810390e3Srobert Ptr = WriteBytes(static_cast<u64>(pc), Ptr);
127*810390e3Srobert ++Count;
128*810390e3Srobert }
129*810390e3Srobert // Store the count in the space we reserved earlier.
130*810390e3Srobert *(u64 *)(Ptr - (Count + 1) * sizeof(u64)) = Count;
131*810390e3Srobert }
132*810390e3Srobert
133*810390e3Srobert CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
134*810390e3Srobert "Expected num bytes != actual bytes written");
135*810390e3Srobert }
136*810390e3Srobert
137*810390e3Srobert // The MIB section has the following format:
138*810390e3Srobert // ---------- MIB Info
139*810390e3Srobert // Num Entries
140*810390e3Srobert // ---------- MIB Entry 0
141*810390e3Srobert // Alloc Count
142*810390e3Srobert // ...
143*810390e3Srobert // ---------- MIB Entry 1
144*810390e3Srobert // Alloc Count
145*810390e3Srobert // ...
146*810390e3Srobert // ----------
SerializeMIBInfoToBuffer(MIBMapTy & MIBMap,const Vector<u64> & StackIds,const u64 ExpectedNumBytes,char * & Buffer)147*810390e3Srobert void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
148*810390e3Srobert const u64 ExpectedNumBytes, char *&Buffer) {
149*810390e3Srobert char *Ptr = Buffer;
150*810390e3Srobert const u64 NumEntries = StackIds.Size();
151*810390e3Srobert Ptr = WriteBytes(NumEntries, Ptr);
152*810390e3Srobert
153*810390e3Srobert for (u64 i = 0; i < NumEntries; i++) {
154*810390e3Srobert const u64 Key = StackIds[i];
155*810390e3Srobert MIBMapTy::Handle h(&MIBMap, Key, /*remove=*/true, /*create=*/false);
156*810390e3Srobert CHECK(h.exists());
157*810390e3Srobert Ptr = WriteBytes(Key, Ptr);
158*810390e3Srobert Ptr = WriteBytes((*h)->mib, Ptr);
159*810390e3Srobert }
160*810390e3Srobert
161*810390e3Srobert CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
162*810390e3Srobert "Expected num bytes != actual bytes written");
163*810390e3Srobert }
164*810390e3Srobert
165*810390e3Srobert // Format
166*810390e3Srobert // ---------- Header
167*810390e3Srobert // Magic
168*810390e3Srobert // Version
169*810390e3Srobert // Total Size
170*810390e3Srobert // Segment Offset
171*810390e3Srobert // MIB Info Offset
172*810390e3Srobert // Stack Offset
173*810390e3Srobert // ---------- Segment Info
174*810390e3Srobert // Num Entries
175*810390e3Srobert // ---------- Segment Entry
176*810390e3Srobert // Start
177*810390e3Srobert // End
178*810390e3Srobert // Offset
179*810390e3Srobert // BuildID 32B
180*810390e3Srobert // ----------
181*810390e3Srobert // ...
182*810390e3Srobert // ----------
183*810390e3Srobert // Optional Padding Bytes
184*810390e3Srobert // ---------- MIB Info
185*810390e3Srobert // Num Entries
186*810390e3Srobert // ---------- MIB Entry
187*810390e3Srobert // Alloc Count
188*810390e3Srobert // ...
189*810390e3Srobert // ----------
190*810390e3Srobert // Optional Padding Bytes
191*810390e3Srobert // ---------- Stack Info
192*810390e3Srobert // Num Entries
193*810390e3Srobert // ---------- Stack Entry
194*810390e3Srobert // Num Stacks
195*810390e3Srobert // PC1
196*810390e3Srobert // PC2
197*810390e3Srobert // ...
198*810390e3Srobert // ----------
199*810390e3Srobert // Optional Padding Bytes
200*810390e3Srobert // ...
SerializeToRawProfile(MIBMapTy & MIBMap,MemoryMappingLayoutBase & Layout,char * & Buffer)201*810390e3Srobert u64 SerializeToRawProfile(MIBMapTy &MIBMap, MemoryMappingLayoutBase &Layout,
202*810390e3Srobert char *&Buffer) {
203*810390e3Srobert // Each section size is rounded up to 8b since the first entry in each section
204*810390e3Srobert // is a u64 which holds the number of entries in the section by convention.
205*810390e3Srobert const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Layout), 8);
206*810390e3Srobert
207*810390e3Srobert Vector<u64> StackIds;
208*810390e3Srobert MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
209*810390e3Srobert // The first 8b are for the total number of MIB records. Each MIB record is
210*810390e3Srobert // preceded by a 8b stack id which is associated with stack frames in the next
211*810390e3Srobert // section.
212*810390e3Srobert const u64 NumMIBInfoBytes = RoundUpTo(
213*810390e3Srobert sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8);
214*810390e3Srobert
215*810390e3Srobert const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
216*810390e3Srobert
217*810390e3Srobert // Ensure that the profile is 8b aligned. We allow for some optional padding
218*810390e3Srobert // at the end so that any subsequent profile serialized to the same file does
219*810390e3Srobert // not incur unaligned accesses.
220*810390e3Srobert const u64 TotalSizeBytes = RoundUpTo(
221*810390e3Srobert sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8);
222*810390e3Srobert
223*810390e3Srobert // Allocate the memory for the entire buffer incl. info blocks.
224*810390e3Srobert Buffer = (char *)InternalAlloc(TotalSizeBytes);
225*810390e3Srobert char *Ptr = Buffer;
226*810390e3Srobert
227*810390e3Srobert Header header{MEMPROF_RAW_MAGIC_64,
228*810390e3Srobert MEMPROF_RAW_VERSION,
229*810390e3Srobert static_cast<u64>(TotalSizeBytes),
230*810390e3Srobert sizeof(Header),
231*810390e3Srobert sizeof(Header) + NumSegmentBytes,
232*810390e3Srobert sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes};
233*810390e3Srobert Ptr = WriteBytes(header, Ptr);
234*810390e3Srobert
235*810390e3Srobert SerializeSegmentsToBuffer(Layout, NumSegmentBytes, Ptr);
236*810390e3Srobert Ptr += NumSegmentBytes;
237*810390e3Srobert
238*810390e3Srobert SerializeMIBInfoToBuffer(MIBMap, StackIds, NumMIBInfoBytes, Ptr);
239*810390e3Srobert Ptr += NumMIBInfoBytes;
240*810390e3Srobert
241*810390e3Srobert SerializeStackToBuffer(StackIds, NumStackBytes, Ptr);
242*810390e3Srobert
243*810390e3Srobert return TotalSizeBytes;
244*810390e3Srobert }
245*810390e3Srobert
246*810390e3Srobert } // namespace __memprof
247