Merge pull request #806 from cpunion/llvm-debug
Debug: fix struct vars debug, params modication, supports expressions, lexical scope/lifecycle
This commit is contained in:
@@ -78,9 +78,10 @@ func FuncWithAllTypeStructParam(s StructWithAllTypeFields) {
|
||||
// s.e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
// s.pad1: 100
|
||||
// s.pad2: 200
|
||||
s.i8 = 8
|
||||
// Expected(skio):
|
||||
// s.i8: '\x08'
|
||||
s.i8 = '\b'
|
||||
// Expected:
|
||||
// s.i8: '\b'
|
||||
// s.i16: 2
|
||||
println(len(s.s), s.i8)
|
||||
}
|
||||
|
||||
@@ -115,6 +116,36 @@ func FuncWithAllTypeParams(
|
||||
err error,
|
||||
fn func(string) (int, error),
|
||||
) (int, error) {
|
||||
// Expected:
|
||||
// all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn
|
||||
// i32: 3
|
||||
// i64: 4
|
||||
// i: 5
|
||||
// u32: 8
|
||||
// u64: 9
|
||||
// u: 10
|
||||
// f32: 11
|
||||
// f64: 12
|
||||
// slice: []int{21, 22, 23}
|
||||
// arr: [3]int{24, 25, 26}
|
||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// slice[0]: 21
|
||||
// slice[1]: 22
|
||||
// slice[2]: 23
|
||||
// arr[0]: 24
|
||||
// arr[1]: 25
|
||||
// arr[2]: 26
|
||||
// arr2[0].i: 27
|
||||
// arr2[1].i: 28
|
||||
// arr2[2].i: 29
|
||||
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
|
||||
// Expected(skip):
|
||||
// i8: '\b'
|
||||
// i16: 2
|
||||
// u8: '\x06'
|
||||
// u16: 7
|
||||
// b: true
|
||||
println(
|
||||
i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
||||
f32, f64, b,
|
||||
@@ -127,32 +158,61 @@ func FuncWithAllTypeParams(
|
||||
err,
|
||||
fn,
|
||||
)
|
||||
// Expected:
|
||||
// all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn
|
||||
// i8: '\x01'
|
||||
// i16: 2
|
||||
// i32: 3
|
||||
// i64: 4
|
||||
// i: 5
|
||||
// u8: '\x06'
|
||||
// u16: 7
|
||||
// u32: 8
|
||||
// u64: 9
|
||||
// u: 10
|
||||
// f32: 11
|
||||
// f64: 12
|
||||
// b: true
|
||||
// c64: complex64{real = 13, imag = 14}
|
||||
// c128: complex128{real = 15, imag = 16}
|
||||
// slice: []int{21, 22, 23}
|
||||
// arr: [3]int{24, 25, 26}
|
||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// s: "hello"
|
||||
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
i8 = 9
|
||||
i16 = 10
|
||||
i32 = 11
|
||||
i64 = 12
|
||||
i = 13
|
||||
u8 = 14
|
||||
u16 = 15
|
||||
u32 = 16
|
||||
u64 = 17
|
||||
u = 18
|
||||
f32 = 19
|
||||
f64 = 20
|
||||
b = false
|
||||
c64 = 21 + 22i
|
||||
c128 = 23 + 24i
|
||||
slice = []int{31, 32, 33}
|
||||
arr = [3]int{34, 35, 36}
|
||||
arr2 = [3]E{{i: 37}, {i: 38}, {i: 39}}
|
||||
s = "world"
|
||||
e = E{i: 40}
|
||||
|
||||
println(i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
||||
f32, f64, b,
|
||||
c64, c128,
|
||||
slice, arr[0:], &arr2,
|
||||
s,
|
||||
&e,
|
||||
&f, pf, pi, intr, m,
|
||||
c,
|
||||
err,
|
||||
fn,
|
||||
)
|
||||
// Expected:
|
||||
// i8: '\t'
|
||||
// i16: 10
|
||||
// i32: 11
|
||||
// i64: 12
|
||||
// i: 13
|
||||
// u8: '\x0e'
|
||||
// u16: 15
|
||||
// u32: 16
|
||||
// u64: 17
|
||||
// u: 18
|
||||
// f32: 19
|
||||
// f64: 20
|
||||
// b: false
|
||||
// c64: complex64{real = 21, imag = 22}
|
||||
// c128: complex128{real = 23, imag = 24}
|
||||
// slice: []int{31, 32, 33}
|
||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 37}, {i = 38}, {i = 39}}
|
||||
// s: "world"
|
||||
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 40}
|
||||
|
||||
// Expected(skip):
|
||||
// i8: '\x09'
|
||||
println(i8)
|
||||
// arr: [3]int{34, 35, 36}
|
||||
return 1, errors.New("some error")
|
||||
}
|
||||
|
||||
@@ -185,7 +245,7 @@ type BigStruct struct {
|
||||
}
|
||||
|
||||
func FuncStructParams(t TinyStruct, s SmallStruct, m MidStruct, b BigStruct) {
|
||||
println(&t, &s, &m, &b)
|
||||
// println(&t, &s, &m, &b)
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 1
|
||||
@@ -204,15 +264,45 @@ func FuncStructParams(t TinyStruct, s SmallStruct, m MidStruct, b BigStruct) {
|
||||
// b.P: 14
|
||||
// b.Q: 15
|
||||
// b.R: 16
|
||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
||||
t.I = 10
|
||||
// Expected(skip):
|
||||
s.I = 20
|
||||
s.J = 21
|
||||
m.I = 40
|
||||
m.J = 41
|
||||
m.K = 42
|
||||
b.I = 70
|
||||
b.J = 71
|
||||
b.K = 72
|
||||
b.L = 73
|
||||
b.M = 74
|
||||
b.N = 75
|
||||
b.O = 76
|
||||
b.P = 77
|
||||
b.Q = 78
|
||||
b.R = 79
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 10
|
||||
// s.I: 20
|
||||
// s.J: 21
|
||||
// m.I: 40
|
||||
// m.J: 41
|
||||
// m.K: 42
|
||||
// b.I: 70
|
||||
// b.J: 71
|
||||
// b.K: 72
|
||||
// b.L: 73
|
||||
// b.M: 74
|
||||
// b.N: 75
|
||||
// b.O: 76
|
||||
// b.P: 77
|
||||
// b.Q: 78
|
||||
// b.R: 79
|
||||
println("done")
|
||||
}
|
||||
|
||||
func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStruct) {
|
||||
println(t, s, m, b)
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 1
|
||||
@@ -231,13 +321,139 @@ func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStru
|
||||
// b.P: 14
|
||||
// b.Q: 15
|
||||
// b.R: 16
|
||||
println(t, s, m, b)
|
||||
t.I = 10
|
||||
s.I = 20
|
||||
s.J = 21
|
||||
m.I = 40
|
||||
m.J = 41
|
||||
m.K = 42
|
||||
b.I = 70
|
||||
b.J = 71
|
||||
b.K = 72
|
||||
b.L = 73
|
||||
b.M = 74
|
||||
b.N = 75
|
||||
b.O = 76
|
||||
b.P = 77
|
||||
b.Q = 78
|
||||
b.R = 79
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 10
|
||||
// s.I: 20
|
||||
// s.J: 21
|
||||
// m.I: 40
|
||||
// m.J: 41
|
||||
// m.K: 42
|
||||
// b.I: 70
|
||||
// b.J: 71
|
||||
// b.K: 72
|
||||
// b.L: 73
|
||||
// b.M: 74
|
||||
// b.N: 75
|
||||
// b.O: 76
|
||||
// b.P: 77
|
||||
// b.Q: 78
|
||||
// b.R: 79
|
||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
||||
println("done")
|
||||
}
|
||||
|
||||
func ScopeIf(branch int) {
|
||||
a := 1
|
||||
// Expected:
|
||||
// all variables: a branch
|
||||
// a: 1
|
||||
if branch == 1 {
|
||||
b := 2
|
||||
c := 3
|
||||
// Expected:
|
||||
// all variables: a b c branch
|
||||
// a: 1
|
||||
// b: 2
|
||||
// c: 3
|
||||
// branch: 1
|
||||
println(a, b, c)
|
||||
} else {
|
||||
c := 3
|
||||
d := 4
|
||||
// Expected:
|
||||
// all variables: a c d branch
|
||||
// a: 1
|
||||
// c: 3
|
||||
// d: 4
|
||||
// branch: 0
|
||||
println(a, c, d)
|
||||
}
|
||||
// Expected:
|
||||
// all variables: a branch
|
||||
// a: 1
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func ScopeFor() {
|
||||
a := 1
|
||||
for i := 0; i < 10; i++ {
|
||||
switch i {
|
||||
case 0:
|
||||
println("i is 0")
|
||||
// Expected:
|
||||
// all variables: i a
|
||||
// i: 0
|
||||
// a: 1
|
||||
println("i:", i)
|
||||
case 1:
|
||||
println("i is 1")
|
||||
// Expected:
|
||||
// all variables: i a
|
||||
// i: 1
|
||||
// a: 1
|
||||
println("i:", i)
|
||||
default:
|
||||
println("i is", i)
|
||||
}
|
||||
}
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func ScopeSwitch(i int) {
|
||||
a := 0
|
||||
switch i {
|
||||
case 1:
|
||||
b := 1
|
||||
println("i is 1")
|
||||
// Expected:
|
||||
// all variables: i a b
|
||||
// i: 1
|
||||
// a: 0
|
||||
// b: 1
|
||||
println("i:", i, "a:", a, "b:", b)
|
||||
case 2:
|
||||
c := 2
|
||||
println("i is 2")
|
||||
// Expected:
|
||||
// all variables: i a c
|
||||
// i: 2
|
||||
// a: 0
|
||||
// c: 2
|
||||
println("i:", i, "a:", a, "c:", c)
|
||||
default:
|
||||
d := 3
|
||||
println("i is", i)
|
||||
// Expected:
|
||||
// all variables: i a d
|
||||
// i: 3
|
||||
// a: 0
|
||||
// d: 3
|
||||
println("i:", i, "a:", a, "d:", d)
|
||||
}
|
||||
// Expected:
|
||||
// all variables: a i
|
||||
// a: 0
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
FuncStructParams(TinyStruct{I: 1}, SmallStruct{I: 2, J: 3}, MidStruct{I: 4, J: 5, K: 6}, BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
||||
FuncStructPtrParams(&TinyStruct{I: 1}, &SmallStruct{I: 2, J: 3}, &MidStruct{I: 4, J: 5, K: 6}, &BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
||||
@@ -263,7 +479,7 @@ func main() {
|
||||
arr2: [3]E{{i: 27}, {i: 28}, {i: 29}},
|
||||
s: "hello",
|
||||
e: E{i: 30},
|
||||
pf: &StructWithAllTypeFields{},
|
||||
pf: &StructWithAllTypeFields{i16: 100},
|
||||
pi: &i,
|
||||
intr: &Struct{},
|
||||
m: map[string]uint64{"a": 31, "b": 32},
|
||||
@@ -277,9 +493,36 @@ func main() {
|
||||
pad1: 100,
|
||||
pad2: 200,
|
||||
}
|
||||
// Expected:
|
||||
// all variables: s i err
|
||||
// s.i8: '\x01'
|
||||
// s.i16: 2
|
||||
// s.i32: 3
|
||||
// s.i64: 4
|
||||
// s.i: 5
|
||||
// s.u8: '\x06'
|
||||
// s.u16: 7
|
||||
// s.u32: 8
|
||||
// s.u64: 9
|
||||
// s.u: 10
|
||||
// s.f32: 11
|
||||
// s.f64: 12
|
||||
// s.b: true
|
||||
// s.c64: complex64{real = 13, imag = 14}
|
||||
// s.c128: complex128{real = 15, imag = 16}
|
||||
// s.slice: []int{21, 22, 23}
|
||||
// s.arr: [3]int{24, 25, 26}
|
||||
// s.arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// s.s: "hello"
|
||||
// s.e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
// s.pf.i16: 100
|
||||
// *(s.pf).i16: 100
|
||||
// *(s.pi): 100
|
||||
globalStructPtr = &s
|
||||
globalStruct = s
|
||||
println("globalInt:", globalInt)
|
||||
// Expected(skip):
|
||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
||||
println("s:", &s)
|
||||
FuncWithAllTypeStructParam(s)
|
||||
println("called function with struct")
|
||||
@@ -298,18 +541,21 @@ func main() {
|
||||
s.fn,
|
||||
)
|
||||
println(i, err)
|
||||
println("called function with types")
|
||||
ScopeIf(1)
|
||||
ScopeIf(0)
|
||||
ScopeFor()
|
||||
ScopeSwitch(1)
|
||||
ScopeSwitch(2)
|
||||
ScopeSwitch(3)
|
||||
println(globalStructPtr)
|
||||
println(&globalStruct)
|
||||
// Expected(skip):
|
||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
||||
// s.i8: '\x01'
|
||||
// s.i16: 2
|
||||
s.i8 = 0x12
|
||||
println(s.i8)
|
||||
// Expected(skip):
|
||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
||||
// Expected:
|
||||
// all variables: s i err
|
||||
// s.i8: '\x12'
|
||||
|
||||
// Expected(skip):
|
||||
// globalStruct.i8: '\x01'
|
||||
println((*globalStructPtr).i8)
|
||||
println("done")
|
||||
|
||||
@@ -238,6 +238,9 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
||||
sig = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||
}
|
||||
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, f.Origin() != nil)
|
||||
if debugSymbols {
|
||||
fn.Inline(llssa.NoInline)
|
||||
}
|
||||
}
|
||||
|
||||
if nblk := len(f.Blocks); nblk > 0 {
|
||||
@@ -260,8 +263,9 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
||||
}
|
||||
b := fn.NewBuilder()
|
||||
if debugSymbols {
|
||||
b.DebugFunction(fn, p.goProg.Fset.Position(f.Pos()))
|
||||
b.DISetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(f.Pos()))
|
||||
pos := p.goProg.Fset.Position(f.Pos())
|
||||
bodyPos := p.getFuncBodyPos(f)
|
||||
b.DebugFunction(fn, pos, bodyPos)
|
||||
}
|
||||
p.bvals = make(map[ssa.Value]llssa.Expr)
|
||||
off := make([]int, len(f.Blocks))
|
||||
@@ -291,14 +295,56 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
||||
return fn, nil, goFunc
|
||||
}
|
||||
|
||||
func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
|
||||
if f.Object() != nil {
|
||||
return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos())
|
||||
}
|
||||
return p.goProg.Fset.Position(f.Pos())
|
||||
}
|
||||
|
||||
func isGlobal(v *types.Var) bool {
|
||||
// TODO(lijie): better implementation
|
||||
return strings.HasPrefix(v.Parent().String(), "package ")
|
||||
}
|
||||
|
||||
func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) {
|
||||
object := v.Object()
|
||||
variable, ok := object.(*types.Var)
|
||||
if !ok {
|
||||
// Not a local variable.
|
||||
return
|
||||
}
|
||||
if variable.IsField() {
|
||||
// skip *ssa.FieldAddr
|
||||
return
|
||||
}
|
||||
if isGlobal(variable) {
|
||||
// avoid generate local variable debug info of global variable in function
|
||||
return
|
||||
}
|
||||
pos := p.goProg.Fset.Position(v.Pos())
|
||||
value := p.compileValue(b, v.X)
|
||||
fn := v.Parent()
|
||||
dbgVar := p.getLocalVariable(b, fn, variable)
|
||||
scope := variable.Parent()
|
||||
diScope := b.DIScope(p.fn, scope)
|
||||
if v.IsAddr {
|
||||
// *ssa.Alloc
|
||||
b.DIDeclare(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
|
||||
} else {
|
||||
b.DIValue(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *context) debugParams(b llssa.Builder, f *ssa.Function) {
|
||||
for i, param := range f.Params {
|
||||
variable := param.Object().(*types.Var)
|
||||
pos := p.goProg.Fset.Position(param.Pos())
|
||||
v := p.compileValue(b, param)
|
||||
ty := param.Type()
|
||||
argNo := i + 1
|
||||
div := b.DIVarParam(p.fn, pos, param.Name(), p.prog.Type(ty, llssa.InGo), argNo)
|
||||
b.DIDeclare(v, div, p.fn, pos, p.fn.Block(0))
|
||||
b.DIParam(variable, v, div, p.fn, pos, p.fn.Block(0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,11 +529,6 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
||||
}
|
||||
log.Panicln("unreachable:", iv)
|
||||
}
|
||||
if debugSymbols {
|
||||
if v, ok := iv.(ssa.Instruction); ok {
|
||||
b.DISetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(v.Pos()))
|
||||
}
|
||||
}
|
||||
switch v := iv.(type) {
|
||||
case *ssa.Call:
|
||||
ret = p.call(b, llssa.Call, &v.Call)
|
||||
@@ -655,11 +696,27 @@ func (p *context) jumpTo(v *ssa.Jump) llssa.BasicBlock {
|
||||
return fn.Block(succs[0].Index)
|
||||
}
|
||||
|
||||
func (p *context) getDebugLocScope(v *ssa.Function, pos token.Pos) *types.Scope {
|
||||
if v.Object() == nil {
|
||||
return nil
|
||||
}
|
||||
funcScope := v.Object().(*types.Func).Scope()
|
||||
return funcScope.Innermost(pos)
|
||||
}
|
||||
|
||||
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
||||
if iv, ok := instr.(instrOrValue); ok {
|
||||
p.compileInstrOrValue(b, iv, false)
|
||||
return
|
||||
}
|
||||
if debugSymbols {
|
||||
scope := p.getDebugLocScope(instr.Parent(), instr.Pos())
|
||||
if scope != nil {
|
||||
diScope := b.DIScope(p.fn, scope)
|
||||
pos := p.fset.Position(instr.Pos())
|
||||
b.DISetCurrentDebugLocation(diScope, pos)
|
||||
}
|
||||
}
|
||||
switch v := instr.(type) {
|
||||
case *ssa.Store:
|
||||
va := v.Addr
|
||||
@@ -720,26 +777,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
||||
b.Send(ch, x)
|
||||
case *ssa.DebugRef:
|
||||
if debugSymbols {
|
||||
object := v.Object()
|
||||
variable, ok := object.(*types.Var)
|
||||
if !ok {
|
||||
// Not a local variable.
|
||||
return
|
||||
}
|
||||
if variable.IsField() {
|
||||
// skip *ssa.FieldAddr
|
||||
return
|
||||
}
|
||||
pos := p.goProg.Fset.Position(v.Pos())
|
||||
value := p.compileValue(b, v.X)
|
||||
fn := v.Parent()
|
||||
dbgVar := p.getLocalVariable(b, fn, variable)
|
||||
if v.IsAddr {
|
||||
// *ssa.Alloc
|
||||
b.DIDeclare(value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index))
|
||||
} else {
|
||||
b.DIValue(value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index))
|
||||
}
|
||||
p.debugRef(b, v)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
||||
@@ -755,7 +793,8 @@ func (p *context) getLocalVariable(b llssa.Builder, fn *ssa.Function, v *types.V
|
||||
return b.DIVarParam(p.fn, pos, v.Name(), t, argNo)
|
||||
}
|
||||
}
|
||||
return b.DIVarAuto(p.fn, pos, v.Name(), t)
|
||||
scope := b.DIScope(p.fn, v.Parent())
|
||||
return b.DIVarAuto(scope, pos, v.Name(), t)
|
||||
}
|
||||
|
||||
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) {
|
||||
|
||||
@@ -273,6 +273,9 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
|
||||
}
|
||||
sig := fn.Signature
|
||||
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil)
|
||||
if debugSymbols {
|
||||
aFn.Inline(llssa.NoInline)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user