Commit a14efb1b authored by Keith Randall's avatar Keith Randall Committed by Keith Randall

runtime: allow the Go runtime to return multiple stack frames for a single PC

Upgrade the thread sanitizer to handle mid-stack inlining correctly.
We can now return multiple stack frames for each pc that the thread sanitizer
gives us to symbolize.

To fix #33309, we still need to modify the tsan library with its portion
of this fix, rebuild the .syso files on all supported archs, and check
them into runtime/race.

Update #33309

Change-Id: I340013631ffc8428043ab7efe3a41b6bf5638eaf
Reviewed-on: https://go-review.googlesource.com/c/go/+/195781
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarDmitry Vyukov <dvyukov@google.com>
parent 87008075
...@@ -155,15 +155,51 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) { ...@@ -155,15 +155,51 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) {
} }
} }
// raceSymbolizeCode reads ctx.pc and populates the rest of *ctx with
// information about the code at that pc.
//
// The race detector has already subtracted 1 from pcs, so they point to the last
// byte of call instructions (including calls to runtime.racewrite and friends).
//
// If the incoming pc is part of an inlined function, *ctx is populated
// with information about the inlined function, and on return ctx.pc is set
// to a pc in the logically containing function. (The race detector should call this
// function again with that pc.)
//
// If the incoming pc is not part of an inlined function, the return pc is unchanged.
func raceSymbolizeCode(ctx *symbolizeCodeContext) { func raceSymbolizeCode(ctx *symbolizeCodeContext) {
f := findfunc(ctx.pc)._Func() pc := ctx.pc
fi := findfunc(pc)
f := fi._Func()
if f != nil { if f != nil {
file, line := f.FileLine(ctx.pc) file, line := f.FileLine(pc)
if line != 0 { if line != 0 {
ctx.fn = cfuncname(f.funcInfo()) if inldata := funcdata(fi, _FUNCDATA_InlTree); inldata != nil {
inltree := (*[1 << 20]inlinedCall)(inldata)
for {
ix := pcdatavalue(fi, _PCDATA_InlTreeIndex, pc, nil)
if ix >= 0 {
if inltree[ix].funcID == funcID_wrapper {
// ignore wrappers
// Back up to an instruction in the "caller".
pc = f.Entry() + uintptr(inltree[ix].parentPc)
continue
}
ctx.pc = f.Entry() + uintptr(inltree[ix].parentPc) // "caller" pc
ctx.fn = cfuncnameFromNameoff(fi, inltree[ix].func_)
ctx.line = uintptr(line)
ctx.file = &bytes(file)[0] // assume NUL-terminated
ctx.off = pc - f.Entry()
ctx.res = 1
return
}
break
}
}
ctx.fn = cfuncname(fi)
ctx.line = uintptr(line) ctx.line = uintptr(line)
ctx.file = &bytes(file)[0] // assume NUL-terminated ctx.file = &bytes(file)[0] // assume NUL-terminated
ctx.off = ctx.pc - f.Entry() ctx.off = pc - f.Entry()
ctx.res = 1 ctx.res = 1
return return
} }
......
...@@ -735,13 +735,15 @@ func funcname(f funcInfo) string { ...@@ -735,13 +735,15 @@ func funcname(f funcInfo) string {
return gostringnocopy(cfuncname(f)) return gostringnocopy(cfuncname(f))
} }
func funcnameFromNameoff(f funcInfo, nameoff int32) string { func cfuncnameFromNameoff(f funcInfo, nameoff int32) *byte {
datap := f.datap
if !f.valid() { if !f.valid() {
return "" return nil
} }
cstr := &datap.pclntable[nameoff] return &f.datap.pclntable[nameoff]
return gostringnocopy(cstr) }
func funcnameFromNameoff(f funcInfo, nameoff int32) string {
return gostringnocopy(cfuncnameFromNameoff(f, nameoff))
} }
func funcfile(f funcInfo, fileno int32) string { func funcfile(f funcInfo, fileno int32) string {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment