1*0fca6ea1SDimitry Andric //===-- nsan_stats.cc -----------------------------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file is a part of NumericalStabilitySanitizer. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric // NumericalStabilitySanitizer statistics. 12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric #include "nsan/nsan_stats.h" 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 17*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 18*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 19*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h" 20*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h" 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric #include <assert.h> 23*0fca6ea1SDimitry Andric #include <stdio.h> 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric using namespace __sanitizer; 26*0fca6ea1SDimitry Andric using namespace __nsan; 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric Stats::Stats() { 29*0fca6ea1SDimitry Andric check_and_warnings.Initialize(0); 30*0fca6ea1SDimitry Andric TrackedLoads.Initialize(0); 31*0fca6ea1SDimitry Andric } 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric Stats::~Stats() { Printf("deleting nsan stats\n"); } 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric static uptr Key(CheckTypeT CheckType, u32 StackId) { 36*0fca6ea1SDimitry Andric return static_cast<uptr>(CheckType) + 37*0fca6ea1SDimitry Andric StackId * static_cast<uptr>(CheckTypeT::kMaxCheckType); 38*0fca6ea1SDimitry Andric } 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric template <typename MapT, typename VectorT, typename Fn> 41*0fca6ea1SDimitry Andric static void UpdateEntry(CheckTypeT check_ty, uptr pc, uptr bp, MapT *map, 42*0fca6ea1SDimitry Andric VectorT *vector, Mutex *mutex, Fn F) { 43*0fca6ea1SDimitry Andric BufferedStackTrace Stack; 44*0fca6ea1SDimitry Andric Stack.Unwind(pc, bp, nullptr, false); 45*0fca6ea1SDimitry Andric u32 stack_id = StackDepotPut(Stack); 46*0fca6ea1SDimitry Andric typename MapT::Handle Handle(map, Key(check_ty, stack_id)); 47*0fca6ea1SDimitry Andric Lock L(mutex); 48*0fca6ea1SDimitry Andric if (Handle.created()) { 49*0fca6ea1SDimitry Andric typename VectorT::value_type entry; 50*0fca6ea1SDimitry Andric entry.stack_id = stack_id; 51*0fca6ea1SDimitry Andric entry.check_ty = check_ty; 52*0fca6ea1SDimitry Andric F(entry); 53*0fca6ea1SDimitry Andric vector->push_back(entry); 54*0fca6ea1SDimitry Andric } else { 55*0fca6ea1SDimitry Andric auto &entry = (*vector)[*Handle]; 56*0fca6ea1SDimitry Andric F(entry); 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric } 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric void Stats::AddCheck(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) { 61*0fca6ea1SDimitry Andric UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings, 62*0fca6ea1SDimitry Andric &check_and_warning_mutex, 63*0fca6ea1SDimitry Andric [rel_err](CheckAndWarningsValue &entry) { 64*0fca6ea1SDimitry Andric ++entry.num_checks; 65*0fca6ea1SDimitry Andric if (rel_err > entry.max_relative_err) { 66*0fca6ea1SDimitry Andric entry.max_relative_err = rel_err; 67*0fca6ea1SDimitry Andric } 68*0fca6ea1SDimitry Andric }); 69*0fca6ea1SDimitry Andric } 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric void Stats::AddWarning(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) { 72*0fca6ea1SDimitry Andric UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings, 73*0fca6ea1SDimitry Andric &check_and_warning_mutex, 74*0fca6ea1SDimitry Andric [rel_err](CheckAndWarningsValue &entry) { 75*0fca6ea1SDimitry Andric ++entry.num_warnings; 76*0fca6ea1SDimitry Andric if (rel_err > entry.max_relative_err) { 77*0fca6ea1SDimitry Andric entry.max_relative_err = rel_err; 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric }); 80*0fca6ea1SDimitry Andric } 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric void Stats::AddInvalidLoadTrackingEvent(uptr pc, uptr bp) { 83*0fca6ea1SDimitry Andric UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads, 84*0fca6ea1SDimitry Andric &TrackedLoadsMutex, 85*0fca6ea1SDimitry Andric [](LoadTrackingValue &entry) { ++entry.num_invalid; }); 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric 88*0fca6ea1SDimitry Andric void Stats::AddUnknownLoadTrackingEvent(uptr pc, uptr bp) { 89*0fca6ea1SDimitry Andric UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads, 90*0fca6ea1SDimitry Andric &TrackedLoadsMutex, 91*0fca6ea1SDimitry Andric [](LoadTrackingValue &entry) { ++entry.num_unknown; }); 92*0fca6ea1SDimitry Andric } 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric static const char *CheckTypeDisplay(CheckTypeT CheckType) { 95*0fca6ea1SDimitry Andric switch (CheckType) { 96*0fca6ea1SDimitry Andric case CheckTypeT::kUnknown: 97*0fca6ea1SDimitry Andric return "unknown"; 98*0fca6ea1SDimitry Andric case CheckTypeT::kRet: 99*0fca6ea1SDimitry Andric return "return"; 100*0fca6ea1SDimitry Andric case CheckTypeT::kArg: 101*0fca6ea1SDimitry Andric return "argument"; 102*0fca6ea1SDimitry Andric case CheckTypeT::kLoad: 103*0fca6ea1SDimitry Andric return "load"; 104*0fca6ea1SDimitry Andric case CheckTypeT::kStore: 105*0fca6ea1SDimitry Andric return "store"; 106*0fca6ea1SDimitry Andric case CheckTypeT::kInsert: 107*0fca6ea1SDimitry Andric return "vector insert"; 108*0fca6ea1SDimitry Andric case CheckTypeT::kUser: 109*0fca6ea1SDimitry Andric return "user-initiated"; 110*0fca6ea1SDimitry Andric case CheckTypeT::kFcmp: 111*0fca6ea1SDimitry Andric return "fcmp"; 112*0fca6ea1SDimitry Andric case CheckTypeT::kMaxCheckType: 113*0fca6ea1SDimitry Andric return "[max]"; 114*0fca6ea1SDimitry Andric } 115*0fca6ea1SDimitry Andric assert(false && "unknown CheckType case"); 116*0fca6ea1SDimitry Andric return ""; 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric void Stats::Print() const { 120*0fca6ea1SDimitry Andric { 121*0fca6ea1SDimitry Andric Lock L(&check_and_warning_mutex); 122*0fca6ea1SDimitry Andric for (const auto &entry : check_and_warnings) { 123*0fca6ea1SDimitry Andric Printf("warned %llu times out of %llu %s checks ", entry.num_warnings, 124*0fca6ea1SDimitry Andric entry.num_checks, CheckTypeDisplay(entry.check_ty)); 125*0fca6ea1SDimitry Andric if (entry.num_warnings > 0) { 126*0fca6ea1SDimitry Andric char RelErrBuf[64]; 127*0fca6ea1SDimitry Andric snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%f", 128*0fca6ea1SDimitry Andric entry.max_relative_err * 100.0); 129*0fca6ea1SDimitry Andric Printf("(max relative error: %s%%) ", RelErrBuf); 130*0fca6ea1SDimitry Andric } 131*0fca6ea1SDimitry Andric Printf("at:\n"); 132*0fca6ea1SDimitry Andric StackDepotGet(entry.stack_id).Print(); 133*0fca6ea1SDimitry Andric } 134*0fca6ea1SDimitry Andric } 135*0fca6ea1SDimitry Andric 136*0fca6ea1SDimitry Andric { 137*0fca6ea1SDimitry Andric Lock L(&TrackedLoadsMutex); 138*0fca6ea1SDimitry Andric u64 TotalInvalidLoadTracking = 0; 139*0fca6ea1SDimitry Andric u64 TotalUnknownLoadTracking = 0; 140*0fca6ea1SDimitry Andric for (const auto &entry : TrackedLoads) { 141*0fca6ea1SDimitry Andric TotalInvalidLoadTracking += entry.num_invalid; 142*0fca6ea1SDimitry Andric TotalUnknownLoadTracking += entry.num_unknown; 143*0fca6ea1SDimitry Andric Printf("invalid/unknown type for %llu/%llu loads at:\n", 144*0fca6ea1SDimitry Andric entry.num_invalid, entry.num_unknown); 145*0fca6ea1SDimitry Andric StackDepotGet(entry.stack_id).Print(); 146*0fca6ea1SDimitry Andric } 147*0fca6ea1SDimitry Andric Printf( 148*0fca6ea1SDimitry Andric "There were %llu/%llu floating-point loads where the shadow type was " 149*0fca6ea1SDimitry Andric "invalid/unknown.\n", 150*0fca6ea1SDimitry Andric TotalInvalidLoadTracking, TotalUnknownLoadTracking); 151*0fca6ea1SDimitry Andric } 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric alignas(64) static char stats_placeholder[sizeof(Stats)]; 155*0fca6ea1SDimitry Andric Stats *__nsan::nsan_stats = nullptr; 156*0fca6ea1SDimitry Andric 157*0fca6ea1SDimitry Andric void __nsan::InitializeStats() { nsan_stats = new (stats_placeholder) Stats(); } 158