LEFT | RIGHT |
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 | 14 |
15 void runtime·racecall(void(*f)(void), ...); | 15 // Race runtime functions called via runtime·racecall. |
16 | |
17 void __tsan_init(void); | 16 void __tsan_init(void); |
18 void __tsan_fini(void); | 17 void __tsan_fini(void); |
19 void __tsan_map_shadow(void); | 18 void __tsan_map_shadow(void); |
20 void __tsan_finalizer_goroutine(void); | 19 void __tsan_finalizer_goroutine(void); |
21 void __tsan_go_start(void); | 20 void __tsan_go_start(void); |
22 void __tsan_go_end(void); | 21 void __tsan_go_end(void); |
23 void __tsan_malloc(void); | 22 void __tsan_malloc(void); |
24 void __tsan_acquire(void); | 23 void __tsan_acquire(void); |
25 void __tsan_release(void); | 24 void __tsan_release(void); |
26 void __tsan_release_merge(void); | 25 void __tsan_release_merge(void); |
27 | 26 |
| 27 // Mimic what cmd/cgo would do. |
| 28 #pragma cgo_import_static __tsan_init |
| 29 #pragma cgo_import_static __tsan_fini |
| 30 #pragma cgo_import_static __tsan_map_shadow |
| 31 #pragma cgo_import_static __tsan_finalizer_goroutine |
| 32 #pragma cgo_import_static __tsan_go_start |
| 33 #pragma cgo_import_static __tsan_go_end |
| 34 #pragma cgo_import_static __tsan_malloc |
| 35 #pragma cgo_import_static __tsan_acquire |
| 36 #pragma cgo_import_static __tsan_release |
| 37 #pragma cgo_import_static __tsan_release_merge |
| 38 |
| 39 // These are called from race_amd64.s. |
| 40 #pragma cgo_import_static __tsan_read |
| 41 #pragma cgo_import_static __tsan_read_pc |
| 42 #pragma cgo_import_static __tsan_read_range |
| 43 #pragma cgo_import_static __tsan_write |
| 44 #pragma cgo_import_static __tsan_write_pc |
| 45 #pragma cgo_import_static __tsan_write_range |
| 46 #pragma cgo_import_static __tsan_func_enter |
| 47 #pragma cgo_import_static __tsan_func_exit |
| 48 |
28 extern byte noptrdata[]; | 49 extern byte noptrdata[]; |
29 extern byte enoptrbss[]; | 50 extern byte enoptrbss[]; |
| 51 ·· |
| 52 // start/end of heap for race_amd64.s |
| 53 uintptr runtime·racearenastart; |
| 54 uintptr runtime·racearenaend; |
| 55 |
| 56 void runtime·racefuncenter(void *callpc); |
| 57 void runtime·racefuncexit(void); |
| 58 void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc); |
| 59 void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc); |
| 60 void runtime·racesymbolizethunk(void*); |
| 61 |
| 62 // racecall allows calling an arbitrary function f from C race runtime |
| 63 // with up to 4 uintptr arguments. |
| 64 void runtime·racecall(void(*f)(void), ...); |
30 | 65 |
31 uintptr | 66 uintptr |
32 runtime·raceinit(void) | 67 runtime·raceinit(void) |
33 { | 68 { |
34 uintptr racectx, start, size; | 69 uintptr racectx, start, size; |
35 | 70 |
36 » runtime·racecall(__tsan_init, &racectx); | 71 » // cgo is required to initialize libc, which is used by race runtime |
| 72 » if(!runtime·iscgo) |
| 73 » » runtime·throw("raceinit: race build must use cgo"); |
| 74 » runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk); |
37 // Round data segment to page boundaries, because it's used in mmap(). | 75 // Round data segment to page boundaries, because it's used in mmap(). |
38 start = (uintptr)noptrdata & ~(PageSize-1); | 76 start = (uintptr)noptrdata & ~(PageSize-1); |
39 size = ROUND((uintptr)enoptrbss - start, PageSize); | 77 size = ROUND((uintptr)enoptrbss - start, PageSize); |
40 runtime·racecall(__tsan_map_shadow, start, size); | 78 runtime·racecall(__tsan_map_shadow, start, size); |
41 return racectx; | 79 return racectx; |
42 } | 80 } |
43 | 81 |
44 void | 82 void |
45 runtime·racefini(void) | 83 runtime·racefini(void) |
46 { | 84 { |
47 runtime·racecall(__tsan_fini); | 85 runtime·racecall(__tsan_fini); |
48 } | 86 } |
49 | 87 |
50 void | 88 void |
51 runtime·racemapshadow(void *addr, uintptr size) | 89 runtime·racemapshadow(void *addr, uintptr size) |
52 { | 90 { |
| 91 if(runtime·racearenastart == 0) |
| 92 runtime·racearenastart = (uintptr)addr; |
| 93 if(runtime·racearenaend < (uintptr)addr+size) |
| 94 runtime·racearenaend = (uintptr)addr+size; |
53 runtime·racecall(__tsan_map_shadow, addr, size); | 95 runtime·racecall(__tsan_map_shadow, addr, size); |
54 } | 96 } |
55 | 97 |
56 void | 98 void |
57 runtime·racemalloc(void *p, uintptr sz) | 99 runtime·racemalloc(void *p, uintptr sz) |
58 { | 100 { |
59 » // use m->curg because runtime·stackalloc() is called from g0 | 101 » runtime·racecall(__tsan_malloc, p, sz); |
60 » if(m->curg == nil) | |
61 » » return; | |
62 » runtime·racecall(__tsan_malloc, m->curg->racectx, p, sz); | |
63 } | 102 } |
64 | 103 |
65 uintptr | 104 uintptr |
66 runtime·racegostart(void *pc) | 105 runtime·racegostart(void *pc) |
67 { | 106 { |
68 uintptr racectx; | 107 uintptr racectx; |
69 | 108 |
70 runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc); | 109 runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc); |
71 return racectx; | 110 return racectx; |
72 } | 111 } |
73 | 112 |
74 void | 113 void |
75 runtime·racegoend(void) | 114 runtime·racegoend(void) |
76 { | 115 { |
77 runtime·racecall(__tsan_go_end, g->racectx); | 116 runtime·racecall(__tsan_go_end, g->racectx); |
| 117 } |
| 118 |
| 119 void |
| 120 runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc) |
| 121 { |
| 122 if(callpc != nil) |
| 123 runtime·racefuncenter(callpc); |
| 124 runtime·racewriterangepc1(addr, sz, pc); |
| 125 if(callpc != nil) |
| 126 runtime·racefuncexit(); |
| 127 } |
| 128 |
| 129 void |
| 130 runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc) |
| 131 { |
| 132 if(callpc != nil) |
| 133 runtime·racefuncenter(callpc); |
| 134 runtime·racereadrangepc1(addr, sz, pc); |
| 135 if(callpc != nil) |
| 136 runtime·racefuncexit(); |
78 } | 137 } |
79 | 138 |
80 void | 139 void |
81 runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc) | 140 runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc) |
82 { | 141 { |
83 uint8 kind; | 142 uint8 kind; |
84 | 143 |
85 kind = t->kind & ~KindNoPointers; | 144 kind = t->kind & ~KindNoPointers; |
86 if(kind == KindArray || kind == KindStruct) | 145 if(kind == KindArray || kind == KindStruct) |
87 runtime·racewriterangepc(addr, t->size, callpc, pc); | 146 runtime·racewriterangepc(addr, t->size, callpc, pc); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 ctx->off = ctx->pc; | 283 ctx->off = ctx->pc; |
225 ctx->res = 1; | 284 ctx->res = 1; |
226 return; | 285 return; |
227 } | 286 } |
228 ctx->func = runtime·funcname(f); | 287 ctx->func = runtime·funcname(f); |
229 ctx->line = runtime·funcline(f, ctx->pc, &file); | 288 ctx->line = runtime·funcline(f, ctx->pc, &file); |
230 ctx->file = (int8*)file.str; // assume zero-terminated | 289 ctx->file = (int8*)file.str; // assume zero-terminated |
231 ctx->off = ctx->pc - f->entry; | 290 ctx->off = ctx->pc - f->entry; |
232 ctx->res = 1; | 291 ctx->res = 1; |
233 } | 292 } |
LEFT | RIGHT |