Home | History | Annotate | Download | only in runtime
      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