Index: lib/esan/cache_frag.cpp =================================================================== --- lib/esan/cache_frag.cpp +++ lib/esan/cache_frag.cpp @@ -16,27 +16,68 @@ namespace __esan { -// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragType. +//===-- Struct field access counter runtime -------------------------------===// + // The tool-specific information per compilation unit (module). +// This should be kept consistent with LLVM's EfficiencySanitizer StructInfoTy. +struct StructInfoTy { + const char *StructName; + u32 NumOfFields; + u64 *Counters; + const char **TypeName; +}; + +// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragTy. struct CacheFragTy { ToolType WhichTool; const char *UnitName; + u32 NumOfStructs; + StructInfoTy *StructInfo; }; +static void printStructInfo(CacheFragTy *CacheFrag) { + // We print StructInfo for debugging purpose. + if ((uptr)Verbosity() >= 3) { + for (u32 i = 0; i < CacheFrag->NumOfStructs; ++i) { + StructInfoTy *Info = &CacheFrag->StructInfo[i]; + Printf(" %s:\t %u field(s)\n", Info->StructName, Info->NumOfFields); + if ((uptr)Verbosity() >= 4) { + for (u32 j = 0; j < Info->NumOfFields; ++j) { + Printf(" #%2u: count = %llu,\t type = %s\n", j, + Info->Counters[j], Info->TypeName[j]); + } + } + } + } +} + +static void registerStructInfo(CacheFragTy *CacheFrag) { + printStructInfo(CacheFrag); + // FIXME: add StructInfo registration code. +} + +static void unregisterStructInfo(CacheFragTy *CacheFrag) { + // FIXME: add StructInfo unregistration code. +} + //===-- Init/exit functions -----------------------------------------------===// void processCacheFragCompilationUnitInit(void *Ptr) { CacheFragTy *CacheFrag = (CacheFragTy *)Ptr; if (CacheFrag->WhichTool != WhichTool) return; - VPrintf(2, "in esan::%s: %s\n", __FUNCTION__, CacheFrag->UnitName); + VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", + __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumOfStructs); + registerStructInfo(CacheFrag); } void processCacheFragCompilationUnitExit(void *Ptr) { CacheFragTy *CacheFrag = (CacheFragTy *)Ptr; if (CacheFrag->WhichTool != WhichTool) return; - VPrintf(2, "in esan::%s: %s\n", __FUNCTION__, CacheFrag->UnitName); + VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", + __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumOfStructs); + unregisterStructInfo(CacheFrag); } void initializeCacheFrag() { Index: test/esan/TestCases/struct-simple.cpp =================================================================== --- test/esan/TestCases/struct-simple.cpp +++ test/esan/TestCases/struct-simple.cpp @@ -1,7 +1,7 @@ // RUN: %clang_esan_frag -O0 %s -DPART -c -o %t-part.o 2>&1 // RUN: %clang_esan_frag -O0 %s -DMAIN -c -o %t-main.o 2>&1 // RUN: %clang_esan_frag -O0 %t-part.o %t-main.o -o %t 2>&1 -// RUN: %env_esan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s +// RUN: %env_esan_opts=verbosity=3 %run %t 2>&1 | FileCheck %s // We generate two different object files from this file with different // macros, and then link them together. We do this to test how we handle @@ -13,32 +13,113 @@ void part(); } +// Same struct in both main and part. +struct S { + int s1; + int s2; +}; + //===-- compilation unit without main function ----------------------------===// #ifdef PART +struct A { + int x; + int y; +}; + +struct B { + float m; + double n; +}; + +union U { + float f; + double d; +}; + +// Different structs with the same name in main and part. +struct D { + int d1; + int d2; +}; + void part() { + struct A a; + struct B b; + union U u; + struct S s; + struct D d; + for (int i = 0; i < (1 << 11); i++) + a.x = 0; + a.y = 1; + b.m = 2.0; + for (int i = 0; i < (1 << 21); i++) + b.n = 3.0; + u.f = 0.0; + u.d = 1.0; + s.s1 = 0; + d.d1 = 0; } #endif // PART //===-- compilation unit with main function -------------------------------===// #ifdef MAIN +class C { +public: + struct { + int x; + int y; + } cs; + union { + float f; + double d; + } cu; + char c[10]; +}; + +// Different structs with the same name in main and part. +struct D { + int d1; + int d2; + int d3; +}; + int main(int argc, char **argv) { // CHECK: in esan::initializeLibrary // CHECK-NEXT: in esan::initializeCacheFrag // CHECK: in esan::processCompilationUnitInit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp + // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 4 class(es)/struct(s) + // CHECK-NEXT: struct.A#2#11#11: 2 field(s) + // CHECK-NEXT: struct.B#2#3#2: 2 field(s) + // CHECK-NEXT: struct.S#2#11#11: 2 field(s) + // CHECK-NEXT: struct.D#2#11#11: 2 field(s) // CHECK-NEXT: in esan::processCompilationUnitInit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp + // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 4 class(es)/struct(s) + // CHECK-NEXT: class.C#3#14#13#13: 3 field(s) + // CHECK-NEXT: struct.anon#2#11#11: 2 field(s) + // CHECK-NEXT: struct.S#2#11#11: 2 field(s) + // CHECK-NEXT: struct.D#3#11#11#11: 3 field(s) + struct C c[2]; + struct S s; + struct D d; + c[0].cs.x = 0; + c[1].cs.y = 1; + c[0].cu.f = 0.0; + c[1].cu.d = 1.0; + c[0].c[2] = 0; + s.s1 = 0; + d.d1 = 0; + d.d2 = 0; part(); return 0; // CHECK: in esan::finalizeLibrary // CHECK-NEXT: in esan::finalizeCacheFrag // CHECK-NEXT: {{.*}}EfficiencySanitizer is not finished: nothing yet to report // CHECK-NEXT: in esan::processCompilationUnitExit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp + // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 4 class(es)/struct(s) // CHECK-NEXT: in esan::processCompilationUnitExit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp + // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 4 class(es)/struct(s) } #endif // MAIN