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