debug: supports scope (if, for)
This commit is contained in:
@@ -93,7 +93,7 @@ def print_all_variables(debugger: lldb.SBDebugger, _command: str, result: lldb.S
|
|||||||
|
|
||||||
frame = debugger.GetSelectedTarget().GetProcess(
|
frame = debugger.GetSelectedTarget().GetProcess(
|
||||||
).GetSelectedThread().GetSelectedFrame()
|
).GetSelectedThread().GetSelectedFrame()
|
||||||
variables = frame.GetVariables(True, True, True, False)
|
variables = frame.GetVariables(True, True, True, True)
|
||||||
|
|
||||||
output: List[str] = []
|
output: List[str] = []
|
||||||
for var in variables:
|
for var in variables:
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class LLDBDebugger:
|
|||||||
|
|
||||||
def get_all_variable_names(self) -> Set[str]:
|
def get_all_variable_names(self) -> Set[str]:
|
||||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
||||||
return set(var.GetName() for var in frame.GetVariables(True, True, True, False))
|
return set(var.GetName() for var in frame.GetVariables(True, True, True, True))
|
||||||
|
|
||||||
def get_current_function_name(self) -> str:
|
def get_current_function_name(self) -> str:
|
||||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
||||||
|
|||||||
@@ -118,26 +118,33 @@ func FuncWithAllTypeParams(
|
|||||||
) (int, error) {
|
) (int, error) {
|
||||||
// Expected:
|
// 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
|
// 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
|
// i32: 3
|
||||||
// i64: 4
|
// i64: 4
|
||||||
// i: 5
|
// i: 5
|
||||||
// u8: '\x06'
|
|
||||||
// u16: 7
|
|
||||||
// u32: 8
|
// u32: 8
|
||||||
// u64: 9
|
// u64: 9
|
||||||
// u: 10
|
// u: 10
|
||||||
// f32: 11
|
// f32: 11
|
||||||
// f64: 12
|
// f64: 12
|
||||||
// b: true
|
|
||||||
// c64: complex64{real = 13, imag = 14}
|
|
||||||
// c128: complex128{real = 15, imag = 16}
|
|
||||||
// slice: []int{21, 22, 23}
|
// slice: []int{21, 22, 23}
|
||||||
// arr: [3]int{24, 25, 26}
|
// arr: [3]int{24, 25, 26}
|
||||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
// 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}
|
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||||
|
// i8: '\b'
|
||||||
|
// i16: 2
|
||||||
|
// u8: '\x06'
|
||||||
|
// u16: 7
|
||||||
|
// b: true
|
||||||
|
// c64: complex64{real = 13, imag = 14}
|
||||||
|
// c128: complex128{real = 15, imag = 16}
|
||||||
|
// s: "hello"
|
||||||
|
|
||||||
|
// Expected(skip):
|
||||||
|
// i8: '\b'
|
||||||
|
// i16: 2
|
||||||
|
// u8: '\x06'
|
||||||
|
// u16: 7
|
||||||
|
// b: true
|
||||||
println(
|
println(
|
||||||
i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
||||||
f32, f64, b,
|
f32, f64, b,
|
||||||
@@ -352,6 +359,63 @@ func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStru
|
|||||||
println("done")
|
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(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 main() {
|
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})
|
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})
|
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})
|
||||||
@@ -392,7 +456,7 @@ func main() {
|
|||||||
pad2: 200,
|
pad2: 200,
|
||||||
}
|
}
|
||||||
// Expected:
|
// Expected:
|
||||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
// all variables: s i err
|
||||||
// s.i8: '\x01'
|
// s.i8: '\x01'
|
||||||
// s.i16: 2
|
// s.i16: 2
|
||||||
// s.i32: 3
|
// s.i32: 3
|
||||||
@@ -419,6 +483,8 @@ func main() {
|
|||||||
globalStructPtr = &s
|
globalStructPtr = &s
|
||||||
globalStruct = s
|
globalStruct = s
|
||||||
println("globalInt:", globalInt)
|
println("globalInt:", globalInt)
|
||||||
|
// Expected(skip):
|
||||||
|
// all variables: globalInt globalStruct globalStructPtr s i err
|
||||||
println("s:", &s)
|
println("s:", &s)
|
||||||
FuncWithAllTypeStructParam(s)
|
FuncWithAllTypeStructParam(s)
|
||||||
println("called function with struct")
|
println("called function with struct")
|
||||||
@@ -437,14 +503,18 @@ func main() {
|
|||||||
s.fn,
|
s.fn,
|
||||||
)
|
)
|
||||||
println(i, err)
|
println(i, err)
|
||||||
println("called function with types")
|
ScopeIf(1)
|
||||||
|
ScopeIf(0)
|
||||||
|
ScopeFor()
|
||||||
println(globalStructPtr)
|
println(globalStructPtr)
|
||||||
println(&globalStruct)
|
println(&globalStruct)
|
||||||
s.i8 = 0x12
|
s.i8 = 0x12
|
||||||
println(s.i8)
|
println(s.i8)
|
||||||
// Expected:
|
// Expected:
|
||||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
// all variables: s i err
|
||||||
// s.i8: '\x12'
|
// s.i8: '\x12'
|
||||||
|
|
||||||
|
// Expected(skip):
|
||||||
// globalStruct.i8: '\x01'
|
// globalStruct.i8: '\x01'
|
||||||
println((*globalStructPtr).i8)
|
println((*globalStructPtr).i8)
|
||||||
println("done")
|
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)
|
sig = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||||
}
|
}
|
||||||
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, f.Origin() != nil)
|
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 {
|
if nblk := len(f.Blocks); nblk > 0 {
|
||||||
@@ -292,18 +295,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
|||||||
return fn, nil, goFunc
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) getDebugPosition(f *ssa.Function, pos token.Pos) token.Position {
|
|
||||||
ppos := p.goProg.Fset.Position(pos)
|
|
||||||
bodyPos := p.getFuncBodyPos(f)
|
|
||||||
if bodyPos.Filename == "" {
|
|
||||||
return ppos
|
|
||||||
}
|
|
||||||
if ppos.Line < bodyPos.Line {
|
|
||||||
return bodyPos
|
|
||||||
}
|
|
||||||
return ppos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
|
func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
|
||||||
if f.Object() != nil {
|
if f.Object() != nil {
|
||||||
return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos())
|
return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos())
|
||||||
@@ -311,6 +302,11 @@ func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
|
|||||||
return p.goProg.Fset.Position(f.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) {
|
func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) {
|
||||||
object := v.Object()
|
object := v.Object()
|
||||||
variable, ok := object.(*types.Var)
|
variable, ok := object.(*types.Var)
|
||||||
@@ -322,15 +318,21 @@ func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) {
|
|||||||
// skip *ssa.FieldAddr
|
// skip *ssa.FieldAddr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if isGlobal(variable) {
|
||||||
|
// avoid generate local variable debug info of global variable in function
|
||||||
|
return
|
||||||
|
}
|
||||||
pos := p.goProg.Fset.Position(v.Pos())
|
pos := p.goProg.Fset.Position(v.Pos())
|
||||||
value := p.compileValue(b, v.X)
|
value := p.compileValue(b, v.X)
|
||||||
fn := v.Parent()
|
fn := v.Parent()
|
||||||
dbgVar := p.getLocalVariable(b, fn, variable)
|
dbgVar := p.getLocalVariable(b, fn, variable)
|
||||||
|
scope := variable.Parent()
|
||||||
|
diScope := b.DIScope(p.fn, scope)
|
||||||
if v.IsAddr {
|
if v.IsAddr {
|
||||||
// *ssa.Alloc
|
// *ssa.Alloc
|
||||||
b.DIDeclare(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index))
|
b.DIDeclare(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
|
||||||
} else {
|
} else {
|
||||||
b.DIValue(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index))
|
b.DIValue(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,10 +529,6 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
}
|
}
|
||||||
log.Panicln("unreachable:", iv)
|
log.Panicln("unreachable:", iv)
|
||||||
}
|
}
|
||||||
if debugSymbols {
|
|
||||||
pos := p.getDebugPosition(iv.Parent(), iv.Pos())
|
|
||||||
b.DISetCurrentDebugLocation(p.fn, pos)
|
|
||||||
}
|
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
ret = p.call(b, llssa.Call, &v.Call)
|
ret = p.call(b, llssa.Call, &v.Call)
|
||||||
@@ -698,11 +696,27 @@ func (p *context) jumpTo(v *ssa.Jump) llssa.BasicBlock {
|
|||||||
return fn.Block(succs[0].Index)
|
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) {
|
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
||||||
if iv, ok := instr.(instrOrValue); ok {
|
if iv, ok := instr.(instrOrValue); ok {
|
||||||
p.compileInstrOrValue(b, iv, false)
|
p.compileInstrOrValue(b, iv, false)
|
||||||
return
|
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) {
|
switch v := instr.(type) {
|
||||||
case *ssa.Store:
|
case *ssa.Store:
|
||||||
va := v.Addr
|
va := v.Addr
|
||||||
@@ -779,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.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) {
|
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) {
|
||||||
|
|||||||
@@ -267,6 +267,9 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
|
|||||||
}
|
}
|
||||||
sig := fn.Signature
|
sig := fn.Signature
|
||||||
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil)
|
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil)
|
||||||
|
if debugSymbols {
|
||||||
|
aFn.Inline(llssa.NoInline)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
23
ssa/decl.go
23
ssa/decl.go
@@ -273,7 +273,8 @@ func (p Function) NewBuilder() Builder {
|
|||||||
b := prog.ctx.NewBuilder()
|
b := prog.ctx.NewBuilder()
|
||||||
// TODO(xsw): Finalize may cause panic, so comment it.
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
// b.Finalize()
|
// b.Finalize()
|
||||||
return &aBuilder{b, nil, p, p.Pkg, prog, make(map[Expr]dbgExpr)}
|
return &aBuilder{b, nil, p, p.Pkg, prog,
|
||||||
|
make(map[Expr]dbgExpr), make(map[*types.Scope]DIScope)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasBody reports whether the function has a body.
|
// HasBody reports whether the function has a body.
|
||||||
@@ -327,3 +328,23 @@ func (p Function) SetRecover(blk BasicBlock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type inlineAttr int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoInline inlineAttr = iota
|
||||||
|
AlwaysInline
|
||||||
|
InlineHint
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Function) Inline(inline inlineAttr) {
|
||||||
|
inlineAttrName := map[inlineAttr]string{
|
||||||
|
NoInline: "noinline",
|
||||||
|
AlwaysInline: "alwaysinline",
|
||||||
|
InlineHint: "inlinehint",
|
||||||
|
}[inline]
|
||||||
|
inlineAttr := p.Pkg.mod.Context().CreateEnumAttribute(llvm.AttributeKindID(inlineAttrName), 0)
|
||||||
|
p.impl.AddFunctionAttr(inlineAttr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
186
ssa/di.go
186
ssa/di.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,7 @@ type aDIBuilder struct {
|
|||||||
prog Program
|
prog Program
|
||||||
types map[Type]DIType
|
types map[Type]DIType
|
||||||
positioner Positioner
|
positioner Positioner
|
||||||
|
m llvm.Module // Add this field
|
||||||
}
|
}
|
||||||
|
|
||||||
type diBuilder = *aDIBuilder
|
type diBuilder = *aDIBuilder
|
||||||
@@ -26,20 +28,21 @@ type diBuilder = *aDIBuilder
|
|||||||
func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
|
func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
|
||||||
m := pkg.mod
|
m := pkg.mod
|
||||||
ctx := m.Context()
|
ctx := m.Context()
|
||||||
m.AddNamedMetadataOperand("llvm.module.flags",
|
|
||||||
ctx.MDNode([]llvm.Metadata{
|
b := &aDIBuilder{
|
||||||
llvm.ConstInt(ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch
|
di: llvm.NewDIBuilder(m),
|
||||||
ctx.MDString("Debug Info Version"),
|
prog: prog,
|
||||||
llvm.ConstInt(ctx.Int32Type(), 3, false).ConstantAsMetadata(),
|
types: make(map[*aType]DIType),
|
||||||
}),
|
positioner: positioner,
|
||||||
)
|
m: m, // Initialize the m field
|
||||||
m.AddNamedMetadataOperand("llvm.module.flags",
|
}
|
||||||
ctx.MDNode([]llvm.Metadata{
|
|
||||||
llvm.ConstInt(ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch
|
b.addNamedMetadataOperand("llvm.module.flags", 2, "Debug Info Version", 3)
|
||||||
ctx.MDString("Dwarf Version"),
|
b.addNamedMetadataOperand("llvm.module.flags", 7, "Dwarf Version", 5)
|
||||||
llvm.ConstInt(ctx.Int32Type(), 5, false).ConstantAsMetadata(),
|
b.addNamedMetadataOperand("llvm.module.flags", 1, "wchar_size", 4)
|
||||||
}),
|
b.addNamedMetadataOperand("llvm.module.flags", 8, "PIC Level", 2)
|
||||||
)
|
b.addNamedMetadataOperand("llvm.module.flags", 7, "uwtable", 1)
|
||||||
|
b.addNamedMetadataOperand("llvm.module.flags", 7, "frame-pointer", 1)
|
||||||
|
|
||||||
// Add llvm.ident metadata
|
// Add llvm.ident metadata
|
||||||
identNode := ctx.MDNode([]llvm.Metadata{
|
identNode := ctx.MDNode([]llvm.Metadata{
|
||||||
@@ -47,12 +50,19 @@ func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
|
|||||||
})
|
})
|
||||||
m.AddNamedMetadataOperand("llvm.ident", identNode)
|
m.AddNamedMetadataOperand("llvm.ident", identNode)
|
||||||
|
|
||||||
return &aDIBuilder{
|
return b
|
||||||
di: llvm.NewDIBuilder(m),
|
}
|
||||||
prog: prog,
|
|
||||||
types: make(map[*aType]DIType),
|
// New method to add named metadata operand
|
||||||
positioner: positioner,
|
func (b diBuilder) addNamedMetadataOperand(name string, intValue int, stringValue string, intValue2 int) {
|
||||||
}
|
ctx := b.m.Context()
|
||||||
|
b.m.AddNamedMetadataOperand(name,
|
||||||
|
ctx.MDNode([]llvm.Metadata{
|
||||||
|
llvm.ConstInt(ctx.Int32Type(), uint64(intValue), false).ConstantAsMetadata(),
|
||||||
|
ctx.MDString(stringValue),
|
||||||
|
llvm.ConstInt(ctx.Int32Type(), uint64(intValue2), false).ConstantAsMetadata(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -225,16 +235,28 @@ func (b diBuilder) createGlobalVariableExpression(scope DIScope, pos token.Posit
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type aDILexicalBlock struct {
|
||||||
|
ll llvm.Metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
type DILexicalBlock = *aDILexicalBlock
|
||||||
|
|
||||||
|
func (l *aDILexicalBlock) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
|
||||||
|
return &aDIScopeMeta{l.ll}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
type aDIVar struct {
|
type aDIVar struct {
|
||||||
ll llvm.Metadata
|
ll llvm.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
type DIVar = *aDIVar
|
type DIVar = *aDIVar
|
||||||
|
|
||||||
func (b diBuilder) createParameterVariable(f Function, pos token.Position, name string, argNo int, ty DIType) DIVar {
|
func (b diBuilder) createParameterVariable(scope DIScope, pos token.Position, name string, argNo int, ty DIType) DIVar {
|
||||||
return &aDIVar{
|
return &aDIVar{
|
||||||
ll: b.di.CreateParameterVariable(
|
ll: b.di.CreateParameterVariable(
|
||||||
f.scopeMeta(b, pos).ll,
|
scope.scopeMeta(b, pos).ll,
|
||||||
llvm.DIParameterVariable{
|
llvm.DIParameterVariable{
|
||||||
Name: name,
|
Name: name,
|
||||||
File: b.file(pos.Filename).ll,
|
File: b.file(pos.Filename).ll,
|
||||||
@@ -513,9 +535,9 @@ func (b diBuilder) diTypeEx(name string, t Type, pos token.Position) DIType {
|
|||||||
return ty
|
return ty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b diBuilder) varParam(f Function, pos token.Position, varName string, vt DIType, argNo int) DIVar {
|
func (b diBuilder) varParam(scope DIScope, pos token.Position, varName string, vt DIType, argNo int) DIVar {
|
||||||
return b.createParameterVariable(
|
return b.createParameterVariable(
|
||||||
f,
|
scope,
|
||||||
pos,
|
pos,
|
||||||
varName,
|
varName,
|
||||||
argNo,
|
argNo,
|
||||||
@@ -523,8 +545,8 @@ func (b diBuilder) varParam(f Function, pos token.Position, varName string, vt D
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b diBuilder) varAuto(f Function, pos token.Position, varName string, vt DIType) DIVar {
|
func (b diBuilder) varAuto(scope DIScope, pos token.Position, varName string, vt DIType) DIVar {
|
||||||
return b.createAutoVariable(f, pos, varName, vt)
|
return b.createAutoVariable(scope, pos, varName, vt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b diBuilder) file(filename string) DIFile {
|
func (b diBuilder) file(filename string) DIFile {
|
||||||
@@ -546,21 +568,21 @@ func (b diBuilder) createExpression(ops []uint64) DIExpression {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Copy to alloca'd memory to get declareable address.
|
// Copy to alloca'd memory to get declareable address.
|
||||||
func (b Builder) constructDebugAddr(v Expr) (dbgPtr Expr, dbgVal Expr, deref bool) {
|
func (b Builder) constructDebugAddr(v Expr) (dbgPtr Expr, dbgVal Expr, exists bool) {
|
||||||
if v, ok := b.dbgVars[v]; ok {
|
if v, ok := b.dbgVars[v]; ok {
|
||||||
return v.ptr, v.val, v.deref
|
return v.ptr, v.val, true
|
||||||
}
|
}
|
||||||
t := v.Type.RawType().Underlying()
|
t := v.Type.RawType().Underlying()
|
||||||
dbgPtr, dbgVal, deref = b.doConstructDebugAddr(v, t)
|
dbgPtr, dbgVal = b.doConstructDebugAddr(v, t)
|
||||||
b.dbgVars[v] = dbgExpr{dbgPtr, dbgVal, deref}
|
dbgExpr := dbgExpr{dbgPtr, dbgVal}
|
||||||
return dbgPtr, dbgVal, deref
|
b.dbgVars[v] = dbgExpr
|
||||||
|
b.dbgVars[dbgVal] = dbgExpr
|
||||||
|
return dbgPtr, dbgVal, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal Expr, deref bool) {
|
func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal Expr) {
|
||||||
var ty Type
|
var ty Type
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case *types.Pointer:
|
|
||||||
return v, v, false
|
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
if t.Info()&types.IsComplex != 0 {
|
if t.Info()&types.IsComplex != 0 {
|
||||||
if t.Kind() == types.Complex128 {
|
if t.Kind() == types.Complex128 {
|
||||||
@@ -590,7 +612,7 @@ func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal
|
|||||||
dbgPtr.Type = b.Prog.Pointer(v.Type)
|
dbgPtr.Type = b.Prog.Pointer(v.Type)
|
||||||
b.Store(dbgPtr, v)
|
b.Store(dbgPtr, v)
|
||||||
dbgVal = b.Load(dbgPtr)
|
dbgVal = b.Load(dbgPtr)
|
||||||
return dbgPtr, dbgVal, deref
|
return dbgPtr, dbgVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) di() diBuilder {
|
func (b Builder) di() diBuilder {
|
||||||
@@ -598,13 +620,7 @@ func (b Builder) di() diBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) DIParam(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
func (b Builder) DIParam(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||||
ty := v.Type.RawType().Underlying()
|
b.DIValue(variable, v, dv, scope, pos, blk)
|
||||||
if isPtrType(ty) {
|
|
||||||
expr := b.di().createExpression(nil)
|
|
||||||
b.di().dbgDeclare(v, dv, scope, pos, expr, blk)
|
|
||||||
} else {
|
|
||||||
b.DIValue(variable, v, dv, scope, pos, blk)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||||
@@ -614,14 +630,13 @@ func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope,
|
|||||||
|
|
||||||
func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||||
ty := v.Type.RawType().Underlying()
|
ty := v.Type.RawType().Underlying()
|
||||||
if isPtrType(ty) {
|
if !needConstructAddr(ty) {
|
||||||
expr := b.di().createExpression(nil)
|
expr := b.di().createExpression(nil)
|
||||||
b.di().dbgValue(v, dv, scope, pos, expr, blk)
|
b.di().dbgValue(v, dv, scope, pos, expr, blk)
|
||||||
} else {
|
} else {
|
||||||
dbgPtr, dbgVal, _ := b.constructDebugAddr(v)
|
dbgPtr, _, _ := b.constructDebugAddr(v)
|
||||||
expr := b.di().createExpression([]uint64{opDeref})
|
expr := b.di().createExpression([]uint64{opDeref})
|
||||||
b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk)
|
b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk)
|
||||||
v.impl = dbgVal.impl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,25 +644,79 @@ const (
|
|||||||
opDeref = 0x06
|
opDeref = 0x06
|
||||||
)
|
)
|
||||||
|
|
||||||
func isPtrType(t types.Type) bool {
|
func needConstructAddr(t types.Type) bool {
|
||||||
switch t.(type) {
|
switch t := t.(type) {
|
||||||
case *types.Pointer:
|
case *types.Basic:
|
||||||
return true
|
if t.Info()&types.IsComplex != 0 {
|
||||||
default:
|
return true
|
||||||
|
} else if t.Info()&types.IsString != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
|
case *types.Pointer:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) DIVarParam(f Function, pos token.Position, varName string, vt Type, argNo int) DIVar {
|
func (b Builder) DIVarParam(scope DIScope, pos token.Position, varName string, vt Type, argNo int) DIVar {
|
||||||
t := b.di().diType(vt, pos)
|
t := b.di().diType(vt, pos)
|
||||||
return b.di().varParam(f, pos, varName, t, argNo)
|
return b.di().varParam(scope, pos, varName, t, argNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) DIVarAuto(f Function, pos token.Position, varName string, vt Type) DIVar {
|
func (b Builder) DIVarAuto(scope DIScope, pos token.Position, varName string, vt Type) DIVar {
|
||||||
t := b.di().diType(vt, pos)
|
t := b.di().diType(vt, pos)
|
||||||
return b.di().varAuto(f, pos, varName, t)
|
return b.di().varAuto(scope, pos, varName, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hack for types.Scope
|
||||||
|
type hackScope struct {
|
||||||
|
parent *types.Scope
|
||||||
|
children []*types.Scope
|
||||||
|
number int // parent.children[number-1] is this scope; 0 if there is no parent
|
||||||
|
elems map[string]types.Object // lazily allocated
|
||||||
|
pos, end token.Pos // scope extent; may be invalid
|
||||||
|
comment string // for debugging only
|
||||||
|
isFunc bool // set if this is a function scope (internal use only)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFunc(scope *types.Scope) bool {
|
||||||
|
hs := (*hackScope)(unsafe.Pointer(scope))
|
||||||
|
return hs.isFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) DIScope(f Function, scope *types.Scope) DIScope {
|
||||||
|
if cachedScope, ok := b.diScopeCache[scope]; ok {
|
||||||
|
return cachedScope
|
||||||
|
}
|
||||||
|
pos := b.di().positioner.Position(scope.Pos())
|
||||||
|
// skip package and universe scope
|
||||||
|
// if scope.Parent().Parent() == nil {
|
||||||
|
// return b.di().file(pos.Filename)
|
||||||
|
// }
|
||||||
|
|
||||||
|
var result DIScope
|
||||||
|
if isFunc(scope) {
|
||||||
|
// TODO(lijie): should check scope == function scope
|
||||||
|
result = f
|
||||||
|
} else {
|
||||||
|
parentScope := b.DIScope(f, scope.Parent())
|
||||||
|
result = &aDILexicalBlock{b.di().di.CreateLexicalBlock(parentScope.scopeMeta(b.di(), pos).ll, llvm.DILexicalBlock{
|
||||||
|
File: b.di().file(pos.Filename).ll,
|
||||||
|
Line: pos.Line,
|
||||||
|
Column: pos.Column,
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.diScopeCache[scope] = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
MD_dbg = 0
|
||||||
|
)
|
||||||
|
|
||||||
func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
|
func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
|
||||||
if _, ok := b.Pkg.glbDbgVars[v]; ok {
|
if _, ok := b.Pkg.glbDbgVars[v]; ok {
|
||||||
return
|
return
|
||||||
@@ -660,16 +729,16 @@ func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
|
|||||||
v.Type,
|
v.Type,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
v.impl.AddMetadata(0, gv.ll)
|
v.impl.AddMetadata(MD_dbg, gv.ll)
|
||||||
b.Pkg.glbDbgVars[v] = true
|
b.Pkg.glbDbgVars[v] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Builder) DISetCurrentDebugLocation(f Function, pos token.Position) {
|
func (b Builder) DISetCurrentDebugLocation(diScope DIScope, pos token.Position) {
|
||||||
b.impl.SetCurrentDebugLocation(
|
b.impl.SetCurrentDebugLocation(
|
||||||
uint(pos.Line),
|
uint(pos.Line),
|
||||||
uint(pos.Column),
|
uint(pos.Column),
|
||||||
f.scopeMeta(b.di(), pos).ll,
|
diScope.scopeMeta(b.di(), pos).ll,
|
||||||
f.impl.InstructionDebugLoc(),
|
llvm.Metadata{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,6 +764,7 @@ func (b Builder) DebugFunction(f Function, pos token.Position, bodyPos token.Pos
|
|||||||
Line: pos.Line,
|
Line: pos.Line,
|
||||||
ScopeLine: bodyPos.Line,
|
ScopeLine: bodyPos.Line,
|
||||||
IsDefinition: true,
|
IsDefinition: true,
|
||||||
|
LocalToUnit: true,
|
||||||
Optimized: true,
|
Optimized: true,
|
||||||
}
|
}
|
||||||
p.diFunc = &aDIFunction{
|
p.diFunc = &aDIFunction{
|
||||||
|
|||||||
@@ -58,9 +58,8 @@ func (p BasicBlock) Addr() Expr {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type dbgExpr struct {
|
type dbgExpr struct {
|
||||||
ptr Expr
|
ptr Expr
|
||||||
val Expr
|
val Expr
|
||||||
deref bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type aBuilder struct {
|
type aBuilder struct {
|
||||||
@@ -70,7 +69,8 @@ type aBuilder struct {
|
|||||||
Pkg Package
|
Pkg Package
|
||||||
Prog Program
|
Prog Program
|
||||||
|
|
||||||
dbgVars map[Expr]dbgExpr
|
dbgVars map[Expr]dbgExpr // save copied address and values for debug info
|
||||||
|
diScopeCache map[*types.Scope]DIScope // avoid duplicated DILexicalBlock(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder represents a builder for creating instructions in a function.
|
// Builder represents a builder for creating instructions in a function.
|
||||||
|
|||||||
Reference in New Issue
Block a user