Skip to content

Commit

Permalink
bugfix, Issue #163: offset of g struct in TLS picked based on the val…
Browse files Browse the repository at this point in the history
…ue of runtime.buildVersion and presence of compile units created by GNU AS, instead of being fixed to -16
  • Loading branch information
aarzilli committed Jul 23, 2015
1 parent 1727df4 commit bd13e32
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 22 deletions.
12 changes: 12 additions & 0 deletions _fixtures/cgotest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

/*
char* foo(void) { return "hello, world!"; }
*/
import "C"

import "fmt"

func main() {
fmt.Println(C.GoString(C.foo()))
}
9 changes: 6 additions & 3 deletions dwarf/op/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ func ExecuteStackProgram(cfa int64, instructions []byte) (int64, error) {
stack := make([]int64, 0, 3)
buf := bytes.NewBuffer(instructions)

for ocfaode, err := buf.ReadByte(); err == nil; ocfaode, err = buf.ReadByte() {
fn, ok := oplut[ocfaode]
for opcode, err := buf.ReadByte(); err == nil; opcode, err = buf.ReadByte() {
fn, ok := oplut[opcode]
if !ok {
return 0, fmt.Errorf("invalid instruction %#v", ocfaode)
return 0, fmt.Errorf("invalid instruction %#v", opcode)
}

stack, err = fn(buf, stack, cfa)
Expand All @@ -51,6 +51,9 @@ func ExecuteStackProgram(cfa int64, instructions []byte) (int64, error) {
}

func callframecfa(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
if cfa == 0 {
return stack, fmt.Errorf("Could not retrieve CFA for current PC")
}
return append(stack, int64(cfa)), nil
}

Expand Down
14 changes: 14 additions & 0 deletions dwarf/reader/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,17 @@ func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
// No more items
return nil, nil
}

func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}

if entry.Tag == dwarf.TagCompileUnit {
return entry, nil
}
}

return nil, nil
}
37 changes: 23 additions & 14 deletions proc/arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package proc
import "runtime"

type Arch interface {
SetCurGInstructions(ver GoVersion, iscgo bool)
PtrSize() int
BreakpointInstruction() []byte
BreakpointSize() int
Expand All @@ -20,10 +21,18 @@ type AMD64 struct {
}

func AMD64Arch() *AMD64 {
var (
curg []byte
breakInstr = []byte{0xCC}
)
var breakInstr = []byte{0xCC}

return &AMD64{
ptrSize: 8,
breakInstruction: breakInstr,
breakInstructionLen: len(breakInstr),
hardwareBreakpointUsage: make([]bool, 4),
}
}

func (a *AMD64) SetCurGInstructions(ver GoVersion, isextld bool) {
var curg []byte

switch runtime.GOOS {
case "darwin":
Expand All @@ -32,19 +41,19 @@ func AMD64Arch() *AMD64 {
0x0, 0x0,
}
case "linux":
curg = []byte{
0x64, 0x48, 0x8b, 0x0c, 0x25, 0xf0, 0xff, 0xff, 0xff, // mov %fs:0xfffffffffffffff0,%rcx
if isextld || ver.After(GoVersion{1, 5, 0}) {
curg = []byte{
0x64, 0x48, 0x8b, 0x0c, 0x25, 0xf8, 0xff, 0xff, 0xff, // mov %fs:0xfffffffffffffff8,%rcx
}
} else {
curg = []byte{
0x64, 0x48, 0x8b, 0x0c, 0x25, 0xf0, 0xff, 0xff, 0xff, // mov %fs:0xfffffffffffffff0,%rcx
}
}
}
curg = append(curg, breakInstr[0])
curg = append(curg, a.breakInstruction...)

return &AMD64{
ptrSize: 8,
breakInstruction: breakInstr,
breakInstructionLen: 1,
curgInstructions: curg,
hardwareBreakpointUsage: make([]bool, 4),
}
a.curgInstructions = curg
}

func (a *AMD64) PtrSize() int {
Expand Down
38 changes: 38 additions & 0 deletions proc/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,13 @@ func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, e
dbp.arch = AMD64Arch()
}

ver, isextld, err := dbp.getGoInformation()
if err != nil {
return nil, err
}

dbp.arch.SetCurGInstructions(ver, isextld)

return dbp, nil
}

Expand Down Expand Up @@ -674,3 +681,34 @@ func (dbp *Process) execPtraceFunc(fn func()) {
dbp.ptraceChan <- fn
<-dbp.ptraceDoneChan
}

func (dbp *Process) getGoInformation() (ver GoVersion, isextld bool, err error) {
th := dbp.Threads[dbp.Pid]

vv, err := th.EvalPackageVariable("runtime.buildVersion")
if err != nil {
err = fmt.Errorf("Could not determine version number: %v\n", err)
return
}

ver, ok := parseVersionString(vv.Value)
if !ok {
err = fmt.Errorf("Could not parse version number: %s\n", vv.Value)
}

isextld = false

rdr := dbp.DwarfReader()
rdr.Seek(0)
for entry, err := rdr.NextCompileUnit(); entry != nil; entry, err = rdr.NextCompileUnit() {
if err != nil {
return ver, isextld, err
}
if prod, ok := entry.Val(dwarf.AttrProducer).(string); ok && (strings.HasPrefix(prod, "GNU AS")) {
isextld = true
break
}
}

return
}
29 changes: 29 additions & 0 deletions proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,32 @@ func TestKill(t *testing.T) {
}
})
}

func testGSupportFunc(name string, t *testing.T, p *Process, fixture protest.Fixture) {
bp, err := p.SetBreakpointByLocation("main.main")
assertNoError(err, t, name+": BreakByLocation()")

assertNoError(p.Continue(), t, name+": Continue()")

g, err := p.CurrentThread.GetG()
assertNoError(err, t, name+": GetG()")

if g == nil {
t.Fatal(name + ": g was nil")
}

t.Logf(name+": g is: %v", g)

p.ClearBreakpoint(bp.Addr)
p.Kill()
}

func TestGetG(t *testing.T) {
withTestProcess("testprog", t, func(p *Process, fixture protest.Fixture) {
testGSupportFunc("nocgo", t, p, fixture)
})

withTestProcess("cgotest", t, func(p *Process, fixture protest.Fixture) {
testGSupportFunc("cgo", t, p, fixture)
})
}
31 changes: 26 additions & 5 deletions proc/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,27 @@ func (thread *Thread) PackageVariables() ([]*Variable, error) {
return vars, nil
}

func (thread *Thread) EvalPackageVariable(name string) (*Variable, error) {
reader := thread.dbp.DwarfReader()

for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
if err != nil {
return nil, err
}

n, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
continue
}

if n == name {
return thread.extractVariableFromEntry(entry)
}
}

return nil, fmt.Errorf("could not find symbol value for %s", name)
}

func (thread *Thread) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) {
parentAddr, err := thread.extractVariableDataAddress(parentEntry, rdr)
if err != nil {
Expand Down Expand Up @@ -387,13 +408,13 @@ func (thread *Thread) executeStackProgram(instructions []byte) (int64, error) {
return 0, err
}

var cfa int64 = 0

fde, err := thread.dbp.frameEntries.FDEForPC(regs.PC())
if err != nil {
return 0, err
if err == nil {
fctx := fde.EstablishFrame(regs.PC())
cfa = fctx.CFAOffset() + int64(regs.SP())
}

fctx := fde.EstablishFrame(regs.PC())
cfa := fctx.CFAOffset() + int64(regs.SP())
address, err := op.ExecuteStackProgram(cfa, instructions)
if err != nil {
return 0, err
Expand Down
54 changes: 54 additions & 0 deletions proc/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package proc

import (
"strconv"
"strings"
)

type GoVersion struct {
Major int
Minor int
Rev int
}

func parseVersionString(ver string) (GoVersion, bool) {
if ver[:2] != "go" {
return GoVersion{}, false
}
v := strings.SplitN(ver[2:], ".", 3)
if len(v) != 3 {
return GoVersion{}, false
}

var r GoVersion
var err1, err2, err3 error

r.Major, err1 = strconv.Atoi(v[0])
r.Minor, err2 = strconv.Atoi(v[1])
r.Rev, err3 = strconv.Atoi(v[2])
if err1 != nil || err2 != nil || err3 != nil {
return GoVersion{}, false
}

return r, true
}

func (a *GoVersion) After(b GoVersion) bool {
if a.Major < b.Major {
return false
} else if a.Major > b.Major {
return true
}

if a.Minor < b.Minor {
return false
} else if a.Minor > b.Minor {
return true
}

if a.Rev < b.Rev {
return false
}

return true
}

0 comments on commit bd13e32

Please sign in to comment.