From a3ee85890d58d2a4a495af8333ab21d81f870b09 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 12 Jul 2021 14:25:59 +0200 Subject: [PATCH] main: remove -no-debug flag The -no-debug flag controls whether to emit DWARF debug information. However, instead of limiting debug information altogether, I think it's better to strip it off at the end if it isn't needed. For several reasons: * Some parts of the compiler now rely on the presence of debug information for proper diagnostics. * It works better with the cache: there is no distinction between debug and no-debug builds. * It makes it easier (or possible at all) to enable debug information in the wasi-libc library without big downsides. I'm doing this in a separate commit so this can be reverted if needed. --- builder/build.go | 1 - compileopts/config.go | 11 +----- compileopts/options.go | 1 - compiler/compiler.go | 88 ++++++++++++++++++------------------------ compiler/goroutine.go | 82 +++++++++++++++++++-------------------- compiler/interface.go | 10 ++--- compiler/interrupt.go | 24 ++++++------ compiler/symbol.go | 2 +- main.go | 7 ---- 9 files changed, 95 insertions(+), 131 deletions(-) diff --git a/builder/build.go b/builder/build.go index e7c4b8094..d08c22003 100644 --- a/builder/build.go +++ b/builder/build.go @@ -100,7 +100,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil AutomaticStackSize: config.AutomaticStackSize(), DefaultStackSize: config.Target.DefaultStackSize, NeedsStackObjects: config.NeedsStackObjects(), - Debug: config.EmitDWARF(), LLVMFeatures: config.LLVMFeatures(), } diff --git a/compileopts/config.go b/compileopts/config.go index ea21221b6..11fcc524a 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -209,9 +209,8 @@ func (c *Config) CFlags() []string { cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include")) cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) } - if c.EmitDWARF() { - cflags = append(cflags, "-g") - } + // Always emit debug information. It is optionally stripped at link time. + cflags = append(cflags, "-g") return cflags } @@ -250,12 +249,6 @@ func (c *Config) VerifyIR() bool { return c.Options.VerifyIR } -// EmitDWARF returns whether to add debug symbols to the IR, for debugging with -// GDB and similar. -func (c *Config) EmitDWARF() bool { - return c.Options.EmitDWARF -} - // Debug returns whether debug (DWARF) information should be retained by the // linker. The default varies by target but can be controlled with the -debug // command line flag. diff --git a/compileopts/options.go b/compileopts/options.go index 2babd19d8..670a2055c 100644 --- a/compileopts/options.go +++ b/compileopts/options.go @@ -29,7 +29,6 @@ type Options struct { DumpSSA bool VerifyIR bool PrintCommands func(cmd string, args ...string) - EmitDWARF bool Debug string PrintSizes string PrintAllocs *regexp.Regexp // regexp string diff --git a/compiler/compiler.go b/compiler/compiler.go index 7841cd656..6110834bf 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -58,7 +58,6 @@ type Config struct { AutomaticStackSize bool DefaultStackSize uint64 NeedsStackObjects bool - Debug bool // Whether to emit debug information in the LLVM module. LLVMFeatures string } @@ -103,9 +102,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C c.mod = c.ctx.NewModule(moduleName) c.mod.SetTarget(config.Triple) c.mod.SetDataLayout(c.targetData.String()) - if c.Debug { - c.dibuilder = llvm.NewDIBuilder(c.mod) - } + c.dibuilder = llvm.NewDIBuilder(c.mod) c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8) if c.targetData.PointerSize() <= 4 { @@ -263,15 +260,13 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, ssaPkg.Build() // Initialize debug information. - if c.Debug { - c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{ - Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?) - File: "", - Dir: "", - Producer: "TinyGo", - Optimized: true, - }) - } + c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{ + Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?) + File: "", + Dir: "", + Producer: "TinyGo", + Optimized: true, + }) // Load comments such as //go:extern on globals. c.loadASTComments(pkg) @@ -286,23 +281,21 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, c.createPackage(irbuilder, ssaPkg) // see: https://reviews.llvm.org/D18355 - if c.Debug { - c.mod.AddNamedMetadataOperand("llvm.module.flags", - c.ctx.MDNode([]llvm.Metadata{ - llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch - c.ctx.MDString("Debug Info Version"), - llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version - }), - ) - c.mod.AddNamedMetadataOperand("llvm.module.flags", - c.ctx.MDNode([]llvm.Metadata{ - llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), - c.ctx.MDString("Dwarf Version"), - llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(), - }), - ) - c.dibuilder.Finalize() - } + c.mod.AddNamedMetadataOperand("llvm.module.flags", + c.ctx.MDNode([]llvm.Metadata{ + llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch + c.ctx.MDString("Debug Info Version"), + llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version + }), + ) + c.mod.AddNamedMetadataOperand("llvm.module.flags", + c.ctx.MDNode([]llvm.Metadata{ + llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), + c.ctx.MDString("Dwarf Version"), + llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(), + }), + ) + c.dibuilder.Finalize() return c.mod, c.diagnostics } @@ -812,20 +805,18 @@ func (b *builder) createFunction() { b.llvmFn.AddFunctionAttr(noinline) } - // Add debug info, if needed. - if b.Debug { - if b.fn.Synthetic == "package initializer" { - // Package initializers have no debug info. Create some fake debug - // info to at least have *something*. - filename := b.fn.Package().Pkg.Path() + "/" - b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0) - } else if b.fn.Syntax() != nil { - // Create debug info file if needed. - b.difunc = b.attachDebugInfo(b.fn) - } - pos := b.program.Fset.Position(b.fn.Pos()) - b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) + // Add debug info. + if b.fn.Synthetic == "package initializer" { + // Package initializers have no debug info. Create some fake debug + // info to at least have *something*. + filename := b.fn.Package().Pkg.Path() + "/" + b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0) + } else if b.fn.Syntax() != nil { + // Create debug info file if needed. + b.difunc = b.attachDebugInfo(b.fn) } + pos := b.program.Fset.Position(b.fn.Pos()) + b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) // Pre-create all basic blocks in the function. for _, block := range b.fn.DomPreorder() { @@ -850,7 +841,7 @@ func (b *builder) createFunction() { b.locals[param] = b.collapseFormalParam(llvmType, fields) // Add debug information to this parameter (if available) - if b.Debug && b.fn.Syntax() != nil { + if b.fn.Syntax() != nil { dbgParam := b.getLocalVariable(param.Object().(*types.Var)) loc := b.GetCurrentDebugLocation() if len(fields) == 1 { @@ -910,9 +901,6 @@ func (b *builder) createFunction() { b.currentBlock = block for _, instr := range block.Instrs { if instr, ok := instr.(*ssa.DebugRef); ok { - if !b.Debug { - continue - } object := instr.Object() variable, ok := object.(*types.Var) if !ok { @@ -1029,10 +1017,8 @@ func getPos(val posser) token.Pos { // createInstruction builds the LLVM IR equivalent instructions for the // particular Go SSA instruction. func (b *builder) createInstruction(instr ssa.Instruction) { - if b.Debug { - pos := b.program.Fset.Position(getPos(instr)) - b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) - } + pos := b.program.Fset.Position(getPos(instr)) + b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) switch instr := instr.(type) { case ssa.Value: diff --git a/compiler/goroutine.go b/compiler/goroutine.go index 730fee92c..229da7be9 100644 --- a/compiler/goroutine.go +++ b/compiler/goroutine.go @@ -182,27 +182,26 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri entry := c.ctx.AddBasicBlock(wrapper, "entry") builder.SetInsertPointAtEnd(entry) - if c.Debug { - pos := c.program.Fset.Position(pos) - diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ - File: c.getDIFile(pos.Filename), - Parameters: nil, // do not show parameters in debugger - Flags: 0, // ? - }) - difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ - Name: "", - File: c.getDIFile(pos.Filename), - Line: pos.Line, - Type: diFuncType, - LocalToUnit: true, - IsDefinition: true, - ScopeLine: 0, - Flags: llvm.FlagPrototyped, - Optimized: true, - }) - wrapper.SetSubprogram(difunc) - builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) - } + // Add debug information. + pos := c.program.Fset.Position(pos) + diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ + File: c.getDIFile(pos.Filename), + Parameters: nil, // do not show parameters in debugger + Flags: 0, // ? + }) + difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ + Name: "", + File: c.getDIFile(pos.Filename), + Line: pos.Line, + Type: diFuncType, + LocalToUnit: true, + IsDefinition: true, + ScopeLine: 0, + Flags: llvm.FlagPrototyped, + Optimized: true, + }) + wrapper.SetSubprogram(difunc) + builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) // Create the list of params for the call. paramTypes := fn.Type().ElementType().ParamTypes() @@ -246,27 +245,26 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri entry := c.ctx.AddBasicBlock(wrapper, "entry") builder.SetInsertPointAtEnd(entry) - if c.Debug { - pos := c.program.Fset.Position(pos) - diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ - File: c.getDIFile(pos.Filename), - Parameters: nil, // do not show parameters in debugger - Flags: 0, // ? - }) - difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ - Name: "", - File: c.getDIFile(pos.Filename), - Line: pos.Line, - Type: diFuncType, - LocalToUnit: true, - IsDefinition: true, - ScopeLine: 0, - Flags: llvm.FlagPrototyped, - Optimized: true, - }) - wrapper.SetSubprogram(difunc) - builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) - } + // Add debug information. + pos := c.program.Fset.Position(pos) + diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ + File: c.getDIFile(pos.Filename), + Parameters: nil, // do not show parameters in debugger + Flags: 0, // ? + }) + difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ + Name: "", + File: c.getDIFile(pos.Filename), + Line: pos.Line, + Type: diFuncType, + LocalToUnit: true, + IsDefinition: true, + ScopeLine: 0, + Flags: llvm.FlagPrototyped, + Optimized: true, + }) + wrapper.SetSubprogram(difunc) + builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) // Get the list of parameters, with the extra parameters at the end. paramTypes := fn.Type().ElementType().ParamTypes() diff --git a/compiler/interface.go b/compiler/interface.go index 5d8895d71..55f394457 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -501,12 +501,10 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv } defer b.Builder.Dispose() - // add debug info if needed - if c.Debug { - pos := c.program.Fset.Position(fn.Pos()) - difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line) - b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) - } + // add debug info + pos := c.program.Fset.Position(fn.Pos()) + difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line) + b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) // set up IR builder block := b.ctx.AddBasicBlock(wrapper, "entry") diff --git a/compiler/interrupt.go b/compiler/interrupt.go index 2437ad452..f345429c8 100644 --- a/compiler/interrupt.go +++ b/compiler/interrupt.go @@ -52,19 +52,17 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro global.SetInitializer(initializer) // Add debug info to the interrupt global. - if b.Debug { - pos := b.program.Fset.Position(instr.Pos()) - diglobal := b.dibuilder.CreateGlobalVariableExpression(b.getDIFile(pos.Filename), llvm.DIGlobalVariableExpression{ - Name: "interrupt" + strconv.FormatInt(id.Int64(), 10), - LinkageName: globalName, - File: b.getDIFile(pos.Filename), - Line: pos.Line, - Type: b.getDIType(globalType), - Expr: b.dibuilder.CreateExpression(nil), - LocalToUnit: false, - }) - global.AddMetadata(0, diglobal) - } + pos := b.program.Fset.Position(instr.Pos()) + diglobal := b.dibuilder.CreateGlobalVariableExpression(b.getDIFile(pos.Filename), llvm.DIGlobalVariableExpression{ + Name: "interrupt" + strconv.FormatInt(id.Int64(), 10), + LinkageName: globalName, + File: b.getDIFile(pos.Filename), + Line: pos.Line, + Type: b.getDIType(globalType), + Expr: b.dibuilder.CreateExpression(nil), + LocalToUnit: false, + }) + global.AddMetadata(0, diglobal) // Create the runtime/interrupt.Interrupt type. It is a struct with a single // member of type int. diff --git a/compiler/symbol.go b/compiler/symbol.go index 49ccfa20d..8f824947b 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -386,7 +386,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value { llvmGlobal.SetAlignment(alignment) } - if c.Debug && !info.extern { + if !info.extern { // Add debug info. pos := c.program.Fset.Position(g.Pos()) diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[pos.Filename], llvm.DIGlobalVariableExpression{ diff --git a/main.go b/main.go index e0eb58070..f1b0d6a8c 100644 --- a/main.go +++ b/main.go @@ -1020,7 +1020,6 @@ func main() { printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printCommands := flag.Bool("x", false, "Print commands") debug := flag.String("debug", "auto", "remove debug information (auto, true, false)") - nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation") ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)") ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug") port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)") @@ -1087,7 +1086,6 @@ func main() { PrintIR: *printIR, DumpSSA: *dumpSSA, VerifyIR: *verifyIR, - EmitDWARF: !*nodebug, Debug: *debug, PrintSizes: *printSize, PrintStacks: *printStacks, @@ -1175,11 +1173,6 @@ func main() { err := Flash(pkgName, *port, options) handleCompilerError(err) } else { - if !options.EmitDWARF { - fmt.Fprintln(os.Stderr, "Debug disabled while running gdb?") - usage() - os.Exit(1) - } err := FlashGDB(pkgName, *ocdOutput, options) handleCompilerError(err) }