// Scan shadow memory to calculate the number of cache lines being accessed, // i.e., the number of non-zero bits indexed by BitIdx in each shadow byte. // We also clear the lowest bits (most recent working set snapshot). static u32 computeWorkingSizeAndReset(u32 BitIdx) { u32 WorkingSetSize = 0; MemoryMappingLayout MemIter(true/*cache*/); uptr Start, End, Prot; while (MemIter.Next(&Start, &End, nullptr/*offs*/, nullptr/*file*/, 0/*file size*/, &Prot)) { VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", __FUNCTION__, Start, End, Prot, isAppMem(Start), isShadowMem(Start)); if (isShadowMem(Start) && (Prot & MemoryMappingLayout::kProtectionWrite)) { VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Start, End); WorkingSetSize += countAndClearShadowValues(BitIdx, Start, End); } } return WorkingSetSize; }
// If this is a shadow fault, we handle it here; otherwise, we pass it to the // app to handle it just as the app would do without our tool in place. static void handleMemoryFault(int SigNum, __sanitizer_siginfo *Info, void *Ctx) { if (SigNum == SIGSEGV) { // We rely on si_addr being filled in (thus we do not support old kernels). siginfo_t *SigInfo = (siginfo_t *)Info; uptr Addr = (uptr)SigInfo->si_addr; if (isShadowMem(Addr)) { VPrintf(3, "Shadow fault @%p\n", Addr); uptr PageSize = GetPageSizeCached(); int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize), PageSize, PROT_READ|PROT_WRITE); CHECK(Res == 0); } else if (AppSigAct.sigaction) { // FIXME: For simplicity we ignore app options including its signal stack // (we just use ours) and all the delivery flags. AppSigAct.sigaction(SigNum, Info, Ctx); } else { // Crash instead of spinning with infinite faults. reinstateDefaultHandler(SigNum); } } else UNREACHABLE("signal not registered"); }
static bool verifyShadowScheme() { // Sanity checks for our shadow mapping scheme. uptr AppStart, AppEnd; if (Verbosity() >= 3) { for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd, (AppEnd - AppStart) >> 30); } } for (int Scale = 0; Scale < 8; ++Scale) { Mapping.initialize(Scale); if (Verbosity() >= 3) { VPrintf(3, "\nChecking scale %d\n", Scale); uptr ShadowStart, ShadowEnd; for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd, (ShadowEnd - ShadowStart) >> 30); } for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i, appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1); } } for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { DCHECK(isAppMem(AppStart)); DCHECK(!isAppMem(AppStart - 1)); DCHECK(isAppMem(AppEnd - 1)); DCHECK(!isAppMem(AppEnd)); DCHECK(!isShadowMem(AppStart)); DCHECK(!isShadowMem(AppEnd - 1)); DCHECK(isShadowMem(appToShadow(AppStart))); DCHECK(isShadowMem(appToShadow(AppEnd - 1))); // Double-shadow checks. DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart)))); DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1)))); } // Ensure no shadow regions overlap each other. uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd; for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) { for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) { DCHECK(i == j || ShadowAStart >= ShadowBEnd || ShadowAEnd <= ShadowBStart); } } }