xref: /aosp_15_r20/external/compiler-rt/lib/esan/esan.cpp (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- esan.cpp ----------------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of EfficiencySanitizer, a family of performance tuners.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Main file (entry points) for the Esan run-time.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "esan.h"
16*7c3d14c8STreehugger Robot #include "esan_flags.h"
17*7c3d14c8STreehugger Robot #include "esan_interface_internal.h"
18*7c3d14c8STreehugger Robot #include "esan_shadow.h"
19*7c3d14c8STreehugger Robot #include "cache_frag.h"
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
21*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_flag_parser.h"
22*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_flags.h"
23*7c3d14c8STreehugger Robot #include "working_set.h"
24*7c3d14c8STreehugger Robot 
25*7c3d14c8STreehugger Robot // See comment below.
26*7c3d14c8STreehugger Robot extern "C" {
27*7c3d14c8STreehugger Robot extern void __cxa_atexit(void (*function)(void));
28*7c3d14c8STreehugger Robot }
29*7c3d14c8STreehugger Robot 
30*7c3d14c8STreehugger Robot namespace __esan {
31*7c3d14c8STreehugger Robot 
32*7c3d14c8STreehugger Robot bool EsanIsInitialized;
33*7c3d14c8STreehugger Robot bool EsanDuringInit;
34*7c3d14c8STreehugger Robot ShadowMapping Mapping;
35*7c3d14c8STreehugger Robot 
36*7c3d14c8STreehugger Robot // Different tools use different scales within the same shadow mapping scheme.
37*7c3d14c8STreehugger Robot // The scale used here must match that used by the compiler instrumentation.
38*7c3d14c8STreehugger Robot // This array is indexed by the ToolType enum.
39*7c3d14c8STreehugger Robot static const uptr ShadowScale[] = {
40*7c3d14c8STreehugger Robot   0, // ESAN_None.
41*7c3d14c8STreehugger Robot   2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2.
42*7c3d14c8STreehugger Robot   6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6.
43*7c3d14c8STreehugger Robot };
44*7c3d14c8STreehugger Robot 
45*7c3d14c8STreehugger Robot // We are combining multiple performance tuning tools under the umbrella of
46*7c3d14c8STreehugger Robot // one EfficiencySanitizer super-tool.  Most of our tools have very similar
47*7c3d14c8STreehugger Robot // memory access instrumentation, shadow memory mapping, libc interception,
48*7c3d14c8STreehugger Robot // etc., and there is typically more shared code than distinct code.
49*7c3d14c8STreehugger Robot //
50*7c3d14c8STreehugger Robot // We are not willing to dispatch on tool dynamically in our fastpath
51*7c3d14c8STreehugger Robot // instrumentation: thus, which tool to use is a static option selected
52*7c3d14c8STreehugger Robot // at compile time and passed to __esan_init().
53*7c3d14c8STreehugger Robot //
54*7c3d14c8STreehugger Robot // We are willing to pay the overhead of tool dispatch in the slowpath to more
55*7c3d14c8STreehugger Robot // easily share code.  We expect to only come here rarely.
56*7c3d14c8STreehugger Robot // If this becomes a performance hit, we can add separate interface
57*7c3d14c8STreehugger Robot // routines for each subtool (e.g., __esan_cache_frag_aligned_load_4).
58*7c3d14c8STreehugger Robot // But for libc interceptors, we'll have to do one of the following:
59*7c3d14c8STreehugger Robot // A) Add multiple-include support to sanitizer_common_interceptors.inc,
60*7c3d14c8STreehugger Robot //    instantiate it separately for each tool, and call the selected
61*7c3d14c8STreehugger Robot //    tool's intercept setup code.
62*7c3d14c8STreehugger Robot // B) Build separate static runtime libraries, one for each tool.
63*7c3d14c8STreehugger Robot // C) Completely split the tools into separate sanitizers.
64*7c3d14c8STreehugger Robot 
processRangeAccess(uptr PC,uptr Addr,int Size,bool IsWrite)65*7c3d14c8STreehugger Robot void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) {
66*7c3d14c8STreehugger Robot   VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC,
67*7c3d14c8STreehugger Robot           IsWrite ? 'w' : 'r', Addr, Size);
68*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
69*7c3d14c8STreehugger Robot     // TODO(bruening): add shadow mapping and update shadow bits here.
70*7c3d14c8STreehugger Robot     // We'll move this to cache_frag.cpp once we have something.
71*7c3d14c8STreehugger Robot   } else if (__esan_which_tool == ESAN_WorkingSet) {
72*7c3d14c8STreehugger Robot     processRangeAccessWorkingSet(PC, Addr, Size, IsWrite);
73*7c3d14c8STreehugger Robot   }
74*7c3d14c8STreehugger Robot }
75*7c3d14c8STreehugger Robot 
processSignal(int SigNum,void (* Handler)(int),void (** Result)(int))76*7c3d14c8STreehugger Robot bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)) {
77*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_WorkingSet)
78*7c3d14c8STreehugger Robot     return processWorkingSetSignal(SigNum, Handler, Result);
79*7c3d14c8STreehugger Robot   return true;
80*7c3d14c8STreehugger Robot }
81*7c3d14c8STreehugger Robot 
processSigaction(int SigNum,const void * Act,void * OldAct)82*7c3d14c8STreehugger Robot bool processSigaction(int SigNum, const void *Act, void *OldAct) {
83*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_WorkingSet)
84*7c3d14c8STreehugger Robot     return processWorkingSetSigaction(SigNum, Act, OldAct);
85*7c3d14c8STreehugger Robot   return true;
86*7c3d14c8STreehugger Robot }
87*7c3d14c8STreehugger Robot 
processSigprocmask(int How,void * Set,void * OldSet)88*7c3d14c8STreehugger Robot bool processSigprocmask(int How, void *Set, void *OldSet) {
89*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_WorkingSet)
90*7c3d14c8STreehugger Robot     return processWorkingSetSigprocmask(How, Set, OldSet);
91*7c3d14c8STreehugger Robot   return true;
92*7c3d14c8STreehugger Robot }
93*7c3d14c8STreehugger Robot 
94*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG
verifyShadowScheme()95*7c3d14c8STreehugger Robot static bool verifyShadowScheme() {
96*7c3d14c8STreehugger Robot   // Sanity checks for our shadow mapping scheme.
97*7c3d14c8STreehugger Robot   uptr AppStart, AppEnd;
98*7c3d14c8STreehugger Robot   if (Verbosity() >= 3) {
99*7c3d14c8STreehugger Robot     for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) {
100*7c3d14c8STreehugger Robot       VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd,
101*7c3d14c8STreehugger Robot               (AppEnd - AppStart) >> 30);
102*7c3d14c8STreehugger Robot     }
103*7c3d14c8STreehugger Robot   }
104*7c3d14c8STreehugger Robot   for (int Scale = 0; Scale < 8; ++Scale) {
105*7c3d14c8STreehugger Robot     Mapping.initialize(Scale);
106*7c3d14c8STreehugger Robot     if (Verbosity() >= 3) {
107*7c3d14c8STreehugger Robot       VPrintf(3, "\nChecking scale %d\n", Scale);
108*7c3d14c8STreehugger Robot       uptr ShadowStart, ShadowEnd;
109*7c3d14c8STreehugger Robot       for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
110*7c3d14c8STreehugger Robot         VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart,
111*7c3d14c8STreehugger Robot                 ShadowEnd, (ShadowEnd - ShadowStart) >> 30);
112*7c3d14c8STreehugger Robot       }
113*7c3d14c8STreehugger Robot       for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
114*7c3d14c8STreehugger Robot         VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i,
115*7c3d14c8STreehugger Robot                 appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1);
116*7c3d14c8STreehugger Robot       }
117*7c3d14c8STreehugger Robot     }
118*7c3d14c8STreehugger Robot     for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) {
119*7c3d14c8STreehugger Robot       DCHECK(isAppMem(AppStart));
120*7c3d14c8STreehugger Robot       DCHECK(!isAppMem(AppStart - 1));
121*7c3d14c8STreehugger Robot       DCHECK(isAppMem(AppEnd - 1));
122*7c3d14c8STreehugger Robot       DCHECK(!isAppMem(AppEnd));
123*7c3d14c8STreehugger Robot       DCHECK(!isShadowMem(AppStart));
124*7c3d14c8STreehugger Robot       DCHECK(!isShadowMem(AppEnd - 1));
125*7c3d14c8STreehugger Robot       DCHECK(isShadowMem(appToShadow(AppStart)));
126*7c3d14c8STreehugger Robot       DCHECK(isShadowMem(appToShadow(AppEnd - 1)));
127*7c3d14c8STreehugger Robot       // Double-shadow checks.
128*7c3d14c8STreehugger Robot       DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart))));
129*7c3d14c8STreehugger Robot       DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1))));
130*7c3d14c8STreehugger Robot     }
131*7c3d14c8STreehugger Robot     // Ensure no shadow regions overlap each other.
132*7c3d14c8STreehugger Robot     uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd;
133*7c3d14c8STreehugger Robot     for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) {
134*7c3d14c8STreehugger Robot       for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) {
135*7c3d14c8STreehugger Robot         DCHECK(i == j || ShadowAStart >= ShadowBEnd ||
136*7c3d14c8STreehugger Robot                ShadowAEnd <= ShadowBStart);
137*7c3d14c8STreehugger Robot       }
138*7c3d14c8STreehugger Robot     }
139*7c3d14c8STreehugger Robot   }
140*7c3d14c8STreehugger Robot   return true;
141*7c3d14c8STreehugger Robot }
142*7c3d14c8STreehugger Robot #endif
143*7c3d14c8STreehugger Robot 
initializeShadow()144*7c3d14c8STreehugger Robot static void initializeShadow() {
145*7c3d14c8STreehugger Robot   verifyAddressSpace();
146*7c3d14c8STreehugger Robot 
147*7c3d14c8STreehugger Robot   DCHECK(verifyShadowScheme());
148*7c3d14c8STreehugger Robot 
149*7c3d14c8STreehugger Robot   Mapping.initialize(ShadowScale[__esan_which_tool]);
150*7c3d14c8STreehugger Robot 
151*7c3d14c8STreehugger Robot   VPrintf(1, "Shadow scale=%d offset=%p\n", Mapping.Scale, Mapping.Offset);
152*7c3d14c8STreehugger Robot 
153*7c3d14c8STreehugger Robot   uptr ShadowStart, ShadowEnd;
154*7c3d14c8STreehugger Robot   for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
155*7c3d14c8STreehugger Robot     VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd,
156*7c3d14c8STreehugger Robot             (ShadowEnd - ShadowStart) >> 30);
157*7c3d14c8STreehugger Robot 
158*7c3d14c8STreehugger Robot     uptr Map;
159*7c3d14c8STreehugger Robot     if (__esan_which_tool == ESAN_WorkingSet) {
160*7c3d14c8STreehugger Robot       // We want to identify all shadow pages that are touched so we start
161*7c3d14c8STreehugger Robot       // out inaccessible.
162*7c3d14c8STreehugger Robot       Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd- ShadowStart,
163*7c3d14c8STreehugger Robot                                     "shadow");
164*7c3d14c8STreehugger Robot     } else {
165*7c3d14c8STreehugger Robot       Map = (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart,
166*7c3d14c8STreehugger Robot                                      "shadow");
167*7c3d14c8STreehugger Robot     }
168*7c3d14c8STreehugger Robot     if (Map != ShadowStart) {
169*7c3d14c8STreehugger Robot       Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n");
170*7c3d14c8STreehugger Robot       Die();
171*7c3d14c8STreehugger Robot     }
172*7c3d14c8STreehugger Robot 
173*7c3d14c8STreehugger Robot     if (common_flags()->no_huge_pages_for_shadow)
174*7c3d14c8STreehugger Robot       NoHugePagesInRegion(ShadowStart, ShadowEnd - ShadowStart);
175*7c3d14c8STreehugger Robot     if (common_flags()->use_madv_dontdump)
176*7c3d14c8STreehugger Robot       DontDumpShadowMemory(ShadowStart, ShadowEnd - ShadowStart);
177*7c3d14c8STreehugger Robot 
178*7c3d14c8STreehugger Robot     // TODO: Call MmapNoAccess() on in-between regions.
179*7c3d14c8STreehugger Robot   }
180*7c3d14c8STreehugger Robot }
181*7c3d14c8STreehugger Robot 
initializeLibrary(ToolType Tool)182*7c3d14c8STreehugger Robot void initializeLibrary(ToolType Tool) {
183*7c3d14c8STreehugger Robot   // We assume there is only one thread during init, but we need to
184*7c3d14c8STreehugger Robot   // guard against double-init when we're (re-)called from an
185*7c3d14c8STreehugger Robot   // early interceptor.
186*7c3d14c8STreehugger Robot   if (EsanIsInitialized || EsanDuringInit)
187*7c3d14c8STreehugger Robot     return;
188*7c3d14c8STreehugger Robot   EsanDuringInit = true;
189*7c3d14c8STreehugger Robot   CHECK(Tool == __esan_which_tool);
190*7c3d14c8STreehugger Robot   SanitizerToolName = "EfficiencySanitizer";
191*7c3d14c8STreehugger Robot   CacheBinaryName();
192*7c3d14c8STreehugger Robot   initializeFlags();
193*7c3d14c8STreehugger Robot 
194*7c3d14c8STreehugger Robot   // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only
195*7c3d14c8STreehugger Robot   // finalizes on an explicit exit call by the app.  To handle a normal
196*7c3d14c8STreehugger Robot   // exit we register an atexit handler.
197*7c3d14c8STreehugger Robot   ::__cxa_atexit((void (*)())finalizeLibrary);
198*7c3d14c8STreehugger Robot 
199*7c3d14c8STreehugger Robot   VPrintf(1, "in esan::%s\n", __FUNCTION__);
200*7c3d14c8STreehugger Robot   if (__esan_which_tool <= ESAN_None || __esan_which_tool >= ESAN_Max) {
201*7c3d14c8STreehugger Robot     Printf("ERROR: unknown tool %d requested\n", __esan_which_tool);
202*7c3d14c8STreehugger Robot     Die();
203*7c3d14c8STreehugger Robot   }
204*7c3d14c8STreehugger Robot 
205*7c3d14c8STreehugger Robot   initializeShadow();
206*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_WorkingSet)
207*7c3d14c8STreehugger Robot     initializeShadowWorkingSet();
208*7c3d14c8STreehugger Robot 
209*7c3d14c8STreehugger Robot   initializeInterceptors();
210*7c3d14c8STreehugger Robot 
211*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
212*7c3d14c8STreehugger Robot     initializeCacheFrag();
213*7c3d14c8STreehugger Robot   } else if (__esan_which_tool == ESAN_WorkingSet) {
214*7c3d14c8STreehugger Robot     initializeWorkingSet();
215*7c3d14c8STreehugger Robot   }
216*7c3d14c8STreehugger Robot 
217*7c3d14c8STreehugger Robot   EsanIsInitialized = true;
218*7c3d14c8STreehugger Robot   EsanDuringInit = false;
219*7c3d14c8STreehugger Robot }
220*7c3d14c8STreehugger Robot 
finalizeLibrary()221*7c3d14c8STreehugger Robot int finalizeLibrary() {
222*7c3d14c8STreehugger Robot   VPrintf(1, "in esan::%s\n", __FUNCTION__);
223*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
224*7c3d14c8STreehugger Robot     return finalizeCacheFrag();
225*7c3d14c8STreehugger Robot   } else if (__esan_which_tool == ESAN_WorkingSet) {
226*7c3d14c8STreehugger Robot     return finalizeWorkingSet();
227*7c3d14c8STreehugger Robot   }
228*7c3d14c8STreehugger Robot   return 0;
229*7c3d14c8STreehugger Robot }
230*7c3d14c8STreehugger Robot 
reportResults()231*7c3d14c8STreehugger Robot void reportResults() {
232*7c3d14c8STreehugger Robot   VPrintf(1, "in esan::%s\n", __FUNCTION__);
233*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
234*7c3d14c8STreehugger Robot     return reportCacheFrag();
235*7c3d14c8STreehugger Robot   } else if (__esan_which_tool == ESAN_WorkingSet) {
236*7c3d14c8STreehugger Robot     return reportWorkingSet();
237*7c3d14c8STreehugger Robot   }
238*7c3d14c8STreehugger Robot }
239*7c3d14c8STreehugger Robot 
processCompilationUnitInit(void * Ptr)240*7c3d14c8STreehugger Robot void processCompilationUnitInit(void *Ptr) {
241*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s\n", __FUNCTION__);
242*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
243*7c3d14c8STreehugger Robot     DCHECK(Ptr != nullptr);
244*7c3d14c8STreehugger Robot     processCacheFragCompilationUnitInit(Ptr);
245*7c3d14c8STreehugger Robot   } else {
246*7c3d14c8STreehugger Robot     DCHECK(Ptr == nullptr);
247*7c3d14c8STreehugger Robot   }
248*7c3d14c8STreehugger Robot }
249*7c3d14c8STreehugger Robot 
250*7c3d14c8STreehugger Robot // This is called when the containing module is unloaded.
251*7c3d14c8STreehugger Robot // For the main executable module, this is called after finalizeLibrary.
processCompilationUnitExit(void * Ptr)252*7c3d14c8STreehugger Robot void processCompilationUnitExit(void *Ptr) {
253*7c3d14c8STreehugger Robot   VPrintf(2, "in esan::%s\n", __FUNCTION__);
254*7c3d14c8STreehugger Robot   if (__esan_which_tool == ESAN_CacheFrag) {
255*7c3d14c8STreehugger Robot     DCHECK(Ptr != nullptr);
256*7c3d14c8STreehugger Robot     processCacheFragCompilationUnitExit(Ptr);
257*7c3d14c8STreehugger Robot   } else {
258*7c3d14c8STreehugger Robot     DCHECK(Ptr == nullptr);
259*7c3d14c8STreehugger Robot   }
260*7c3d14c8STreehugger Robot }
261*7c3d14c8STreehugger Robot 
262*7c3d14c8STreehugger Robot } // namespace __esan
263