1 // Copyright 2012 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.
12 // The instrument pass modifies the code tree for instrumentation.
14 // For flag_race it modifies the function as follows:
16 // 1. It inserts a call to racefuncenterfp at the beginning of each function.
17 // 2. It inserts a call to racefuncexit at the end of each function.
18 // 3. It inserts a call to raceread before each memory read.
19 // 4. It inserts a call to racewrite before each memory write.
23 // 1. It inserts a call to msanread before each memory read.
24 // 2. It inserts a call to msanwrite before each memory write.
26 // The rewriting is not yet complete. Certain nodes are not rewritten
29 // TODO(dvyukov): do not instrument initialization as writes:
30 // a := make([]int, 10)
32 // Do not instrument the following packages at all,
33 // at best instrumentation would cause infinite recursion.
34 var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
36 // Only insert racefuncenterfp/racefuncexit into the following packages.
37 // Memory accesses in the packages are either uninteresting or will cause false positives.
38 var norace_inst_pkgs = []string{"sync", "sync/atomic"}
40 func ispkgin(pkgs []string) bool {
41 if myimportpath != "" {
42 for _, p := range pkgs {
43 if myimportpath == p {
52 func instrument(fn *Node) {
53 if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
57 if flag_race == 0 || !ispkgin(norace_inst_pkgs) {
58 instrumentlist(fn.Nbody, nil)
60 // nothing interesting for race detector in fn->enter
61 instrumentslice(fn.Func.Exit.Slice(), nil)
65 // nodpc is the PC of the caller as extracted by
66 // getcallerpc. We use -widthptr(FP) for x86.
67 // BUG: this will not work on arm.
68 nodpc := Nod(OXXX, nil, nil)
71 nodpc.Type = Types[TUINTPTR]
72 nodpc.Xoffset = int64(-Widthptr)
73 nd := mkcall("racefuncenter", nil, nil, nodpc)
74 fn.Func.Enter.Set(append([]*Node{nd}, fn.Func.Enter.Slice()...))
75 nd = mkcall("racefuncexit", nil, nil)
76 fn.Func.Exit.Append(nd)
80 s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
82 s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
83 dumpslice(s, fn.Func.Enter.Slice())
84 s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
85 dumpslice(s, fn.Func.Exit.Slice())
89 func instrumentlist(l *NodeList, init **NodeList) {
92 for ; l != nil; l = l.Next {
94 instrumentnode(&l.N, &instr, 0, 0)
96 l.N.Ninit = concat(l.N.Ninit, instr)
98 *init = concat(*init, instr)
103 func instrumentslice(l []*Node, init **NodeList) {
106 instrumentnode(&l[i], &instr, 0, 0)
108 l[i].Ninit = concat(l[i].Ninit, instr)
110 *init = concat(*init, instr)
115 // walkexpr and walkstmt combined
116 // walks the tree and adds calls to the
117 // instrumentation code to top-level (statement) nodes' init
118 func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
126 Dump("instrument-before", n)
130 Fatalf("instrument: bad init list")
132 if init == &n.Ninit {
133 // If init == &n->ninit and n->ninit is non-nil,
134 // instrumentnode might append it to itself.
135 // nil it out and handle it separately before putting it back.
139 instrumentlist(l, nil)
140 instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
146 instrumentlist(n.Ninit, nil)
150 Fatalf("instrument: unknown node type %v", Oconv(int(n.Op), 0))
152 case OAS, OASWB, OAS2FUNC:
153 instrumentnode(&n.Left, init, 1, 0)
154 instrumentnode(&n.Right, init, 0, 0)
158 case OCFUNC, OVARKILL, OVARLIVE:
163 for l := n.List; l != nil; l = l.Next {
165 case OCALLFUNC, OCALLMETH, OCALLINTER:
166 instrumentnode(&l.N, &l.N.Ninit, 0, 0)
168 // Scan past OAS nodes copying results off stack.
169 // Those must not be instrumented, because the
170 // instrumentation calls will smash the results.
171 // The assignments are to temporaries, so they cannot
172 // be involved in races and need not be instrumented.
173 for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
178 instrumentnode(&l.N, &out, 0, 0)
186 instrumentnode(&n.Left, init, 0, 0)
190 instrumentnode(&n.Left, init, 0, 0)
194 instrumentnode(&n.Left, init, 0, 0)
197 // Instrument dst argument of runtime.writebarrier* calls
198 // as we do not instrument runtime code.
199 // typedslicecopy is instrumented in runtime.
201 instrumentnode(&n.Left, init, 0, 0)
211 instrumentnode(&n.Left, init, wr, 0)
215 instrumentnode(&n.Left, init, 0, 0)
219 instrumentnode(&n.Left, init, 0, 1)
220 callinstr(&n, init, wr, skip)
223 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
224 instrumentnode(&n.Left, init, 0, 0)
226 callinstr(&n, init, wr, skip)
230 instrumentnode(&n.Left, init, 0, 0)
232 callinstr(&n, init, wr, skip)
235 case OSPTR, OLEN, OCAP:
236 instrumentnode(&n.Left, init, 0, 0)
237 if Istype(n.Left.Type, TMAP) {
238 n1 := Nod(OCONVNOP, n.Left, nil)
239 n1.Type = Ptrto(Types[TUINT8])
240 n1 = Nod(OIND, n1, nil)
242 callinstr(&n1, init, 0, skip)
265 instrumentnode(&n.Left, init, wr, 0)
266 instrumentnode(&n.Right, init, wr, 0)
270 instrumentnode(&n.Left, init, wr, 0)
272 // walk has ensured the node has moved to a location where
273 // side effects are safe.
274 // n->right may not be executed,
275 // so instrumentation goes to n->right->ninit, not init.
276 instrumentnode(&n.Right, &n.Right.Ninit, wr, 0)
281 callinstr(&n, init, wr, skip)
285 instrumentnode(&n.Left, init, wr, 0)
289 instrumentnode(&n.Left, init, wr, 0)
293 instrumentnode(&n.Left, init, wr, 0)
294 instrumentnode(&n.Right, init, wr, 0)
298 if !Isfixedarray(n.Left.Type) {
299 instrumentnode(&n.Left, init, 0, 0)
300 } else if !islvalue(n.Left) {
301 // index of unaddressable array, like Map[k][i].
302 instrumentnode(&n.Left, init, wr, 0)
304 instrumentnode(&n.Right, init, 0, 0)
308 instrumentnode(&n.Right, init, 0, 0)
309 if n.Left.Type.Etype != TSTRING {
310 callinstr(&n, init, wr, skip)
314 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
315 instrumentnode(&n.Left, init, 0, 0)
316 instrumentnode(&n.Right, init, 0, 0)
320 instrumentnode(&n.Left, init, 0, 0)
321 instrumentnode(&n.Right, init, 0, 0)
325 instrumentnode(&n.Left, init, 0, 1)
328 // n->left is Type* which is not interesting.
330 instrumentnode(&n.Right, init, 0, 0)
335 instrumentnode(&n.Left, init, 0, 0)
338 // should not appear in AST by now
370 OCLOSURE, // lowered to PTRLIT
371 ORANGE, // lowered to ordinary for loop
372 OARRAYLIT, // lowered to assignments
379 Yyerror("instrument: %v must be lowered by now", Oconv(int(n.Op), 0))
383 // impossible nodes: only appear in backend.
384 case ORROTC, OEXTEND:
385 Yyerror("instrument: %v cannot exist now", Oconv(int(n.Op), 0))
389 Yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
394 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
397 instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
403 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
407 // just do generic traversal
420 // does not require instrumentation
421 case OPRINT, // don't bother instrumenting it
422 OPRINTN, // don't bother instrumenting it
423 OCHECKNIL, // always followed by a read.
424 OPARAM, // it appears only in fn->exit to copy heap params back
425 OCLOSUREVAR, // immutable pointer to captured variable
426 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
427 OINDREG, // at this stage, only n(SP) nodes from nodarg
428 ODCL, // declarations (without value) cannot be races
434 OTYPESW: // ignored by code generation, do not instrument.
439 if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
440 instrumentlist(n.List, init)
442 instrumentlist(n.Nbody, nil)
443 instrumentlist(n.Rlist, nil)
447 func isartificial(n *Node) bool {
448 // compiler-emitted artificial things that we do not want to instrument,
449 // can't possibly participate in a data race.
450 // can't be seen by C/C++ and therefore irrelevant for msan.
451 if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
452 if n.Sym.Name == "_" {
456 // autotmp's are always local
457 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
461 // statictmp's are read-only
462 if strings.HasPrefix(n.Sym.Name, "statictmp_") {
466 // go.itab is accessed only by the compiler and runtime (assume safe)
467 if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
475 func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
478 //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
479 // n, n->op, n->type ? n->type->etype : -1, n->class);
481 if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
491 // it skips e.g. stores to ... parameter array
497 // BUG: we _may_ want to instrument PAUTO sometimes
498 // e.g. if we've got a local variable/method receiver
499 // that has got a pointer inside. Whether it points to
500 // the heap or not is impossible to know at compile time
501 if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
503 foreach(n, hascallspred, &hascalls)
505 n = detachexpr(n, init)
517 // dowidth may not have been called for PEXTERN.
521 Fatalf("instrument: %v badwidth", t)
523 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
524 } else if flag_race != 0 && (t.Etype == TSTRUCT || Isfixedarray(t)) {
525 name := "racereadrange"
527 name = "racewriterange"
529 // dowidth may not have been called for PEXTERN.
533 Fatalf("instrument: %v badwidth", t)
535 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
536 } else if flag_race != 0 {
541 f = mkcall(name, nil, init, uintptraddr(n))
544 *init = list(*init, f)
551 // makeaddable returns a node whose memory location is the
552 // same as n, but which is addressable in the Go language
554 // This is different from functions like cheapexpr that may make
555 // a copy of their argument.
556 func makeaddable(n *Node) {
557 // The arguments to uintptraddr technically have an address but
558 // may not be addressable in the Go sense: for example, in the case
559 // of T(v).Field where T is a struct type and v is
560 // an addressable value.
563 if Isfixedarray(n.Left.Type) {
567 // Turn T(v).Field into v.Field
569 if n.Left.Op == OCONVNOP {
582 func uintptraddr(n *Node) *Node {
583 r := Nod(OADDR, n, nil)
585 r = conv(r, Types[TUNSAFEPTR])
586 r = conv(r, Types[TUINTPTR])
590 func detachexpr(n *Node, init **NodeList) *Node {
591 addr := Nod(OADDR, n, nil)
592 l := temp(Ptrto(n.Type))
593 as := Nod(OAS, l, addr)
596 *init = list(*init, as)
597 ind := Nod(OIND, l, nil)
603 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
609 func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
610 for ; l != nil; l = l.Next {
611 foreachnode(l.N, f, c)
615 func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
616 foreachlist(n.Ninit, f, c)
617 foreachnode(n.Left, f, c)
618 foreachnode(n.Right, f, c)
619 foreachlist(n.List, f, c)
620 foreachlist(n.Nbody, f, c)
621 foreachlist(n.Rlist, f, c)
624 func hascallspred(n *Node, c interface{}) {
626 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
631 // appendinit is like addinit in subr.go
632 // but appends rather than prepends.
633 func appendinit(np **Node, init *NodeList) {
640 // There may be multiple refs to this node;
641 // introduce OCONVNOP to hold init list.
642 case ONAME, OLITERAL:
643 n = Nod(OCONVNOP, n, nil)
650 n.Ninit = concat(n.Ninit, init)