Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions cl/caller_frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,7 @@ func TestRuntimeFrameNameNormalization(t *testing.T) {
}

func TestCompileRuntimeCallerFrameInstrumentation(t *testing.T) {
old := emitShadowStackInstrumentation
emitShadowStackInstrumentation = true
defer func() { emitShadowStackInstrumentation = old }()
t.Setenv("LLGO_SHADOW_STACK", "1")
ssapkg, files := buildCallerFrameSSAPackage(t, "example.com/foo", `package foo
import "runtime/debug"

Expand Down Expand Up @@ -744,9 +742,7 @@ func top() {
}

func TestCompileRuntimeCallerFrameUsesGoNameForLinkname(t *testing.T) {
old := emitShadowStackInstrumentation
emitShadowStackInstrumentation = true
defer func() { emitShadowStackInstrumentation = old }()
t.Setenv("LLGO_SHADOW_STACK", "1")
ssapkg, files := buildCallerFrameSSAPackage(t, "command-line-arguments", `package main
import "runtime"

Expand Down Expand Up @@ -825,9 +821,7 @@ func f() { _ = runtime.FuncForPC(0) }
}

func TestCompileRuntimeCallerLocationOnlyForRuntimePaths(t *testing.T) {
old := emitShadowStackInstrumentation
emitShadowStackInstrumentation = true
defer func() { emitShadowStackInstrumentation = old }()
t.Setenv("LLGO_SHADOW_STACK", "1")
ssapkg, files := buildCallerFrameSSAPackage(t, "example.com/foo", `package foo
import "runtime"

Expand Down
74 changes: 62 additions & 12 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ var (
enableExportRename bool
)

// Options contains frontend behavior for one package compilation. Drivers that
// may host multiple builds in one process should pass Options explicitly
// instead of changing the legacy package-level Enable* settings.
type Options struct {
Debug bool
DebugSymbols bool
Trace bool
ExportRename bool
ShadowStack bool
}

func legacyOptions() Options {
return Options{
Debug: enableDbg,
DebugSymbols: enableDbgSyms,
Trace: enableCallTracing,
ExportRename: enableExportRename,
ShadowStack: os.Getenv("LLGO_SHADOW_STACK") == "1",
}
}

// SetDebug sets debug flags.
func SetDebug(dbgFlags dbgFlags) {
debugInstr = (dbgFlags & DbgFlagInstruction) != 0
Expand Down Expand Up @@ -115,20 +136,27 @@ func dbgGoSSAln(args ...any) {
}
}

// EnableDebug changes the legacy process-wide default.
// Deprecated: pass Options to NewPackageExWithEmbedMetaOptions.
func EnableDebug(b bool) {
enableDbg = b
}

// EnableDbgSyms changes the legacy process-wide default.
// Deprecated: pass Options to NewPackageExWithEmbedMetaOptions.
func EnableDbgSyms(b bool) {
enableDbgSyms = b
}

// EnableTrace changes the legacy process-wide default.
// Deprecated: pass Options to NewPackageExWithEmbedMetaOptions.
func EnableTrace(b bool) {
enableCallTracing = b
}

// EnableExportRename enables or disables //export with different C symbol names.
// This is enabled when using -target flag for TinyGo compatibility.
// Deprecated: pass Options to NewPackageExWithEmbedMetaOptions.
func EnableExportRename(b bool) {
enableExportRename = b
}
Expand Down Expand Up @@ -180,6 +208,8 @@ type context struct {
debugAllocVars map[*ssa.Alloc]*types.Var
runtimeCallerFuncs map[*ssa.Function]bool
pcLineSeq uint64
options Options
optionsSet bool

patches Patches
blkInfos []blocks.Info
Expand Down Expand Up @@ -213,6 +243,13 @@ type context struct {
locality localityLowering
}

func (p *context) frontendOptions() Options {
if p != nil && p.optionsSet {
return p.options
}
return legacyOptions()
}

func (p *context) rewriteValue(name string) (string, bool) {
if p.rewrites == nil {
return "", false
Expand Down Expand Up @@ -601,8 +638,8 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
if f.Recover != nil { // set recover block
fn.SetRecover(fn.Block(f.Recover.Index))
}
dbgEnabled := enableDbg
dbgSymsEnabled := enableDbgSyms && (f == nil || f.Origin() == nil)
dbgEnabled := p.frontendOptions().Debug
dbgSymsEnabled := p.frontendOptions().DebugSymbols && (f == nil || f.Origin() == nil)
p.inits = append(p.inits, func() {
oldFn, oldGoFn, oldMethodNilDerefChecks, oldCallerFrameMark := p.fn, p.goFn, p.methodNilDerefChecks, p.callerFrameMark
oldLocalityFunction := p.locality.function
Expand Down Expand Up @@ -850,11 +887,11 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
if block.Index == 0 && p.shouldTrackCallerFrames() {
p.pushCallerLocationFrame(b, block.Parent())
}
if block.Index == 0 && enableCallTracing && !strings.HasPrefix(fn.Name(), "github.com/goplus/llgo/runtime/internal/runtime.Print") {
if block.Index == 0 && p.frontendOptions().Trace && !strings.HasPrefix(fn.Name(), "github.com/goplus/llgo/runtime/internal/runtime.Print") {
b.Printf("call " + fn.Name() + "\n\x00")
}
// place here to avoid wrong current-block
if enableDbgSyms && block.Parent().Origin() == nil && block.Index == 0 {
if p.frontendOptions().DebugSymbols && block.Parent().Origin() == nil && block.Index == 0 {
p.debugParams(b, block.Parent())
}

Expand Down Expand Up @@ -1640,7 +1677,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
if _, ok := p.staticInitInstrs[instr]; ok {
return
}
if enableDbg && instr.Parent().Origin() == nil {
if p.frontendOptions().Debug && instr.Parent().Origin() == nil {
if _, isDebugRef := instr.(*ssa.DebugRef); !isDebugRef {
scope := p.getDebugLocScope(instr.Parent(), instr.Pos())
if scope != nil {
Expand Down Expand Up @@ -1757,7 +1794,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
p.recordPanicLocation(b, v.Pos())
b.Send(ch, x)
case *ssa.DebugRef:
if enableDbgSyms && v.Parent().Origin() == nil {
if p.frontendOptions().DebugSymbols && v.Parent().Origin() == nil {
p.debugRef(b, v)
}
default:
Expand Down Expand Up @@ -1820,7 +1857,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
if isCgoVar(varName) {
p.cgoSymbols = append(p.cgoSymbols, val.Name())
}
if enableDbgSyms && p.localityAllowsGlobalDebug(v) {
if p.frontendOptions().DebugSymbols && p.localityAllowsGlobalDebug(v) {
pos := p.fset.Position(v.Pos())
b.DIGlobal(val, v.Name(), pos)
}
Expand Down Expand Up @@ -2053,6 +2090,7 @@ type Patch struct {
type Patches = map[string]Patch

// NewPackage compiles a Go package to LLVM IR package.
// Deprecated: use NewPackageExWithEmbedMetaOptions with explicit Options.
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
ret, _, err = NewPackageEx(prog, nil, nil, pkg, files)
return
Expand All @@ -2073,8 +2111,9 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
//
// The rewrites map uses short variable names (without package qualifier) and
// only affects string-typed globals defined in the current package.
// Deprecated: use NewPackageExWithEmbedMetaOptions with explicit Options.
func NewPackageEx(prog llssa.Program, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, externs []string, err error) {
return newPackageEx(prog, nil, patches, rewrites, pkg, files, nil, false)
return newPackageEx(prog, nil, patches, rewrites, pkg, files, nil, false, legacyOptions())
}

// NewPackageExWithEmbed compiles a package using pre-loaded go:embed metadata.
Expand All @@ -2084,15 +2123,24 @@ func NewPackageEx(prog llssa.Program, patches Patches, rewrites map[string]strin
// compiling multiple packages pass the same instance for every package
// of one compilation (like patches). nil means one-shot: a fresh
// instance is created for this call.
// Deprecated: use NewPackageExWithEmbedMetaOptions with explicit Options.
func NewPackageExWithEmbed(prog llssa.Program, ct *CallerTracking, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File, embedMap goembed.VarMap) (ret llssa.Package, externs []string, err error) {
return newPackageEx(prog, ct, patches, rewrites, pkg, files, &embedMap, false)
return newPackageEx(prog, ct, patches, rewrites, pkg, files, &embedMap, false, legacyOptions())
}

// NewPackageExWithEmbedMeta compiles a package and optionally collects metadata.
// Deprecated: use NewPackageExWithEmbedMetaOptions with explicit Options.
func NewPackageExWithEmbedMeta(prog llssa.Program, ct *CallerTracking, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File, embedMap goembed.VarMap, metaCollect bool) (ret llssa.Package, externs []string, err error) {
return newPackageEx(prog, ct, patches, rewrites, pkg, files, &embedMap, metaCollect)
return newPackageEx(prog, ct, patches, rewrites, pkg, files, &embedMap, metaCollect, legacyOptions())
}

// NewPackageExWithEmbedMetaOptions is NewPackageExWithEmbedMeta with explicit
// per-package frontend options.
func NewPackageExWithEmbedMetaOptions(prog llssa.Program, ct *CallerTracking, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File, embedMap goembed.VarMap, metaCollect bool, options Options) (ret llssa.Package, externs []string, err error) {
return newPackageEx(prog, ct, patches, rewrites, pkg, files, &embedMap, metaCollect, options)
}

func newPackageEx(prog llssa.Program, ct *CallerTracking, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File, embedMap *goembed.VarMap, metaCollect bool) (ret llssa.Package, externs []string, err error) {
func newPackageEx(prog llssa.Program, ct *CallerTracking, patches Patches, rewrites map[string]string, pkg *ssa.Package, files []*ast.File, embedMap *goembed.VarMap, metaCollect bool, options Options) (ret llssa.Package, externs []string, err error) {
pkgProg := pkg.Prog
pkgTypes := pkg.Pkg
oldTypes := pkgTypes
Expand All @@ -2116,7 +2164,7 @@ func newPackageEx(prog llssa.Program, ct *CallerTracking, patches Patches, rewri
prog.SetRuntime(pkgTypes)
}
ret = prog.NewPackageEx(pkgName, pkgPath, metaCollect)
if enableDbg {
if options.Debug {
ret.InitDebug(pkgName, pkgPath, pkgProg.Fset)
defer ret.FinalizeDebug()
}
Expand All @@ -2132,6 +2180,8 @@ func newPackageEx(prog llssa.Program, ct *CallerTracking, patches Patches, rewri
goTyps: pkgTypes,
goPkg: pkg,
patches: patches,
options: options,
optionsSet: true,
skips: make(map[string]none),
vargs: make(map[*ssa.Alloc][]llssa.Expr),
funcs: make(map[*ssa.Function]llssa.Function),
Expand Down
52 changes: 43 additions & 9 deletions cl/debug_compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,45 @@ import (
"golang.org/x/tools/go/ssa/ssautil"
)

func TestFrontendOptions(t *testing.T) {
oldDebug := enableDbg
oldDebugSymbols := enableDbgSyms
oldTrace := enableCallTracing
oldExportRename := enableExportRename
t.Cleanup(func() {
enableDbg = oldDebug
enableDbgSyms = oldDebugSymbols
enableCallTracing = oldTrace
enableExportRename = oldExportRename
})

EnableDebug(true)
EnableDbgSyms(true)
EnableTrace(true)
EnableExportRename(true)
t.Setenv("LLGO_SHADOW_STACK", "1")

wantLegacy := Options{
Debug: true,
DebugSymbols: true,
Trace: true,
ExportRename: true,
ShadowStack: true,
}
if got := (&context{}).frontendOptions(); got != wantLegacy {
t.Fatalf("frontendOptions() = %+v, want legacy options %+v", got, wantLegacy)
}
if got := (*context)(nil).frontendOptions(); got != wantLegacy {
t.Fatalf("nil frontendOptions() = %+v, want legacy options %+v", got, wantLegacy)
}

wantExplicit := Options{Trace: true}
ctx := &context{options: wantExplicit, optionsSet: true}
if got := ctx.frontendOptions(); got != wantExplicit {
t.Fatalf("frontendOptions() = %+v, want explicit options %+v", got, wantExplicit)
}
}

func TestCompileDebugMetadata(t *testing.T) {
const source = `package debugcompile

Expand Down Expand Up @@ -55,21 +94,16 @@ var anonymous = func(seed int) int {
t.Fatal(err)
}

oldDebug, oldDebugSyms := enableDbg, enableDbgSyms
EnableDebug(true)
EnableDbgSyms(true)
defer func() {
EnableDebug(oldDebug)
EnableDbgSyms(oldDebugSyms)
}()

prog := newLLSSAProgForTarget(t, &llssa.Target{
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
OptLevel: optlevel.O0,
})
defer prog.Dispose()
pkg, err := NewPackage(prog, ssaPkg, []*ast.File{file})
pkg, _, err := newPackageEx(prog, nil, nil, nil, ssaPkg, []*ast.File{file}, nil, false, Options{
Debug: true,
DebugSymbols: true,
})
if err != nil {
t.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions cl/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func (p *context) processLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgNam
for n := len(doc.List) - 1; n >= 0; n-- {
line := doc.List[n].Text
ret := p.initLinkname(line, allowExport, func(name string, isExport bool) (_ string, _, ok bool) {
return fullName, isVar, name == inPkgName || (isExport && enableExportRename)
return fullName, isVar, name == inPkgName || (isExport && p.frontendOptions().ExportRename)
})
if ret != unknownDirective {
return ret == hasLinkname
Expand Down Expand Up @@ -370,7 +370,7 @@ func (p *context) initLink(line string, prefix int, export bool, f func(inPkgNam
}
} else {
// Export with different names already processed by initLinknameByDoc
if export && enableExportRename {
if export && p.frontendOptions().ExportRename {
return
}
if export {
Expand Down
12 changes: 2 additions & 10 deletions cl/instr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1481,16 +1481,8 @@ func (p *context) runtimeCallerFrameName() string {
return ""
}

// emitShadowStackInstrumentation gates the legacy shadow-stack calls
// (PushCallerLocationFrame / RecordCallerLocation / RecordPanicLocation).
// The FP-chain unwinder supersedes them: physical pcs resolve through the
// prebuilt ftab and pcline labels, so tracked functions keep only noinline,
// no-tail-call and the label records. The emitters stay for one release as
// an escape hatch (LLGO_SHADOW_STACK=1).
var emitShadowStackInstrumentation = os.Getenv("LLGO_SHADOW_STACK") == "1"

func (p *context) pushCallerLocationFrame(b llssa.Builder, fn *ssa.Function) {
if !emitShadowStackInstrumentation {
if !p.frontendOptions().ShadowStack {
return
}
if fn == nil {
Expand All @@ -1516,7 +1508,7 @@ func (p *context) recordPanicLocation(b llssa.Builder, pos token.Pos) {
}

func (p *context) recordRuntimeLocation(b llssa.Builder, pos token.Pos, fn string) {
if !emitShadowStackInstrumentation || !p.shouldTrackCallerFrames() {
if !p.frontendOptions().ShadowStack || !p.shouldTrackCallerFrames() {
return
}
position := p.fset.Position(pos)
Expand Down
Loading
Loading