]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/objdump: add support for -gnu option on Go objdump
authorLynn Boger <laboger@linux.vnet.ibm.com>
Wed, 25 Mar 2020 17:47:43 +0000 (13:47 -0400)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Mon, 30 Mar 2020 14:30:49 +0000 (14:30 +0000)
This adds support for the -gnu option on Go objdump. When
this option is used, then output will include gnu
assembly in comments alongside the Go assembly.

The objdump test was updated to test this new option.

This option is supported for the arches found in
golang.org/x that provide the GNUsyntax function.

Updates #34372

Change-Id: I9e60e1691526607dda3c857c4564dcef408b8391
Reviewed-on: https://go-review.googlesource.com/c/go/+/225459
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/internal/objfile/disasm.go
src/cmd/objdump/main.go
src/cmd/objdump/objdump_test.go
src/cmd/pprof/pprof.go

index 35cfd35d37c83d7331d128d18b3d61bac009409a..b5f1cd1632d8e8ec712b876675b7ed714aba389d 100644 (file)
@@ -187,7 +187,7 @@ func (fc *FileCache) Line(filename string, line int) ([]byte, error) {
 // If filter is non-nil, the disassembly only includes functions with names matching filter.
 // If printCode is true, the disassembly includs corresponding source lines.
 // The disassembly only includes functions that overlap the range [start, end).
-func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool) {
+func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) {
        if start < d.textStart {
                start = d.textStart
        }
@@ -229,7 +229,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
                var lastFile string
                var lastLine int
 
-               d.Decode(symStart, symEnd, relocs, func(pc, size uint64, file string, line int, text string) {
+               d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) {
                        i := pc - d.textStart
 
                        if printCode {
@@ -266,7 +266,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
 }
 
 // Decode disassembles the text segment range [start, end), calling f for each instruction.
-func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint64, file string, line int, text string)) {
+func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
        if start < d.textStart {
                start = d.textStart
        }
@@ -277,7 +277,7 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6
        lookup := d.lookup
        for pc := start; pc < end; {
                i := pc - d.textStart
-               text, size := d.disasm(code[i:], pc, lookup, d.byteOrder)
+               text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm)
                file, line, _ := d.pcln.PCToLine(pc)
                sep := "\t"
                for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) {
@@ -291,17 +291,17 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6
 }
 
 type lookupFunc = func(addr uint64) (sym string, base uint64)
-type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder) (text string, size int)
+type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int)
 
-func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
-       return disasm_x86(code, pc, lookup, 32)
+func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
+       return disasm_x86(code, pc, lookup, 32, gnuAsm)
 }
 
-func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
-       return disasm_x86(code, pc, lookup, 64)
+func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
+       return disasm_x86(code, pc, lookup, 64, gnuAsm)
 }
 
-func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
+func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) {
        inst, err := x86asm.Decode(code, arch)
        var text string
        size := inst.Len
@@ -309,7 +309,11 @@ func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, in
                size = 1
                text = "?"
        } else {
-               text = x86asm.GoSyntax(inst, pc, lookup)
+               if gnuAsm {
+                       text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil))
+               } else {
+                       text = x86asm.GoSyntax(inst, pc, lookup)
+               }
        }
        return text, size
 }
@@ -334,31 +338,35 @@ func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
        return
 }
 
-func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
+func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
        inst, err := armasm.Decode(code, armasm.ModeARM)
        var text string
        size := inst.Len
        if err != nil || size == 0 || inst.Op == 0 {
                size = 4
                text = "?"
+       } else if gnuAsm {
+               text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst))
        } else {
                text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc})
        }
        return text, size
 }
 
-func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
+func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
        inst, err := arm64asm.Decode(code)
        var text string
        if err != nil || inst.Op == 0 {
                text = "?"
+       } else if gnuAsm {
+               text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst))
        } else {
                text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc})
        }
        return text, 4
 }
 
-func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
+func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
        inst, err := ppc64asm.Decode(code, byteOrder)
        var text string
        size := inst.Len
@@ -366,7 +374,11 @@ func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.By
                size = 4
                text = "?"
        } else {
-               text = ppc64asm.GoSyntax(inst, pc, lookup)
+               if gnuAsm {
+                       text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc))
+               } else {
+                       text = ppc64asm.GoSyntax(inst, pc, lookup)
+               }
        }
        return text, size
 }
index 6a60697ebd4d612850ae021a560ed88d7f8d1b3d..6605f8a60ce18e500f639075da72e0fc99918853 100644 (file)
@@ -43,12 +43,13 @@ import (
        "cmd/internal/objfile"
 )
 
-var printCode = flag.Bool("S", false, "print go code alongside assembly")
+var printCode = flag.Bool("S", false, "print Go code alongside assembly")
 var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
+var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)")
 var symRE *regexp.Regexp
 
 func usage() {
-       fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-s symregexp] binary [start end]\n\n")
+       fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-gnu] [-s symregexp] binary [start end]\n\n")
        flag.PrintDefaults()
        os.Exit(2)
 }
@@ -87,7 +88,7 @@ func main() {
                usage()
        case 1:
                // disassembly of entire object
-               dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode)
+               dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode, *gnuAsm)
 
        case 3:
                // disassembly of PC range
@@ -99,6 +100,6 @@ func main() {
                if err != nil {
                        log.Fatalf("invalid end PC: %v", err)
                }
-               dis.Print(os.Stdout, symRE, start, end, *printCode)
+               dis.Print(os.Stdout, symRE, start, end, *printCode, *gnuAsm)
        }
 }
index 7ed32cf3c2737b0659c657f8aaad333cbfca7592..5030ec65d28952056d8b311af59567f6f199d4d0 100644 (file)
@@ -64,18 +64,42 @@ var x86Need = []string{
        "RET",
 }
 
+var amd64GnuNeed = []string{
+       "movq",
+       "callq",
+       "cmpb",
+}
+
+var i386GnuNeed = []string{
+       "mov",
+       "call",
+       "cmp",
+}
+
 var armNeed = []string{
        "B main.main(SB)",
        "BL main.Println(SB)",
        "RET",
 }
 
+var arm64GnuNeed = []string{
+       "ldr",
+       "bl",
+       "cmp",
+}
+
 var ppcNeed = []string{
        "BR main.main(SB)",
        "CALL main.Println(SB)",
        "RET",
 }
 
+var ppcGnuNeed = []string{
+       "mflr",
+       "lbz",
+       "cmpw",
+}
+
 var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
 
 // objdump is fully cross platform: it can handle binaries
@@ -87,7 +111,7 @@ var target = flag.String("target", "", "test disassembly of `goos/goarch` binary
 // binary for the current system (only) and test that objdump
 // can handle that one.
 
-func testDisasm(t *testing.T, printCode bool, flags ...string) {
+func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string) {
        t.Parallel()
        goarch := runtime.GOARCH
        if *target != "" {
@@ -102,7 +126,7 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
                goarch = f[1]
        }
 
-       hash := md5.Sum([]byte(fmt.Sprintf("%v-%v", flags, printCode)))
+       hash := md5.Sum([]byte(fmt.Sprintf("%v-%v-%v", flags, printCode, printGnuAsm)))
        hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
        args := []string{"build", "-o", hello}
        args = append(args, flags...)
@@ -133,6 +157,18 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
                need = append(need, ppcNeed...)
        }
 
+       if printGnuAsm {
+               switch goarch {
+               case "amd64":
+                       need = append(need, amd64GnuNeed...)
+               case "386":
+                       need = append(need, i386GnuNeed...)
+               case "arm64":
+                       need = append(need, arm64GnuNeed...)
+               case "ppc64", "ppc64le":
+                       need = append(need, ppcGnuNeed...)
+               }
+       }
        args = []string{
                "-s", "main.main",
                hello,
@@ -142,6 +178,9 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
                args = append([]string{"-S"}, args...)
        }
 
+       if printGnuAsm {
+               args = append([]string{"-gnu"}, args...)
+       }
        cmd = exec.Command(exe, args...)
        cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
        out, err = cmd.CombinedOutput()
@@ -180,7 +219,7 @@ func TestDisasm(t *testing.T) {
        case "s390x":
                t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
        }
-       testDisasm(t, false)
+       testDisasm(t, false, false)
 }
 
 func TestDisasmCode(t *testing.T) {
@@ -188,7 +227,17 @@ func TestDisasmCode(t *testing.T) {
        case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
                t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
        }
-       testDisasm(t, true)
+       testDisasm(t, true, false)
+}
+
+func TestDisasmGnuAsm(t *testing.T) {
+       switch runtime.GOARCH {
+       case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
+               t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
+       case "arm":
+               t.Skipf("skipping gnuAsm test on %s", runtime.GOARCH)
+       }
+       testDisasm(t, false, true)
 }
 
 func TestDisasmExtld(t *testing.T) {
@@ -209,7 +258,7 @@ func TestDisasmExtld(t *testing.T) {
        if !build.Default.CgoEnabled {
                t.Skip("skipping because cgo is not enabled")
        }
-       testDisasm(t, false, "-ldflags=-linkmode=external")
+       testDisasm(t, false, false, "-ldflags=-linkmode=external")
 }
 
 func TestDisasmGoobj(t *testing.T) {
index 42e310043d465264599240dbbe947bc822db7967..903f9cc1db918a7eaaa875e5765cee5bd3cd9d67 100644 (file)
@@ -177,7 +177,7 @@ func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error)
                return nil, err
        }
        var asm []driver.Inst
-       d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) {
+       d.Decode(start, end, nil, false, func(pc, size uint64, file string, line int, text string) {
                asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text})
        })
        return asm, nil