]>
Commit | Line | Data |
---|---|---|
5d3805fc JJ |
1 | //===-- sanitizer_coverage_libcdep_new.cc ---------------------------------===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // Sanitizer Coverage Controller for Trace PC Guard. | |
8 | ||
9 | #include "sanitizer_platform.h" | |
10 | ||
11 | #if !SANITIZER_FUCHSIA | |
12 | #include "sancov_flags.h" | |
13 | #include "sanitizer_allocator_internal.h" | |
14 | #include "sanitizer_atomic.h" | |
15 | #include "sanitizer_common.h" | |
16 | #include "sanitizer_file.h" | |
5d3805fc JJ |
17 | |
18 | using namespace __sanitizer; | |
19 | ||
20 | using AddressRange = LoadedModule::AddressRange; | |
21 | ||
22 | namespace __sancov { | |
23 | namespace { | |
24 | ||
25 | static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; | |
26 | static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; | |
27 | static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; | |
28 | ||
29 | static fd_t OpenFile(const char* path) { | |
30 | error_t err; | |
31 | fd_t fd = OpenFile(path, WrOnly, &err); | |
32 | if (fd == kInvalidFd) | |
33 | Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", | |
34 | path, err); | |
35 | return fd; | |
36 | } | |
37 | ||
38 | static void GetCoverageFilename(char* path, const char* name, | |
39 | const char* extension) { | |
40 | CHECK(name); | |
41 | internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", | |
42 | common_flags()->coverage_dir, name, internal_getpid(), | |
43 | extension); | |
44 | } | |
45 | ||
46 | static void WriteModuleCoverage(char* file_path, const char* module_name, | |
47 | const uptr* pcs, uptr len) { | |
48 | GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); | |
49 | fd_t fd = OpenFile(file_path); | |
50 | WriteToFile(fd, &Magic, sizeof(Magic)); | |
51 | WriteToFile(fd, pcs, len * sizeof(*pcs)); | |
52 | CloseFile(fd); | |
53 | Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); | |
54 | } | |
55 | ||
56 | static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { | |
57 | if (!len) return; | |
58 | ||
59 | char* file_path = static_cast<char*>(InternalAlloc(kMaxPathLength)); | |
60 | char* module_name = static_cast<char*>(InternalAlloc(kMaxPathLength)); | |
61 | uptr* pcs = static_cast<uptr*>(InternalAlloc(len * sizeof(uptr))); | |
62 | ||
63 | internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); | |
eac97531 | 64 | Sort(pcs, len); |
5d3805fc JJ |
65 | |
66 | bool module_found = false; | |
67 | uptr last_base = 0; | |
68 | uptr module_start_idx = 0; | |
69 | ||
70 | for (uptr i = 0; i < len; ++i) { | |
71 | const uptr pc = pcs[i]; | |
72 | if (!pc) continue; | |
73 | ||
74 | if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { | |
75 | Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc); | |
76 | continue; | |
77 | } | |
78 | uptr module_base = pc - pcs[i]; | |
79 | ||
80 | if (module_base != last_base || !module_found) { | |
81 | if (module_found) { | |
82 | WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], | |
83 | i - module_start_idx); | |
84 | } | |
85 | ||
86 | last_base = module_base; | |
87 | module_start_idx = i; | |
88 | module_found = true; | |
89 | __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength, | |
90 | &pcs[i]); | |
91 | } | |
92 | } | |
93 | ||
94 | if (module_found) { | |
95 | WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], | |
96 | len - module_start_idx); | |
97 | } | |
98 | ||
99 | InternalFree(file_path); | |
100 | InternalFree(module_name); | |
101 | InternalFree(pcs); | |
102 | } | |
103 | ||
104 | // Collects trace-pc guard coverage. | |
105 | // This class relies on zero-initialization. | |
106 | class TracePcGuardController { | |
107 | public: | |
108 | void Initialize() { | |
109 | CHECK(!initialized); | |
110 | ||
111 | initialized = true; | |
112 | InitializeSancovFlags(); | |
113 | ||
114 | pc_vector.Initialize(0); | |
115 | } | |
116 | ||
117 | void InitTracePcGuard(u32* start, u32* end) { | |
118 | if (!initialized) Initialize(); | |
119 | CHECK(!*start); | |
120 | CHECK_NE(start, end); | |
121 | ||
122 | u32 i = pc_vector.size(); | |
123 | for (u32* p = start; p < end; p++) *p = ++i; | |
124 | pc_vector.resize(i); | |
125 | } | |
126 | ||
127 | void TracePcGuard(u32* guard, uptr pc) { | |
128 | u32 idx = *guard; | |
129 | if (!idx) return; | |
130 | // we start indices from 1. | |
131 | atomic_uintptr_t* pc_ptr = | |
132 | reinterpret_cast<atomic_uintptr_t*>(&pc_vector[idx - 1]); | |
133 | if (atomic_load(pc_ptr, memory_order_relaxed) == 0) | |
134 | atomic_store(pc_ptr, pc, memory_order_relaxed); | |
135 | } | |
136 | ||
137 | void Reset() { | |
138 | internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); | |
139 | } | |
140 | ||
141 | void Dump() { | |
142 | if (!initialized || !common_flags()->coverage) return; | |
143 | __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); | |
144 | } | |
145 | ||
146 | private: | |
147 | bool initialized; | |
148 | InternalMmapVectorNoCtor<uptr> pc_vector; | |
149 | }; | |
150 | ||
151 | static TracePcGuardController pc_guard_controller; | |
152 | ||
153 | } // namespace | |
154 | } // namespace __sancov | |
155 | ||
156 | namespace __sanitizer { | |
157 | void InitializeCoverage(bool enabled, const char *dir) { | |
158 | static bool coverage_enabled = false; | |
159 | if (coverage_enabled) | |
160 | return; // May happen if two sanitizer enable coverage in the same process. | |
161 | coverage_enabled = enabled; | |
162 | Atexit(__sanitizer_cov_dump); | |
163 | AddDieCallback(__sanitizer_cov_dump); | |
164 | } | |
165 | } // namespace __sanitizer | |
166 | ||
167 | extern "C" { | |
168 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT | |
169 | const uptr* pcs, uptr len) { | |
170 | return __sancov::SanitizerDumpCoverage(pcs, len); | |
171 | } | |
172 | ||
173 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { | |
174 | if (!*guard) return; | |
175 | __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); | |
176 | } | |
177 | ||
178 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, | |
179 | u32* start, u32* end) { | |
180 | if (start == end || *start) return; | |
181 | __sancov::pc_guard_controller.InitTracePcGuard(start, end); | |
182 | } | |
183 | ||
184 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { | |
185 | __sancov::pc_guard_controller.Dump(); | |
186 | } | |
187 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { | |
188 | __sanitizer_dump_trace_pc_guard_coverage(); | |
189 | } | |
190 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { | |
191 | __sancov::pc_guard_controller.Reset(); | |
192 | } | |
193 | // Default empty implementations (weak). Users should redefine them. | |
194 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} | |
195 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} | |
196 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} | |
197 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} | |
198 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} | |
199 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} | |
200 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} | |
201 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} | |
202 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} | |
203 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} | |
204 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} | |
205 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} | |
206 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} | |
207 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} | |
208 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} | |
209 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} | |
210 | } // extern "C" | |
211 | // Weak definition for code instrumented with -fsanitize-coverage=stack-depth | |
212 | // and later linked with code containing a strong definition. | |
213 | // E.g., -fsanitize=fuzzer-no-link | |
214 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | |
215 | SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; | |
216 | ||
217 | #endif // !SANITIZER_FUCHSIA |