github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/pkginit/initAsanGlobals.go (about) 1 // Copyright 2022 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 package pkginit 6 7 import ( 8 "strings" 9 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 14 "github.com/bir3/gocompiler/src/cmd/internal/src" 15 ) 16 17 // instrumentGlobals declares a global array of _asan_global structures and initializes it. 18 func instrumentGlobals(fn *ir.Func) *ir.Name { 19 asanGlobalStruct, asanLocationStruct, defStringstruct := createtypes() 20 lname := typecheck.Lookup 21 tconv := typecheck.ConvNop 22 // Make a global array of asanGlobalStruct type. 23 // var asanglobals []asanGlobalStruct 24 arraytype := types.NewArray(asanGlobalStruct, int64(len(InstrumentGlobalsMap))) 25 symG := lname(".asanglobals") 26 globals := typecheck.NewName(symG) 27 globals.SetType(arraytype) 28 globals.Class = ir.PEXTERN 29 symG.Def = globals 30 typecheck.Target.Externs = append(typecheck.Target.Externs, globals) 31 // Make a global array of asanLocationStruct type. 32 // var asanL []asanLocationStruct 33 arraytype = types.NewArray(asanLocationStruct, int64(len(InstrumentGlobalsMap))) 34 symL := lname(".asanL") 35 asanlocation := typecheck.NewName(symL) 36 asanlocation.SetType(arraytype) 37 asanlocation.Class = ir.PEXTERN 38 symL.Def = asanlocation 39 typecheck.Target.Externs = append(typecheck.Target.Externs, asanlocation) 40 // Make three global string variables to pass the global name and module name 41 // and the name of the source file that defines it. 42 // var asanName string 43 // var asanModulename string 44 // var asanFilename string 45 symL = lname(".asanName") 46 asanName := typecheck.NewName(symL) 47 asanName.SetType(types.Types[types.TSTRING]) 48 asanName.Class = ir.PEXTERN 49 symL.Def = asanName 50 typecheck.Target.Externs = append(typecheck.Target.Externs, asanName) 51 52 symL = lname(".asanModulename") 53 asanModulename := typecheck.NewName(symL) 54 asanModulename.SetType(types.Types[types.TSTRING]) 55 asanModulename.Class = ir.PEXTERN 56 symL.Def = asanModulename 57 typecheck.Target.Externs = append(typecheck.Target.Externs, asanModulename) 58 59 symL = lname(".asanFilename") 60 asanFilename := typecheck.NewName(symL) 61 asanFilename.SetType(types.Types[types.TSTRING]) 62 asanFilename.Class = ir.PEXTERN 63 symL.Def = asanFilename 64 typecheck.Target.Externs = append(typecheck.Target.Externs, asanFilename) 65 66 var init ir.Nodes 67 var c ir.Node 68 // globals[i].odrIndicator = 0 is the default, no need to set it explicitly here. 69 for i, n := range InstrumentGlobalsSlice { 70 setField := func(f string, val ir.Node, i int) { 71 r := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, 72 ir.NewIndexExpr(base.Pos, globals, ir.NewInt(int64(i))), lname(f)), val) 73 init.Append(typecheck.Stmt(r)) 74 } 75 // globals[i].beg = uintptr(unsafe.Pointer(&n)) 76 c = tconv(typecheck.NodAddr(n), types.Types[types.TUNSAFEPTR]) 77 c = tconv(c, types.Types[types.TUINTPTR]) 78 setField("beg", c, i) 79 // Assign globals[i].size. 80 g := n.(*ir.Name) 81 size := g.Type().Size() 82 c = tconv(ir.NewInt(size), types.Types[types.TUINTPTR]) 83 setField("size", c, i) 84 // Assign globals[i].sizeWithRedzone. 85 rzSize := GetRedzoneSizeForGlobal(size) 86 sizeWithRz := rzSize + size 87 c = tconv(ir.NewInt(sizeWithRz), types.Types[types.TUINTPTR]) 88 setField("sizeWithRedzone", c, i) 89 // The C string type is terminated by a null character "\0", Go should use three-digit 90 // octal "\000" or two-digit hexadecimal "\x00" to create null terminated string. 91 // asanName = symbol's linkname + "\000" 92 // globals[i].name = (*defString)(unsafe.Pointer(&asanName)).data 93 name := g.Linksym().Name 94 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, asanName, ir.NewString(name+"\000")))) 95 c = tconv(typecheck.NodAddr(asanName), types.Types[types.TUNSAFEPTR]) 96 c = tconv(c, types.NewPtr(defStringstruct)) 97 c = ir.NewSelectorExpr(base.Pos, ir.ODOT, c, lname("data")) 98 setField("name", c, i) 99 100 // Set the name of package being compiled as a unique identifier of a module. 101 // asanModulename = pkgName + "\000" 102 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, asanModulename, ir.NewString(types.LocalPkg.Name+"\000")))) 103 c = tconv(typecheck.NodAddr(asanModulename), types.Types[types.TUNSAFEPTR]) 104 c = tconv(c, types.NewPtr(defStringstruct)) 105 c = ir.NewSelectorExpr(base.Pos, ir.ODOT, c, lname("data")) 106 setField("moduleName", c, i) 107 // Assign asanL[i].filename, asanL[i].line, asanL[i].column 108 // and assign globals[i].location = uintptr(unsafe.Pointer(&asanL[i])) 109 asanLi := ir.NewIndexExpr(base.Pos, asanlocation, ir.NewInt(int64(i))) 110 filename := ir.NewString(base.Ctxt.PosTable.Pos(n.Pos()).Filename() + "\000") 111 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, asanFilename, filename))) 112 c = tconv(typecheck.NodAddr(asanFilename), types.Types[types.TUNSAFEPTR]) 113 c = tconv(c, types.NewPtr(defStringstruct)) 114 c = ir.NewSelectorExpr(base.Pos, ir.ODOT, c, lname("data")) 115 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, asanLi, lname("filename")), c))) 116 line := ir.NewInt(int64(n.Pos().Line())) 117 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, asanLi, lname("line")), line))) 118 col := ir.NewInt(int64(n.Pos().Col())) 119 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, asanLi, lname("column")), col))) 120 c = tconv(typecheck.NodAddr(asanLi), types.Types[types.TUNSAFEPTR]) 121 c = tconv(c, types.Types[types.TUINTPTR]) 122 setField("sourceLocation", c, i) 123 } 124 fn.Body.Append(init...) 125 return globals 126 } 127 128 // createtypes creates the asanGlobal, asanLocation and defString struct type. 129 // Go compiler does not refer to the C types, we represent the struct field 130 // by a uintptr, then use type conversion to make copies of the data. 131 // E.g., (*defString)(asanGlobal.name).data to C string. 132 // 133 // Keep in sync with src/runtime/asan/asan.go. 134 // type asanGlobal struct { 135 // beg uintptr 136 // size uintptr 137 // size_with_redzone uintptr 138 // name uintptr 139 // moduleName uintptr 140 // hasDynamicInit uintptr 141 // sourceLocation uintptr 142 // odrIndicator uintptr 143 // } 144 // 145 // type asanLocation struct { 146 // filename uintptr 147 // line int32 148 // column int32 149 // } 150 // 151 // defString is synthesized struct type meant to capture the underlying 152 // implementations of string. 153 // type defString struct { 154 // data uintptr 155 // len uintptr 156 // } 157 158 func createtypes() (*types.Type, *types.Type, *types.Type) { 159 up := types.Types[types.TUINTPTR] 160 i32 := types.Types[types.TINT32] 161 fname := typecheck.Lookup 162 nxp := src.NoXPos 163 nfield := types.NewField 164 asanGlobal := types.NewStruct(types.NoPkg, []*types.Field{ 165 nfield(nxp, fname("beg"), up), 166 nfield(nxp, fname("size"), up), 167 nfield(nxp, fname("sizeWithRedzone"), up), 168 nfield(nxp, fname("name"), up), 169 nfield(nxp, fname("moduleName"), up), 170 nfield(nxp, fname("hasDynamicInit"), up), 171 nfield(nxp, fname("sourceLocation"), up), 172 nfield(nxp, fname("odrIndicator"), up), 173 }) 174 types.CalcSize(asanGlobal) 175 176 asanLocation := types.NewStruct(types.NoPkg, []*types.Field{ 177 nfield(nxp, fname("filename"), up), 178 nfield(nxp, fname("line"), i32), 179 nfield(nxp, fname("column"), i32), 180 }) 181 types.CalcSize(asanLocation) 182 183 defString := types.NewStruct(types.NoPkg, []*types.Field{ 184 types.NewField(nxp, fname("data"), up), 185 types.NewField(nxp, fname("len"), up), 186 }) 187 types.CalcSize(defString) 188 189 return asanGlobal, asanLocation, defString 190 } 191 192 // Calculate redzone for globals. 193 func GetRedzoneSizeForGlobal(size int64) int64 { 194 maxRZ := int64(1 << 18) 195 minRZ := int64(32) 196 redZone := (size / minRZ / 4) * minRZ 197 switch { 198 case redZone > maxRZ: 199 redZone = maxRZ 200 case redZone < minRZ: 201 redZone = minRZ 202 } 203 // Round up to multiple of minRZ. 204 if size%minRZ != 0 { 205 redZone += minRZ - (size % minRZ) 206 } 207 return redZone 208 } 209 210 // InstrumentGlobalsMap contains only package-local (and unlinknamed from somewhere else) 211 // globals. 212 // And the key is the object name. For example, in package p, a global foo would be in this 213 // map as "foo". 214 // Consider range over maps is nondeterministic, make a slice to hold all the values in the 215 // InstrumentGlobalsMap and iterate over the InstrumentGlobalsSlice. 216 var InstrumentGlobalsMap = make(map[string]ir.Node) 217 var InstrumentGlobalsSlice = make([]ir.Node, 0, 0) 218 219 func canInstrumentGlobal(g ir.Node) bool { 220 if g.Op() != ir.ONAME { 221 return false 222 } 223 n := g.(*ir.Name) 224 if n.Class == ir.PFUNC { 225 return false 226 } 227 if n.Sym().Pkg != types.LocalPkg { 228 return false 229 } 230 // Do not instrument any _cgo_ related global variables, because they are declared in C code. 231 if strings.Contains(n.Sym().Name, "cgo") { 232 return false 233 } 234 235 // Do not instrument globals that are linknamed, because their home package will do the work. 236 if n.Sym().Linkname != "" { 237 return false 238 } 239 240 return true 241 }