LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Implementation of the race detector API. | 5 // Implementation of the race detector API. |
6 // +build race | 6 // +build race |
7 | 7 |
8 #include "runtime.h" | 8 #include "runtime.h" |
9 #include "arch_GOARCH.h" | 9 #include "arch_GOARCH.h" |
10 #include "malloc.h" | 10 #include "malloc.h" |
11 #include "race.h" | 11 #include "race.h" |
12 #include "type.h" | 12 #include "type.h" |
13 #include "typekind.h" | 13 #include "typekind.h" |
| 14 #include "textflag.h" |
14 | 15 |
15 // Race runtime functions called via runtime·racecall. | 16 // Race runtime functions called via runtime·racecall. |
16 void __tsan_init(void); | 17 void __tsan_init(void); |
17 void __tsan_fini(void); | 18 void __tsan_fini(void); |
18 void __tsan_map_shadow(void); | 19 void __tsan_map_shadow(void); |
19 void __tsan_finalizer_goroutine(void); | 20 void __tsan_finalizer_goroutine(void); |
20 void __tsan_go_start(void); | 21 void __tsan_go_start(void); |
21 void __tsan_go_end(void); | 22 void __tsan_go_end(void); |
22 void __tsan_malloc(void); | 23 void __tsan_malloc(void); |
23 void __tsan_acquire(void); | 24 void __tsan_acquire(void); |
24 void __tsan_release(void); | 25 void __tsan_release(void); |
25 void __tsan_release_merge(void); | 26 void __tsan_release_merge(void); |
| 27 void __tsan_go_ignore_sync_begin(void); |
| 28 void __tsan_go_ignore_sync_end(void); |
26 | 29 |
27 // Mimic what cmd/cgo would do. | 30 // Mimic what cmd/cgo would do. |
28 #pragma cgo_import_static __tsan_init | 31 #pragma cgo_import_static __tsan_init |
29 #pragma cgo_import_static __tsan_fini | 32 #pragma cgo_import_static __tsan_fini |
30 #pragma cgo_import_static __tsan_map_shadow | 33 #pragma cgo_import_static __tsan_map_shadow |
31 #pragma cgo_import_static __tsan_finalizer_goroutine | 34 #pragma cgo_import_static __tsan_finalizer_goroutine |
32 #pragma cgo_import_static __tsan_go_start | 35 #pragma cgo_import_static __tsan_go_start |
33 #pragma cgo_import_static __tsan_go_end | 36 #pragma cgo_import_static __tsan_go_end |
34 #pragma cgo_import_static __tsan_malloc | 37 #pragma cgo_import_static __tsan_malloc |
35 #pragma cgo_import_static __tsan_acquire | 38 #pragma cgo_import_static __tsan_acquire |
36 #pragma cgo_import_static __tsan_release | 39 #pragma cgo_import_static __tsan_release |
37 #pragma cgo_import_static __tsan_release_merge | 40 #pragma cgo_import_static __tsan_release_merge |
| 41 #pragma cgo_import_static __tsan_go_ignore_sync_begin |
| 42 #pragma cgo_import_static __tsan_go_ignore_sync_end |
38 | 43 |
39 // These are called from race_amd64.s. | 44 // These are called from race_amd64.s. |
40 #pragma cgo_import_static __tsan_read | 45 #pragma cgo_import_static __tsan_read |
41 #pragma cgo_import_static __tsan_read_pc | 46 #pragma cgo_import_static __tsan_read_pc |
42 #pragma cgo_import_static __tsan_read_range | 47 #pragma cgo_import_static __tsan_read_range |
43 #pragma cgo_import_static __tsan_write | 48 #pragma cgo_import_static __tsan_write |
44 #pragma cgo_import_static __tsan_write_pc | 49 #pragma cgo_import_static __tsan_write_pc |
45 #pragma cgo_import_static __tsan_write_range | 50 #pragma cgo_import_static __tsan_write_range |
46 #pragma cgo_import_static __tsan_func_enter | 51 #pragma cgo_import_static __tsan_func_enter |
47 #pragma cgo_import_static __tsan_func_exit | 52 #pragma cgo_import_static __tsan_func_exit |
48 | 53 |
49 extern byte noptrdata[]; | 54 #pragma cgo_import_static __tsan_go_atomic32_load |
50 extern byte enoptrbss[]; | 55 #pragma cgo_import_static __tsan_go_atomic64_load |
| 56 #pragma cgo_import_static __tsan_go_atomic32_store |
| 57 #pragma cgo_import_static __tsan_go_atomic64_store |
| 58 #pragma cgo_import_static __tsan_go_atomic32_exchange |
| 59 #pragma cgo_import_static __tsan_go_atomic64_exchange |
| 60 #pragma cgo_import_static __tsan_go_atomic32_fetch_add |
| 61 #pragma cgo_import_static __tsan_go_atomic64_fetch_add |
| 62 #pragma cgo_import_static __tsan_go_atomic32_compare_exchange |
| 63 #pragma cgo_import_static __tsan_go_atomic64_compare_exchange |
| 64 |
| 65 extern byte runtime·noptrdata[]; |
| 66 extern byte runtime·enoptrbss[]; |
51 ·· | 67 ·· |
52 // start/end of heap for race_amd64.s | 68 // start/end of heap for race_amd64.s |
53 uintptr runtime·racearenastart; | 69 uintptr runtime·racearenastart; |
54 uintptr runtime·racearenaend; | 70 uintptr runtime·racearenaend; |
55 | 71 |
56 void runtime·racefuncenter(void *callpc); | 72 void runtime·racefuncenter(void *callpc); |
57 void runtime·racefuncexit(void); | 73 void runtime·racefuncexit(void); |
58 void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc); | 74 void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc); |
59 void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc); | 75 void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc); |
60 void runtime·racesymbolizethunk(void*); | 76 void runtime·racesymbolizethunk(void*); |
61 | 77 |
62 // racecall allows calling an arbitrary function f from C race runtime | 78 // racecall allows calling an arbitrary function f from C race runtime |
63 // with up to 4 uintptr arguments. | 79 // with up to 4 uintptr arguments. |
64 void runtime·racecall(void(*f)(void), ...); | 80 void runtime·racecall(void(*f)(void), ...); |
65 | 81 |
66 // checks if the address has shadow (i.e. heap or data/bss) | 82 // checks if the address has shadow (i.e. heap or data/bss) |
| 83 #pragma textflag NOSPLIT |
67 static bool | 84 static bool |
68 isvalidaddr(uintptr addr) | 85 isvalidaddr(uintptr addr) |
69 { | 86 { |
70 if(addr >= runtime·racearenastart && addr < runtime·racearenaend) | 87 if(addr >= runtime·racearenastart && addr < runtime·racearenaend) |
71 return true; | 88 return true; |
72 » if(addr >= (uintptr)noptrdata && addr < (uintptr)enoptrbss) | 89 » if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrb
ss) |
73 return true; | 90 return true; |
74 return false; | 91 return false; |
75 } | 92 } |
76 | 93 |
| 94 #pragma textflag NOSPLIT |
77 uintptr | 95 uintptr |
78 runtime·raceinit(void) | 96 runtime·raceinit(void) |
79 { | 97 { |
80 uintptr racectx, start, size; | 98 uintptr racectx, start, size; |
81 | 99 |
82 // cgo is required to initialize libc, which is used by race runtime | 100 // cgo is required to initialize libc, which is used by race runtime |
83 if(!runtime·iscgo) | 101 if(!runtime·iscgo) |
84 runtime·throw("raceinit: race build must use cgo"); | 102 runtime·throw("raceinit: race build must use cgo"); |
85 runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk); | 103 runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk); |
86 // Round data segment to page boundaries, because it's used in mmap(). | 104 // Round data segment to page boundaries, because it's used in mmap(). |
87 » start = (uintptr)noptrdata & ~(PageSize-1); | 105 » start = (uintptr)runtime·noptrdata & ~(PageSize-1); |
88 » size = ROUND((uintptr)enoptrbss - start, PageSize); | 106 » size = ROUND((uintptr)runtime·enoptrbss - start, PageSize); |
89 runtime·racecall(__tsan_map_shadow, start, size); | 107 runtime·racecall(__tsan_map_shadow, start, size); |
90 return racectx; | 108 return racectx; |
91 } | 109 } |
92 | 110 |
| 111 #pragma textflag NOSPLIT |
93 void | 112 void |
94 runtime·racefini(void) | 113 runtime·racefini(void) |
95 { | 114 { |
96 runtime·racecall(__tsan_fini); | 115 runtime·racecall(__tsan_fini); |
97 } | 116 } |
98 | 117 |
| 118 #pragma textflag NOSPLIT |
99 void | 119 void |
100 runtime·racemapshadow(void *addr, uintptr size) | 120 runtime·racemapshadow(void *addr, uintptr size) |
101 { | 121 { |
102 if(runtime·racearenastart == 0) | 122 if(runtime·racearenastart == 0) |
103 runtime·racearenastart = (uintptr)addr; | 123 runtime·racearenastart = (uintptr)addr; |
104 if(runtime·racearenaend < (uintptr)addr+size) | 124 if(runtime·racearenaend < (uintptr)addr+size) |
105 runtime·racearenaend = (uintptr)addr+size; | 125 runtime·racearenaend = (uintptr)addr+size; |
106 runtime·racecall(__tsan_map_shadow, addr, size); | 126 runtime·racecall(__tsan_map_shadow, addr, size); |
107 } | 127 } |
108 | 128 |
| 129 #pragma textflag NOSPLIT |
109 void | 130 void |
110 runtime·racemalloc(void *p, uintptr sz) | 131 runtime·racemalloc(void *p, uintptr sz) |
111 { | 132 { |
112 runtime·racecall(__tsan_malloc, p, sz); | 133 runtime·racecall(__tsan_malloc, p, sz); |
113 } | 134 } |
114 | 135 |
| 136 #pragma textflag NOSPLIT |
115 uintptr | 137 uintptr |
116 runtime·racegostart(void *pc) | 138 runtime·racegostart(void *pc) |
117 { | 139 { |
118 uintptr racectx; | 140 uintptr racectx; |
119 | 141 » G *spawng; |
120 » runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc); | 142 |
| 143 » if(g->m->curg != nil) |
| 144 » » spawng = g->m->curg; |
| 145 » else |
| 146 » » spawng = g; |
| 147 |
| 148 » runtime·racecall(__tsan_go_start, spawng->racectx, &racectx, pc); |
121 return racectx; | 149 return racectx; |
122 } | 150 } |
123 | 151 |
| 152 #pragma textflag NOSPLIT |
124 void | 153 void |
125 runtime·racegoend(void) | 154 runtime·racegoend(void) |
126 { | 155 { |
127 runtime·racecall(__tsan_go_end, g->racectx); | 156 runtime·racecall(__tsan_go_end, g->racectx); |
128 } | 157 } |
129 | 158 |
| 159 #pragma textflag NOSPLIT |
130 void | 160 void |
131 runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc) | 161 runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc) |
132 { | 162 { |
| 163 if(g != g->m->curg) { |
| 164 // The call is coming from manual instrumentation of Go code run
ning on g0/gsignal. |
| 165 // Not interesting. |
| 166 return; |
| 167 } |
133 if(callpc != nil) | 168 if(callpc != nil) |
134 runtime·racefuncenter(callpc); | 169 runtime·racefuncenter(callpc); |
135 runtime·racewriterangepc1(addr, sz, pc); | 170 runtime·racewriterangepc1(addr, sz, pc); |
136 if(callpc != nil) | 171 if(callpc != nil) |
137 runtime·racefuncexit(); | 172 runtime·racefuncexit(); |
138 } | 173 } |
139 | 174 |
| 175 #pragma textflag NOSPLIT |
140 void | 176 void |
141 runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc) | 177 runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc) |
142 { | 178 { |
| 179 if(g != g->m->curg) { |
| 180 // The call is coming from manual instrumentation of Go code run
ning on g0/gsignal. |
| 181 // Not interesting. |
| 182 return; |
| 183 } |
143 if(callpc != nil) | 184 if(callpc != nil) |
144 runtime·racefuncenter(callpc); | 185 runtime·racefuncenter(callpc); |
145 runtime·racereadrangepc1(addr, sz, pc); | 186 runtime·racereadrangepc1(addr, sz, pc); |
146 if(callpc != nil) | 187 if(callpc != nil) |
147 runtime·racefuncexit(); | 188 runtime·racefuncexit(); |
148 } | 189 } |
149 | 190 |
| 191 #pragma textflag NOSPLIT |
150 void | 192 void |
151 runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc) | 193 runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc) |
152 { | 194 { |
153 uint8 kind; | 195 uint8 kind; |
154 | 196 |
155 kind = t->kind & KindMask; | 197 kind = t->kind & KindMask; |
156 if(kind == KindArray || kind == KindStruct) | 198 if(kind == KindArray || kind == KindStruct) |
157 runtime·racewriterangepc(addr, t->size, callpc, pc); | 199 runtime·racewriterangepc(addr, t->size, callpc, pc); |
158 else | 200 else |
159 runtime·racewritepc(addr, callpc, pc); | 201 runtime·racewritepc(addr, callpc, pc); |
160 } | 202 } |
161 | 203 |
| 204 #pragma textflag NOSPLIT |
162 void | 205 void |
163 runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc) | 206 runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc) |
164 { | 207 { |
165 uint8 kind; | 208 uint8 kind; |
166 | 209 |
167 kind = t->kind & KindMask; | 210 kind = t->kind & KindMask; |
168 if(kind == KindArray || kind == KindStruct) | 211 if(kind == KindArray || kind == KindStruct) |
169 runtime·racereadrangepc(addr, t->size, callpc, pc); | 212 runtime·racereadrangepc(addr, t->size, callpc, pc); |
170 else | 213 else |
171 runtime·racereadpc(addr, callpc, pc); | 214 runtime·racereadpc(addr, callpc, pc); |
172 } | 215 } |
173 | 216 |
| 217 #pragma textflag NOSPLIT |
174 void | 218 void |
175 runtime·raceacquire(void *addr) | 219 runtime·raceacquire(void *addr) |
176 { | 220 { |
177 runtime·raceacquireg(g, addr); | 221 runtime·raceacquireg(g, addr); |
178 } | 222 } |
179 | 223 |
| 224 #pragma textflag NOSPLIT |
180 void | 225 void |
181 runtime·raceacquireg(G *gp, void *addr) | 226 runtime·raceacquireg(G *gp, void *addr) |
182 { | 227 { |
183 if(g->raceignore || !isvalidaddr((uintptr)addr)) | 228 if(g->raceignore || !isvalidaddr((uintptr)addr)) |
184 return; | 229 return; |
185 runtime·racecall(__tsan_acquire, gp->racectx, addr); | 230 runtime·racecall(__tsan_acquire, gp->racectx, addr); |
186 } | 231 } |
187 | 232 |
| 233 #pragma textflag NOSPLIT |
188 void | 234 void |
189 runtime·racerelease(void *addr) | 235 runtime·racerelease(void *addr) |
190 { | 236 { |
191 if(g->raceignore || !isvalidaddr((uintptr)addr)) | 237 if(g->raceignore || !isvalidaddr((uintptr)addr)) |
192 return; | 238 return; |
193 runtime·racereleaseg(g, addr); | 239 runtime·racereleaseg(g, addr); |
194 } | 240 } |
195 | 241 |
| 242 #pragma textflag NOSPLIT |
196 void | 243 void |
197 runtime·racereleaseg(G *gp, void *addr) | 244 runtime·racereleaseg(G *gp, void *addr) |
198 { | 245 { |
199 if(g->raceignore || !isvalidaddr((uintptr)addr)) | 246 if(g->raceignore || !isvalidaddr((uintptr)addr)) |
200 return; | 247 return; |
201 runtime·racecall(__tsan_release, gp->racectx, addr); | 248 runtime·racecall(__tsan_release, gp->racectx, addr); |
202 } | 249 } |
203 | 250 |
| 251 #pragma textflag NOSPLIT |
204 void | 252 void |
205 runtime·racereleasemerge(void *addr) | 253 runtime·racereleasemerge(void *addr) |
206 { | 254 { |
207 runtime·racereleasemergeg(g, addr); | 255 runtime·racereleasemergeg(g, addr); |
208 } | 256 } |
209 | 257 |
| 258 #pragma textflag NOSPLIT |
210 void | 259 void |
211 runtime·racereleasemergeg(G *gp, void *addr) | 260 runtime·racereleasemergeg(G *gp, void *addr) |
212 { | 261 { |
213 if(g->raceignore || !isvalidaddr((uintptr)addr)) | 262 if(g->raceignore || !isvalidaddr((uintptr)addr)) |
214 return; | 263 return; |
215 runtime·racecall(__tsan_release_merge, gp->racectx, addr); | 264 runtime·racecall(__tsan_release_merge, gp->racectx, addr); |
216 } | 265 } |
217 | 266 |
| 267 #pragma textflag NOSPLIT |
218 void | 268 void |
219 runtime·racefingo(void) | 269 runtime·racefingo(void) |
220 { | 270 { |
221 runtime·racecall(__tsan_finalizer_goroutine, g->racectx); | 271 runtime·racecall(__tsan_finalizer_goroutine, g->racectx); |
222 } | 272 } |
223 | 273 |
224 // func RaceAcquire(addr unsafe.Pointer) | 274 // func RaceAcquire(addr unsafe.Pointer) |
| 275 #pragma textflag NOSPLIT |
225 void | 276 void |
226 runtime·RaceAcquire(void *addr) | 277 runtime·RaceAcquire(void *addr) |
227 { | 278 { |
228 runtime·raceacquire(addr); | 279 runtime·raceacquire(addr); |
229 } | 280 } |
230 | 281 |
231 // func RaceRelease(addr unsafe.Pointer) | 282 // func RaceRelease(addr unsafe.Pointer) |
| 283 #pragma textflag NOSPLIT |
232 void | 284 void |
233 runtime·RaceRelease(void *addr) | 285 runtime·RaceRelease(void *addr) |
234 { | 286 { |
235 runtime·racerelease(addr); | 287 runtime·racerelease(addr); |
236 } | 288 } |
237 | 289 |
238 // func RaceReleaseMerge(addr unsafe.Pointer) | 290 // func RaceReleaseMerge(addr unsafe.Pointer) |
| 291 #pragma textflag NOSPLIT |
239 void | 292 void |
240 runtime·RaceReleaseMerge(void *addr) | 293 runtime·RaceReleaseMerge(void *addr) |
241 { | 294 { |
242 runtime·racereleasemerge(addr); | 295 runtime·racereleasemerge(addr); |
243 } | 296 } |
244 | 297 |
245 // func RaceSemacquire(s *uint32) | |
246 void | |
247 runtime·RaceSemacquire(uint32 *s) | |
248 { | |
249 runtime·semacquire(s, false); | |
250 } | |
251 | |
252 // func RaceSemrelease(s *uint32) | |
253 void | |
254 runtime·RaceSemrelease(uint32 *s) | |
255 { | |
256 runtime·semrelease(s); | |
257 } | |
258 | |
259 // func RaceDisable() | 298 // func RaceDisable() |
| 299 #pragma textflag NOSPLIT |
260 void | 300 void |
261 runtime·RaceDisable(void) | 301 runtime·RaceDisable(void) |
262 { | 302 { |
263 » g->raceignore++; | 303 » if(g->raceignore++ == 0) |
| 304 » » runtime·racecall(__tsan_go_ignore_sync_begin, g->racectx); |
264 } | 305 } |
265 | 306 |
266 // func RaceEnable() | 307 // func RaceEnable() |
| 308 #pragma textflag NOSPLIT |
267 void | 309 void |
268 runtime·RaceEnable(void) | 310 runtime·RaceEnable(void) |
269 { | 311 { |
270 » g->raceignore--; | 312 » if(--g->raceignore == 0) |
271 } | 313 » » runtime·racecall(__tsan_go_ignore_sync_end, g->racectx); |
272 | 314 } |
273 typedef struct SymbolizeContext SymbolizeContext; | |
274 struct SymbolizeContext | |
275 { | |
276 » uintptr»pc; | |
277 » int8*» func; | |
278 » int8*» file; | |
279 » uintptr»line; | |
280 » uintptr»off; | |
281 » uintptr»res; | |
282 }; | |
283 | |
284 // Callback from C into Go, runs on g0. | |
285 void | |
286 runtime·racesymbolize(SymbolizeContext *ctx) | |
287 { | |
288 » Func *f; | |
289 » String file; | |
290 | |
291 » f = runtime·findfunc(ctx->pc); | |
292 » if(f == nil) { | |
293 » » ctx->func = "??"; | |
294 » » ctx->file = "-"; | |
295 » » ctx->line = 0; | |
296 » » ctx->off = ctx->pc; | |
297 » » ctx->res = 1; | |
298 » » return; | |
299 » } | |
300 » ctx->func = runtime·funcname(f); | |
301 » ctx->line = runtime·funcline(f, ctx->pc, &file); | |
302 » ctx->file = (int8*)file.str; // assume zero-terminated | |
303 » ctx->off = ctx->pc - f->entry; | |
304 » ctx->res = 1; | |
305 } | |
LEFT | RIGHT |