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