diff --git a/driver/driver.go b/driver/driver.go index 9bcbc829..e65bc2f4 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -142,7 +142,7 @@ type ObjTool interface { // Disasm disassembles the named object file, starting at // the start address and stopping at (before) the end address. - Disasm(file string, start, end uint64) ([]Inst, error) + Disasm(file string, start, end uint64, intelSyntax bool) ([]Inst, error) } // An Inst is a single instruction in an assembly listing. @@ -269,8 +269,8 @@ func (f *internalObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, return pluginSyms, nil } -func (o *internalObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { - insts, err := o.ObjTool.Disasm(file, start, end) +func (o *internalObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { + insts, err := o.ObjTool.Disasm(file, start, end, intelSyntax) if err != nil { return nil, err } diff --git a/internal/binutils/binutils.go b/internal/binutils/binutils.go index 967726d1..8adfa8eb 100644 --- a/internal/binutils/binutils.go +++ b/internal/binutils/binutils.go @@ -157,12 +157,22 @@ func findExe(cmd string, paths []string) (string, bool) { // Disasm returns the assembly instructions for the specified address range // of a binary. -func (bu *Binutils) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { +func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { b := bu.get() - cmd := exec.Command(b.objdump, "-d", "-C", "--no-show-raw-insn", "-l", + args := []string{"-d", "-C", "--no-show-raw-insn", "-l", fmt.Sprintf("--start-address=%#x", start), - fmt.Sprintf("--stop-address=%#x", end), - file) + fmt.Sprintf("--stop-address=%#x", end)} + + if intelSyntax { + if runtime.GOOS == "darwin" { + args = append(args, "-x86-asm-syntax=intel") + } else { + args = append(args, "-M", "intel") + } + } + + args = append(args, file) + cmd := exec.Command(b.objdump, args...) out, err := cmd.Output() if err != nil { return nil, fmt.Errorf("%v: %v", cmd.Args, err) diff --git a/internal/binutils/binutils_test.go b/internal/binutils/binutils_test.go index 5e261449..ad34c33e 100644 --- a/internal/binutils/binutils_test.go +++ b/internal/binutils/binutils_test.go @@ -188,10 +188,9 @@ func skipUnlessDarwinAmd64(t *testing.T) { } } -func TestDisasm(t *testing.T) { - skipUnlessLinuxAmd64(t) +func testDisasm(t *testing.T, intelSyntax bool) { bu := &Binutils{} - insts, err := bu.Disasm(filepath.Join("testdata", "exe_linux_64"), 0, math.MaxUint64) + insts, err := bu.Disasm(filepath.Join("testdata", "exe_linux_64"), 0, math.MaxUint64, intelSyntax) if err != nil { t.Fatalf("Disasm: unexpected error %v", err) } @@ -206,6 +205,12 @@ func TestDisasm(t *testing.T) { } } +func TestDisasm(t *testing.T) { + skipUnlessLinuxAmd64(t) + testDisasm(t, true) + testDisasm(t, false) +} + func findSymbol(syms []*plugin.Sym, name string) *plugin.Sym { for _, s := range syms { for _, n := range s.Name { diff --git a/internal/driver/commands.go b/internal/driver/commands.go index f5247149..1925843b 100644 --- a/internal/driver/commands.go +++ b/internal/driver/commands.go @@ -154,6 +154,9 @@ var pprofVariables = variables{ "compact_labels": &variable{boolKind, "f", "", "Show minimal headers"}, "source_path": &variable{stringKind, "", "", "Search path for source files"}, "trim_path": &variable{stringKind, "", "", "Path to trim from source paths before search"}, + "intel_syntax": &variable{boolKind, "f", "", helpText( + "Show assembly in Intel syntax", + "Only applicable to commands `disasm` and `weblist`")}, // Filtering options "nodecount": &variable{intKind, "-1", "", helpText( diff --git a/internal/driver/driver.go b/internal/driver/driver.go index 1be749aa..9640cdcb 100644 --- a/internal/driver/driver.go +++ b/internal/driver/driver.go @@ -281,6 +281,8 @@ func reportOptions(p *profile.Profile, numLabelUnits map[string]string, vars var SourcePath: vars["source_path"].stringValue(), TrimPath: vars["trim_path"].stringValue(), + + IntelSyntax: vars["intel_syntax"].boolValue(), } if len(p.Mapping) > 0 && p.Mapping[0].File != "" { diff --git a/internal/driver/driver_test.go b/internal/driver/driver_test.go index 96534fbb..1d8545e0 100644 --- a/internal/driver/driver_test.go +++ b/internal/driver/driver_test.go @@ -1562,7 +1562,7 @@ func (*mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFi return &mockFile{file, "abcdef", 0}, nil } -func (m *mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { +func (m *mockObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { switch start { case 0x1000: return []plugin.Inst{ diff --git a/internal/driver/fetch_test.go b/internal/driver/fetch_test.go index b9e9dfe8..318eba13 100644 --- a/internal/driver/fetch_test.go +++ b/internal/driver/fetch_test.go @@ -161,7 +161,9 @@ func (o testObj) Open(file string, start, limit, offset uint64) (plugin.ObjFile, func (testObj) Demangler(_ string) func(names []string) (map[string]string, error) { return func(names []string) (map[string]string, error) { return nil, nil } } -func (testObj) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { return nil, nil } +func (testObj) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { + return nil, nil +} type testFile struct{ name, buildID string } diff --git a/internal/driver/webui_test.go b/internal/driver/webui_test.go index 6d288b31..220b88ab 100644 --- a/internal/driver/webui_test.go +++ b/internal/driver/webui_test.go @@ -172,7 +172,7 @@ func (obj fakeObjTool) Open(file string, start, limit, offset uint64) (plugin.Ob return fakeObj{}, nil } -func (obj fakeObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { +func (obj fakeObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { return []plugin.Inst{ {Addr: addrBase + 0, Text: "f1:asm", Function: "F1"}, {Addr: addrBase + 10, Text: "f2:asm", Function: "F2"}, diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 4c1db233..3a8d0af7 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -114,7 +114,7 @@ type ObjTool interface { // Disasm disassembles the named object file, starting at // the start address and stopping at (before) the end address. - Disasm(file string, start, end uint64) ([]Inst, error) + Disasm(file string, start, end uint64, intelSyntax bool) ([]Inst, error) } // An Inst is a single instruction in an assembly listing. diff --git a/internal/report/report.go b/internal/report/report.go index 56083d8a..b8bf86da 100644 --- a/internal/report/report.go +++ b/internal/report/report.go @@ -79,6 +79,8 @@ type Options struct { Symbol *regexp.Regexp // Symbols to include on disassembly report. SourcePath string // Search path for source files. TrimPath string // Paths to trim from source file paths. + + IntelSyntax bool // Whether or not to print assembly in Intel syntax. } // Generate generates a report as directed by the Report. @@ -438,7 +440,7 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e flatSum, cumSum := sns.Sum() // Get the function assembly. - insts, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End) + insts, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End, o.IntelSyntax) if err != nil { return err } diff --git a/internal/report/source.go b/internal/report/source.go index ab8b64cb..b4805354 100644 --- a/internal/report/source.go +++ b/internal/report/source.go @@ -205,7 +205,7 @@ func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) er ff := fileFunction{n.Info.File, n.Info.Name} fns := fileNodes[ff] - asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj) + asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj, o.IntelSyntax) start, end := sourceCoordinates(asm) fnodes, path, err := getSourceFromFile(ff.fileName, reader, fns, start, end) @@ -239,7 +239,7 @@ func sourceCoordinates(asm map[int][]assemblyInstruction) (start, end int) { // assemblyPerSourceLine disassembles the binary containing a symbol // and classifies the assembly instructions according to its // corresponding source line, annotating them with a set of samples. -func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj plugin.ObjTool) map[int][]assemblyInstruction { +func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj plugin.ObjTool, intelSyntax bool) map[int][]assemblyInstruction { assembly := make(map[int][]assemblyInstruction) // Identify symbol to use for this collection of samples. o := findMatchingSymbol(objSyms, rs) @@ -248,7 +248,7 @@ func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj } // Extract assembly for matched symbol - insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End) + insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End, intelSyntax) if err != nil { return assembly } diff --git a/internal/symbolizer/symbolizer_test.go b/internal/symbolizer/symbolizer_test.go index 2d26b51e..e93e25e2 100644 --- a/internal/symbolizer/symbolizer_test.go +++ b/internal/symbolizer/symbolizer_test.go @@ -267,7 +267,7 @@ func (mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFil return mockObjFile{frames: mockAddresses}, nil } -func (mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { +func (mockObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) { return nil, fmt.Errorf("disassembly not supported") }