diff --git a/dibuilder.go b/dibuilder.go index e5128cf..368f1f9 100644 --- a/dibuilder.go +++ b/dibuilder.go @@ -60,8 +60,17 @@ const ( type DwarfLang uint32 const ( - // http://dwarfstd.org/ShowIssue.php?issue=101014.1&type=open - DW_LANG_Go DwarfLang = 0x0016 + // LLVMDWARFSourceLanguage is a dense C API enum, not the raw DW_LANG + // encoding from the DWARF specification. + DW_LANG_Go DwarfLang = C.LLVMDWARFSourceLanguageGo +) + +type DwarfEmissionKind uint8 + +const ( + DwarfEmissionFull DwarfEmissionKind = iota + DwarfEmissionLineTablesOnly + DwarfEmissionNone ) type DwarfTypeEncoding uint32 @@ -120,6 +129,7 @@ type DICompileUnit struct { RuntimeVersion int SysRoot string SDK string + EmissionKind DwarfEmissionKind } // CreateCompileUnit creates compile unit debug metadata. @@ -136,6 +146,16 @@ func (d *DIBuilder) CreateCompileUnit(cu DICompileUnit) Metadata { defer C.free(unsafe.Pointer(sysroot)) sdk := C.CString(cu.SDK) defer C.free(unsafe.Pointer(sdk)) + emissionKind := C.LLVMDWARFEmissionKind(C.LLVMDWARFEmissionFull) + switch cu.EmissionKind { + case DwarfEmissionFull: + case DwarfEmissionLineTablesOnly: + emissionKind = C.LLVMDWARFEmissionLineTablesOnly + case DwarfEmissionNone: + emissionKind = C.LLVMDWARFEmissionNone + default: + panic("invalid DWARF emission kind") + } result := C.LLVMDIBuilderCreateCompileUnit( d.ref, C.LLVMDWARFSourceLanguage(cu.Language), @@ -145,7 +165,7 @@ func (d *DIBuilder) CreateCompileUnit(cu DICompileUnit) Metadata { flags, C.size_t(len(cu.Flags)), C.unsigned(cu.RuntimeVersion), /*SplitName=*/ nil, 0, - C.LLVMDWARFEmissionFull, + emissionKind, /*DWOId=*/ 0, /*SplitDebugInlining*/ C.LLVMBool(boolToCInt(true)), /*DebugInfoForProfiling*/ C.LLVMBool(boolToCInt(false)), @@ -155,6 +175,13 @@ func (d *DIBuilder) CreateCompileUnit(cu DICompileUnit) Metadata { return Metadata{C: result} } +// CreateDebugLocation creates an exact DILocation, including an optional +// inlinedAt chain. +func (c Context) CreateDebugLocation(line, col uint, scope, inlinedAt Metadata) Metadata { + return Metadata{C: C.LLVMDIBuilderCreateDebugLocation( + c.C, C.uint(line), C.uint(col), scope.C, inlinedAt.C)} +} + // CreateFile creates file debug metadata. func (d *DIBuilder) CreateFile(filename, dir string) Metadata { cfilename := C.CString(filename) diff --git a/ir.go b/ir.go index 9d471a4..c24fe62 100644 --- a/ir.go +++ b/ir.go @@ -1390,6 +1390,20 @@ func (b Builder) SetCurrentDebugLocation(line, col uint, scope, inlinedAt Metada C.LLVMGoSetCurrentDebugLocation(b.C, C.unsigned(line), C.unsigned(col), scope.C, inlinedAt.C) } +// SetCurrentDebugLocationMetadata sets the exact DILocation inherited by +// subsequently created instructions. A nil value clears it. +func (b Builder) SetCurrentDebugLocationMetadata(loc Metadata) { + C.LLVMSetCurrentDebugLocation2(b.C, loc.C) +} + +func (b Builder) CurrentDebugLocationMetadata() Metadata { + return Metadata{C: C.LLVMGetCurrentDebugLocation2(b.C)} +} + +func (b Builder) ClearCurrentDebugLocation() { + C.LLVMSetCurrentDebugLocation2(b.C, nil) +} + // Get current debug location. Please do not call this function until setting debug location with SetCurrentDebugLocation() func (b Builder) GetCurrentDebugLocation() (loc DebugLoc) { md := C.LLVMGoGetCurrentDebugLocation(b.C) diff --git a/ir_test.go b/ir_test.go index 3767a11..cf59c51 100644 --- a/ir_test.go +++ b/ir_test.go @@ -244,6 +244,40 @@ func TestDebugLoc(t *testing.T) { if loc.Scope.C != scope.C { t.Errorf("Got metadata %v as scope, though wanted %v", loc.Scope.C, scope.C) } + + exact := ctx.CreateDebugLocation(11, 7, scope, Metadata{}) + b.SetCurrentDebugLocationMetadata(exact) + if got := b.CurrentDebugLocationMetadata(); got.C != exact.C { + t.Errorf("Got exact location %v, want %v", got.C, exact.C) + } + b.ClearCurrentDebugLocation() + if got := b.CurrentDebugLocationMetadata(); !got.IsNil() { + t.Errorf("Cleared debug location is non-nil: %v", got.C) + } +} + +func TestGoCompileUnitLanguageAndEmission(t *testing.T) { + ctx := NewContext() + defer ctx.Dispose() + mod := ctx.NewModule("go-debug") + defer mod.Dispose() + d := NewDIBuilder(mod) + defer d.Destroy() + + d.CreateCompileUnit(DICompileUnit{ + Language: DW_LANG_Go, + File: "debug.go", + Producer: "go-llvm-test", + EmissionKind: DwarfEmissionLineTablesOnly, + }) + d.Finalize() + text := mod.String() + if !strings.Contains(text, "language: DW_LANG_Go") { + t.Fatalf("compile unit does not use the Go source language:\n%s", text) + } + if !strings.Contains(text, "emissionKind: LineTablesOnly") { + t.Fatalf("compile unit does not use line-tables-only emission:\n%s", text) + } } func TestSubtypes(t *testing.T) {