Skip to content

Commit

Permalink
terminal: add ability to show disassembly instead of source (go-delve…
Browse files Browse the repository at this point in the history
…#3047)

Adds ability to show current position as disassembly instead of source
listing every time execution stops. Change default to show disassembly
after step-instruction and source listing in every other case.

Fixes go-delve#2878
  • Loading branch information
aarzilli authored Jul 14, 2022
1 parent 278e4d1 commit 1fe03e7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 22 deletions.
31 changes: 30 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ import (
"path"
"runtime"

"github.com/go-delve/delve/service/api"
"gopkg.in/yaml.v2"
)

const (
configDir string = "dlv"
configDirHidden string = ".dlv"
configFile string = "config.yml"

PositionSource = "source"
PositionDisassembly = "disassembly"
PositionDefault = "default"
)

// SubstitutePathRule describes a rule for substitution of path to source code file.
Expand Down Expand Up @@ -76,9 +81,19 @@ type Config struct {
// called (i.e. when execution stops, listCommand is used, etc)
SourceListLineCount *int `yaml:"source-list-line-count,omitempty"`

// DebugFileDirectories is the list of directories Delve will use
// DebugInfoDirectories is the list of directories Delve will use
// in order to resolve external debug info files.
DebugInfoDirectories []string `yaml:"debug-info-directories"`

// Position controls how the current position in the program is displayed.
// There are three possible values:
// - source: always show the current position in the program's source
// code.
// - disassembly: always should the current position by disassembling the
// current function.
// - default (or the empty string): use disassembly for step-instruction,
// source for everything else.
Position string `yaml:"position"`
}

func (c *Config) GetSourceListLineCount() int {
Expand All @@ -90,6 +105,20 @@ func (c *Config) GetSourceListLineCount() int {
return n
}

func (c *Config) GetDisassembleFlavour() api.AssemblyFlavour {
if c == nil || c.DisassembleFlavor == nil {
return api.IntelFlavour
}
switch *c.DisassembleFlavor {
case "go":
return api.GoFlavour
case "gnu":
return api.GNUFlavour
default:
return api.IntelFlavour
}
}

// LoadConfig attempts to populate a Config object from the config.yml file.
func LoadConfig() (*Config, error) {
err := createConfigPath()
Expand Down
77 changes: 58 additions & 19 deletions pkg/terminal/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ func restartRecorded(t *Term, ctx callContext, args string) error {
return err
}
printcontext(t, state)
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
t.onStop()
return nil
}
Expand Down Expand Up @@ -1328,15 +1328,15 @@ func (c *Commands) cont(t *Term, ctx callContext, args string) error {
}
printcontext(t, state)
}
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
return nil
}

func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, shouldPrintFile bool) error {
defer t.onStop()
if !state.NextInProgress {
if shouldPrintFile {
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
}
return nil
}
Expand All @@ -1356,7 +1356,7 @@ func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, sho
fallthrough
default:
t.client.CancelNext()
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
return err
}
} else {
Expand All @@ -1372,7 +1372,7 @@ func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, sho
printcontext(t, state)
}
if !state.NextInProgress {
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
return nil
}
}
Expand Down Expand Up @@ -1452,7 +1452,7 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error
return err
}
printcontext(t, state)
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow|printPosStepInstruction)
return nil
}

Expand Down Expand Up @@ -2385,17 +2385,7 @@ func disassCommand(t *Term, ctx callContext, args string) error {
rest = argv[1]
}

flavor := api.IntelFlavour
if t.conf != nil && t.conf.DisassembleFlavor != nil {
switch *t.conf.DisassembleFlavor {
case "go":
flavor = api.GoFlavour
case "gnu":
flavor = api.GNUFlavour
default:
flavor = api.IntelFlavour
}
}
flavor := t.conf.GetDisassembleFlavour()

var disasm api.AsmInstructions
var disasmErr error
Expand Down Expand Up @@ -2438,7 +2428,7 @@ func disassCommand(t *Term, ctx callContext, args string) error {
return disasmErr
}

disasmPrint(disasm, t.stdout)
disasmPrint(disasm, t.stdout, true)

return nil
}
Expand Down Expand Up @@ -2678,6 +2668,26 @@ func printTracepoint(t *Term, th *api.Thread, bpname string, fn *api.Function, a
}
}

type printPosFlags uint8

const (
printPosShowArrow printPosFlags = 1 << iota
printPosStepInstruction
)

func printPos(t *Term, th *api.Thread, flags printPosFlags) error {
if flags&printPosStepInstruction != 0 {
if t.conf.Position == config.PositionSource {
return printfile(t, th.File, th.Line, flags&printPosShowArrow != 0)
}
return printdisass(t, th.PC)
}
if t.conf.Position == config.PositionDisassembly {
return printdisass(t, th.PC)
}
return printfile(t, th.File, th.Line, flags&printPosShowArrow != 0)
}

func printfile(t *Term, filename string, line int, showArrow bool) error {
if filename == "" {
return nil
Expand Down Expand Up @@ -2712,6 +2722,35 @@ func printfile(t *Term, filename string, line int, showArrow bool) error {
return t.stdout.ColorizePrint(file.Name(), file, line-lineCount, line+lineCount+1, arrowLine)
}

func printdisass(t *Term, pc uint64) error {
disasm, err := t.client.DisassemblePC(api.EvalScope{GoroutineID: -1, Frame: 0, DeferredCall: 0}, pc, t.conf.GetDisassembleFlavour())
if err != nil {
return err
}

lineCount := t.conf.GetSourceListLineCount()

showHeader := true
for i := range disasm {
if disasm[i].AtPC {
s := i - lineCount
if s < 0 {
s = 0
}
e := i + lineCount + 1
if e > len(disasm) {
e = len(disasm)
}
showHeader = s == 0
disasm = disasm[s:e]
break
}
}

disasmPrint(disasm, t.stdout, showHeader)
return nil
}

// ExitRequestError is returned when the user
// exits Delve.
type ExitRequestError struct{}
Expand Down Expand Up @@ -2908,7 +2947,7 @@ func (c *Commands) rewind(t *Term, ctx callContext, args string) error {
}
printcontext(t, state)
}
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
printPos(t, state.CurrentThread, printPosShowArrow)
return nil
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/terminal/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1331,3 +1331,14 @@ func TestTranscript(t *testing.T) {
os.Remove(name)
})
}

func TestDisassPosCmd(t *testing.T) {
withTestTerminal("testvariables2", t, func(term *FakeTerminal) {
term.MustExec("continue")
out := term.MustExec("step-instruction")
t.Logf("%q\n", out)
if !strings.Contains(out, "call $runtime.Breakpoint") && !strings.Contains(out, "CALL runtime.Breakpoint(SB)") {
t.Errorf("output doesn't look like disassembly")
}
})
}
4 changes: 2 additions & 2 deletions pkg/terminal/disasmprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"github.com/go-delve/delve/service/api"
)

func disasmPrint(dv api.AsmInstructions, out io.Writer) {
func disasmPrint(dv api.AsmInstructions, out io.Writer, showHeader bool) {
bw := bufio.NewWriter(out)
defer bw.Flush()
if len(dv) > 0 && dv[0].Loc.Function != nil {
if len(dv) > 0 && dv[0].Loc.Function != nil && showHeader {
fmt.Fprintf(bw, "TEXT %s(SB) %s\n", dv[0].Loc.Function.Name(), dv[0].Loc.File)
}
tw := tabwriter.NewWriter(bw, 1, 8, 1, '\t', 0)
Expand Down

0 comments on commit 1fe03e7

Please sign in to comment.