xref: /freebsd/contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===-- nsan_stats.h --------------------------------------------*- C++- *-===//
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 // NSan statistics. This class counts the number of checks per code location,
12*0fca6ea1SDimitry Andric // and is used to output statistics (typically when using
13*0fca6ea1SDimitry Andric // `disable_warnings=1,enable_check_stats=1,enable_warning_stats=1`).
14*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric #ifndef NSAN_STATS_H
17*0fca6ea1SDimitry Andric #define NSAN_STATS_H
18*0fca6ea1SDimitry Andric 
19*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_addrhashmap.h"
20*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
21*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_mutex.h"
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric namespace __nsan {
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric enum class CheckTypeT {
26*0fca6ea1SDimitry Andric   kUnknown = 0,
27*0fca6ea1SDimitry Andric   kRet,
28*0fca6ea1SDimitry Andric   kArg,
29*0fca6ea1SDimitry Andric   kLoad,
30*0fca6ea1SDimitry Andric   kStore,
31*0fca6ea1SDimitry Andric   kInsert,
32*0fca6ea1SDimitry Andric   kUser, // User initiated.
33*0fca6ea1SDimitry Andric   kFcmp,
34*0fca6ea1SDimitry Andric   kMaxCheckType,
35*0fca6ea1SDimitry Andric };
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric class Stats {
38*0fca6ea1SDimitry Andric public:
39*0fca6ea1SDimitry Andric   Stats();
40*0fca6ea1SDimitry Andric   ~Stats();
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric   // Signal that we checked the instruction at the given address.
43*0fca6ea1SDimitry Andric   void AddCheck(CheckTypeT check_ty, __sanitizer::uptr pc, __sanitizer::uptr bp,
44*0fca6ea1SDimitry Andric                 double rel_err);
45*0fca6ea1SDimitry Andric   // Signal that we warned for the instruction at the given address.
46*0fca6ea1SDimitry Andric   void AddWarning(CheckTypeT check_ty, __sanitizer::uptr pc,
47*0fca6ea1SDimitry Andric                   __sanitizer::uptr bp, double rel_err);
48*0fca6ea1SDimitry Andric 
49*0fca6ea1SDimitry Andric   // Signal that we detected a floating-point load where the shadow type was
50*0fca6ea1SDimitry Andric   // invalid.
51*0fca6ea1SDimitry Andric   void AddInvalidLoadTrackingEvent(__sanitizer::uptr pc, __sanitizer::uptr bp);
52*0fca6ea1SDimitry Andric   // Signal that we detected a floating-point load where the shadow type was
53*0fca6ea1SDimitry Andric   // unknown but the value was nonzero.
54*0fca6ea1SDimitry Andric   void AddUnknownLoadTrackingEvent(__sanitizer::uptr pc, __sanitizer::uptr bp);
55*0fca6ea1SDimitry Andric 
56*0fca6ea1SDimitry Andric   void Print() const;
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric private:
59*0fca6ea1SDimitry Andric   using IndexMap = __sanitizer::AddrHashMap<__sanitizer::uptr, 11>;
60*0fca6ea1SDimitry Andric 
61*0fca6ea1SDimitry Andric   struct CheckAndWarningsValue {
62*0fca6ea1SDimitry Andric     CheckTypeT check_ty;
63*0fca6ea1SDimitry Andric     __sanitizer::u32 stack_id = 0;
64*0fca6ea1SDimitry Andric     __sanitizer::u64 num_checks = 0;
65*0fca6ea1SDimitry Andric     __sanitizer::u64 num_warnings = 0;
66*0fca6ea1SDimitry Andric     // This is a bitcasted double. Doubles have the nice idea to be ordered as
67*0fca6ea1SDimitry Andric     // ints.
68*0fca6ea1SDimitry Andric     double max_relative_err = 0;
69*0fca6ea1SDimitry Andric   };
70*0fca6ea1SDimitry Andric   // Map Key(check_ty, StackId) to indices in CheckAndWarnings.
71*0fca6ea1SDimitry Andric   IndexMap CheckAndWarningsMap;
72*0fca6ea1SDimitry Andric   __sanitizer::InternalMmapVectorNoCtor<CheckAndWarningsValue>
73*0fca6ea1SDimitry Andric       check_and_warnings;
74*0fca6ea1SDimitry Andric   mutable __sanitizer::Mutex check_and_warning_mutex;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   struct LoadTrackingValue {
77*0fca6ea1SDimitry Andric     CheckTypeT check_ty;
78*0fca6ea1SDimitry Andric     __sanitizer::u32 stack_id = 0;
79*0fca6ea1SDimitry Andric     __sanitizer::u64 num_invalid = 0;
80*0fca6ea1SDimitry Andric     __sanitizer::u64 num_unknown = 0;
81*0fca6ea1SDimitry Andric   };
82*0fca6ea1SDimitry Andric   // Map Key(CheckTypeT::kLoad, StackId) to indices in TrackedLoads.
83*0fca6ea1SDimitry Andric   IndexMap LoadTrackingMap;
84*0fca6ea1SDimitry Andric   __sanitizer::InternalMmapVectorNoCtor<LoadTrackingValue> TrackedLoads;
85*0fca6ea1SDimitry Andric   mutable __sanitizer::Mutex TrackedLoadsMutex;
86*0fca6ea1SDimitry Andric };
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric extern Stats *nsan_stats;
89*0fca6ea1SDimitry Andric void InitializeStats();
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric } // namespace __nsan
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric #endif // NSAN_STATS_H
94