1*349cc55cSDimitry Andric #include "memprof/memprof_rawprofile.h" 2*349cc55cSDimitry Andric 3*349cc55cSDimitry Andric #include "memprof/memprof_meminfoblock.h" 4*349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_common.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_stacktrace.h" 8*349cc55cSDimitry Andric #include "gmock/gmock.h" 9*349cc55cSDimitry Andric #include "gtest/gtest.h" 10*349cc55cSDimitry Andric 11*349cc55cSDimitry Andric #include <memory> 12*349cc55cSDimitry Andric 13*349cc55cSDimitry Andric namespace { 14*349cc55cSDimitry Andric 15*349cc55cSDimitry Andric using ::__memprof::MemInfoBlock; 16*349cc55cSDimitry Andric using ::__memprof::MIBMapTy; 17*349cc55cSDimitry Andric using ::__memprof::SerializeToRawProfile; 18*349cc55cSDimitry Andric using ::__sanitizer::MemoryMappedSegment; 19*349cc55cSDimitry Andric using ::__sanitizer::MemoryMappingLayoutBase; 20*349cc55cSDimitry Andric using ::__sanitizer::StackDepotPut; 21*349cc55cSDimitry Andric using ::__sanitizer::StackTrace; 22*349cc55cSDimitry Andric using ::testing::_; 23*349cc55cSDimitry Andric using ::testing::Action; 24*349cc55cSDimitry Andric using ::testing::DoAll; 25*349cc55cSDimitry Andric using ::testing::Return; 26*349cc55cSDimitry Andric using ::testing::SetArgPointee; 27*349cc55cSDimitry Andric 28*349cc55cSDimitry Andric class MockMemoryMappingLayout final : public MemoryMappingLayoutBase { 29*349cc55cSDimitry Andric public: 30*349cc55cSDimitry Andric MOCK_METHOD(bool, Next, (MemoryMappedSegment *), (override)); 31*349cc55cSDimitry Andric MOCK_METHOD(void, Reset, (), (override)); 32*349cc55cSDimitry Andric }; 33*349cc55cSDimitry Andric 34*349cc55cSDimitry Andric u64 PopulateFakeMap(const MemInfoBlock &FakeMIB, uptr StackPCBegin, 35*349cc55cSDimitry Andric MIBMapTy &FakeMap) { 36*349cc55cSDimitry Andric constexpr int kSize = 5; 37*349cc55cSDimitry Andric uptr array[kSize]; 38*349cc55cSDimitry Andric for (int i = 0; i < kSize; i++) { 39*349cc55cSDimitry Andric array[i] = StackPCBegin + i; 40*349cc55cSDimitry Andric } 41*349cc55cSDimitry Andric StackTrace St(array, kSize); 42*349cc55cSDimitry Andric u32 Id = StackDepotPut(St); 43*349cc55cSDimitry Andric 44*349cc55cSDimitry Andric InsertOrMerge(Id, FakeMIB, FakeMap); 45*349cc55cSDimitry Andric return Id; 46*349cc55cSDimitry Andric } 47*349cc55cSDimitry Andric 48*349cc55cSDimitry Andric template <class T = u64> T Read(char *&Buffer) { 49*349cc55cSDimitry Andric static_assert(std::is_pod<T>::value, "Must be a POD type."); 50*349cc55cSDimitry Andric T t = *reinterpret_cast<T *>(Buffer); 51*349cc55cSDimitry Andric Buffer += sizeof(T); 52*349cc55cSDimitry Andric return t; 53*349cc55cSDimitry Andric } 54*349cc55cSDimitry Andric 55*349cc55cSDimitry Andric TEST(MemProf, Basic) { 56*349cc55cSDimitry Andric MockMemoryMappingLayout Layout; 57*349cc55cSDimitry Andric MemoryMappedSegment FakeSegment; 58*349cc55cSDimitry Andric memset(&FakeSegment, 0, sizeof(FakeSegment)); 59*349cc55cSDimitry Andric FakeSegment.start = 0x10; 60*349cc55cSDimitry Andric FakeSegment.end = 0x20; 61*349cc55cSDimitry Andric FakeSegment.offset = 0x10; 62*349cc55cSDimitry Andric uint8_t uuid[__sanitizer::kModuleUUIDSize] = {0xC, 0x0, 0xF, 0xF, 0xE, 0xE}; 63*349cc55cSDimitry Andric memcpy(FakeSegment.uuid, uuid, __sanitizer::kModuleUUIDSize); 64*349cc55cSDimitry Andric FakeSegment.protection = 65*349cc55cSDimitry Andric __sanitizer::kProtectionExecute | __sanitizer::kProtectionRead; 66*349cc55cSDimitry Andric 67*349cc55cSDimitry Andric const Action<bool(MemoryMappedSegment *)> SetSegment = 68*349cc55cSDimitry Andric DoAll(SetArgPointee<0>(FakeSegment), Return(true)); 69*349cc55cSDimitry Andric EXPECT_CALL(Layout, Next(_)) 70*349cc55cSDimitry Andric .WillOnce(SetSegment) 71*349cc55cSDimitry Andric .WillOnce(Return(false)) 72*349cc55cSDimitry Andric .WillOnce(SetSegment) 73*349cc55cSDimitry Andric .WillRepeatedly(Return(false)); 74*349cc55cSDimitry Andric 75*349cc55cSDimitry Andric EXPECT_CALL(Layout, Reset).Times(2); 76*349cc55cSDimitry Andric 77*349cc55cSDimitry Andric MIBMapTy FakeMap; 78*349cc55cSDimitry Andric MemInfoBlock FakeMIB; 79*349cc55cSDimitry Andric // Since we want to override the constructor set vals to make it easier to 80*349cc55cSDimitry Andric // test. 81*349cc55cSDimitry Andric memset(&FakeMIB, 0, sizeof(MemInfoBlock)); 82*349cc55cSDimitry Andric FakeMIB.alloc_count = 0x1; 83*349cc55cSDimitry Andric FakeMIB.total_access_count = 0x2; 84*349cc55cSDimitry Andric 85*349cc55cSDimitry Andric u64 FakeIds[2]; 86*349cc55cSDimitry Andric FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap); 87*349cc55cSDimitry Andric FakeIds[1] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/3, FakeMap); 88*349cc55cSDimitry Andric 89*349cc55cSDimitry Andric char *Ptr = nullptr; 90*349cc55cSDimitry Andric u64 NumBytes = SerializeToRawProfile(FakeMap, Layout, Ptr); 91*349cc55cSDimitry Andric const char *Buffer = Ptr; 92*349cc55cSDimitry Andric 93*349cc55cSDimitry Andric ASSERT_GT(NumBytes, 0ULL); 94*349cc55cSDimitry Andric ASSERT_TRUE(Ptr); 95*349cc55cSDimitry Andric 96*349cc55cSDimitry Andric // Check the header. 97*349cc55cSDimitry Andric EXPECT_THAT(Read(Ptr), MEMPROF_RAW_MAGIC_64); 98*349cc55cSDimitry Andric EXPECT_THAT(Read(Ptr), MEMPROF_RAW_VERSION); 99*349cc55cSDimitry Andric const u64 TotalSize = Read(Ptr); 100*349cc55cSDimitry Andric const u64 SegmentOffset = Read(Ptr); 101*349cc55cSDimitry Andric const u64 MIBOffset = Read(Ptr); 102*349cc55cSDimitry Andric const u64 StackOffset = Read(Ptr); 103*349cc55cSDimitry Andric 104*349cc55cSDimitry Andric // ============= Check sizes. 105*349cc55cSDimitry Andric EXPECT_EQ(TotalSize, NumBytes); 106*349cc55cSDimitry Andric 107*349cc55cSDimitry Andric // Should be equal to the size of the raw profile header. 108*349cc55cSDimitry Andric EXPECT_EQ(SegmentOffset, 48ULL); 109*349cc55cSDimitry Andric 110*349cc55cSDimitry Andric // We expect only 1 segment entry, 8b for the count and 56b for SegmentEntry 111*349cc55cSDimitry Andric // in memprof_rawprofile.cpp. 112*349cc55cSDimitry Andric EXPECT_EQ(MIBOffset - SegmentOffset, 64ULL); 113*349cc55cSDimitry Andric 114*349cc55cSDimitry Andric EXPECT_EQ(MIBOffset, 112ULL); 115*349cc55cSDimitry Andric // We expect 2 mib entry, 8b for the count and sizeof(u64) + 116*349cc55cSDimitry Andric // sizeof(MemInfoBlock) contains stack id + MeminfoBlock. 117*349cc55cSDimitry Andric EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock))); 118*349cc55cSDimitry Andric 119*349cc55cSDimitry Andric EXPECT_EQ(StackOffset, 336ULL); 120*349cc55cSDimitry Andric // We expect 2 stack entries, with 5 frames - 8b for total count, 121*349cc55cSDimitry Andric // 2 * (8b for id, 8b for frame count and 5*8b for fake frames) 122*349cc55cSDimitry Andric EXPECT_EQ(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8)); 123*349cc55cSDimitry Andric 124*349cc55cSDimitry Andric // ============= Check contents. 125*349cc55cSDimitry Andric unsigned char ExpectedSegmentBytes[64] = { 126*349cc55cSDimitry Andric 0x01, 0, 0, 0, 0, 0, 0, 0, // Number of entries 127*349cc55cSDimitry Andric 0x10, 0, 0, 0, 0, 0, 0, 0, // Start 128*349cc55cSDimitry Andric 0x20, 0, 0, 0, 0, 0, 0, 0, // End 129*349cc55cSDimitry Andric 0x10, 0, 0, 0, 0, 0, 0, 0, // Offset 130*349cc55cSDimitry Andric 0x0C, 0x0, 0xF, 0xF, 0xE, 0xE, // Uuid 131*349cc55cSDimitry Andric }; 132*349cc55cSDimitry Andric EXPECT_EQ(memcmp(Buffer + SegmentOffset, ExpectedSegmentBytes, 64), 0); 133*349cc55cSDimitry Andric 134*349cc55cSDimitry Andric // Check that the number of entries is 2. 135*349cc55cSDimitry Andric EXPECT_EQ(*reinterpret_cast<const u64 *>(Buffer + MIBOffset), 2ULL); 136*349cc55cSDimitry Andric // Check that stack id is set. 137*349cc55cSDimitry Andric EXPECT_EQ(*reinterpret_cast<const u64 *>(Buffer + MIBOffset + 8), FakeIds[0]); 138*349cc55cSDimitry Andric 139*349cc55cSDimitry Andric // Only check a few fields of the first MemInfoBlock. 140*349cc55cSDimitry Andric unsigned char ExpectedMIBBytes[sizeof(MemInfoBlock)] = { 141*349cc55cSDimitry Andric 0x01, 0, 0, 0, // Alloc count 142*349cc55cSDimitry Andric 0x02, 0, 0, 0, // Total access count 143*349cc55cSDimitry Andric }; 144*349cc55cSDimitry Andric // Compare contents of 1st MIB after skipping count and stack id. 145*349cc55cSDimitry Andric EXPECT_EQ( 146*349cc55cSDimitry Andric memcmp(Buffer + MIBOffset + 16, ExpectedMIBBytes, sizeof(MemInfoBlock)), 147*349cc55cSDimitry Andric 0); 148*349cc55cSDimitry Andric // Compare contents of 2nd MIB after skipping count and stack id for the first 149*349cc55cSDimitry Andric // and only the id for the second. 150*349cc55cSDimitry Andric EXPECT_EQ(memcmp(Buffer + MIBOffset + 16 + sizeof(MemInfoBlock) + 8, 151*349cc55cSDimitry Andric ExpectedMIBBytes, sizeof(MemInfoBlock)), 152*349cc55cSDimitry Andric 0); 153*349cc55cSDimitry Andric 154*349cc55cSDimitry Andric // Check that the number of entries is 2. 155*349cc55cSDimitry Andric EXPECT_EQ(*reinterpret_cast<const u64 *>(Buffer + StackOffset), 2ULL); 156*349cc55cSDimitry Andric // Check that the 1st stack id is set. 157*349cc55cSDimitry Andric EXPECT_EQ(*reinterpret_cast<const u64 *>(Buffer + StackOffset + 8), 158*349cc55cSDimitry Andric FakeIds[0]); 159*349cc55cSDimitry Andric // Contents are num pcs, value of each pc - 1. 160*349cc55cSDimitry Andric unsigned char ExpectedStackBytes[2][6 * 8] = { 161*349cc55cSDimitry Andric { 162*349cc55cSDimitry Andric 0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs 163*349cc55cSDimitry Andric 0x1, 0, 0, 0, 0, 0, 0, 0, // PC ... 164*349cc55cSDimitry Andric 0x2, 0, 0, 0, 0, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0, 165*349cc55cSDimitry Andric 0x4, 0, 0, 0, 0, 0, 0, 0, 0x5, 0, 0, 0, 0, 0, 0, 0, 166*349cc55cSDimitry Andric }, 167*349cc55cSDimitry Andric { 168*349cc55cSDimitry Andric 0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs 169*349cc55cSDimitry Andric 0x2, 0, 0, 0, 0, 0, 0, 0, // PC ... 170*349cc55cSDimitry Andric 0x3, 0, 0, 0, 0, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 171*349cc55cSDimitry Andric 0x5, 0, 0, 0, 0, 0, 0, 0, 0x6, 0, 0, 0, 0, 0, 0, 0, 172*349cc55cSDimitry Andric }, 173*349cc55cSDimitry Andric }; 174*349cc55cSDimitry Andric EXPECT_EQ(memcmp(Buffer + StackOffset + 16, ExpectedStackBytes[0], 175*349cc55cSDimitry Andric sizeof(ExpectedStackBytes[0])), 176*349cc55cSDimitry Andric 0); 177*349cc55cSDimitry Andric 178*349cc55cSDimitry Andric // Check that the 2nd stack id is set. 179*349cc55cSDimitry Andric EXPECT_EQ( 180*349cc55cSDimitry Andric *reinterpret_cast<const u64 *>(Buffer + StackOffset + 8 + 6 * 8 + 8), 181*349cc55cSDimitry Andric FakeIds[1]); 182*349cc55cSDimitry Andric 183*349cc55cSDimitry Andric EXPECT_EQ(memcmp(Buffer + StackOffset + 16 + 6 * 8 + 8, ExpectedStackBytes[1], 184*349cc55cSDimitry Andric sizeof(ExpectedStackBytes[1])), 185*349cc55cSDimitry Andric 0); 186*349cc55cSDimitry Andric } 187*349cc55cSDimitry Andric 188*349cc55cSDimitry Andric } // namespace 189