delve: support linux-arm64 native debug(#118)

* delve now can be built to arm64-arch and running on linux-arm64 OS.
* arm64 general-purpose registers have completed.
* arm64 disasm has completed.

Co-authored-by: tykcd996 <tang.yuke@zte.com.cn>
Co-authored-by: hengwu0 <wu.heng@zte.com.cn>
This commit is contained in:
hengwu0 2019-10-25 21:22:33 +08:00 committed by Derek Parker
parent be98a8503c
commit 2a68058b4a
29 changed files with 12222 additions and 390 deletions

2
go.mod

@ -19,7 +19,7 @@ require (
github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1 // indirect
github.com/stretchr/testify v1.3.0 // indirect
go.starlark.net v0.0.0-20190702223751-32f345186213
golang.org/x/arch v0.0.0-20171004143515-077ac972c2e4
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4
golang.org/x/crypto v0.0.0-20180614174826-fd5f17ee7299 // indirect
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb
golang.org/x/tools v0.0.0-20181120060634-fc4f04983f62

4
go.sum Normal file → Executable file

@ -45,8 +45,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.starlark.net v0.0.0-20190702223751-32f345186213 h1:lkYv5AKwvvduv5XWP6szk/bvvgO6aDeUujhZQXIFTes=
go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
golang.org/x/arch v0.0.0-20171004143515-077ac972c2e4 h1:TP7YcWHbnFq4v8/3wM2JwgM0SRRtsYJ7Z6Oj0arz2bs=
golang.org/x/arch v0.0.0-20171004143515-077ac972c2e4/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 h1:QlVATYS7JBoZMVaf+cNjb90WD/beKVHnIxFKT4QaHVI=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20180614174826-fd5f17ee7299 h1:zxP+xTjjk4kD+M5IFPweL7/4851FUhYkzbDqbzkN1JE=
golang.org/x/crypto v0.0.0-20180614174826-fd5f17ee7299/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=

299
pkg/proc/amd64_arch.go Normal file

@ -0,0 +1,299 @@
package proc
import (
"encoding/binary"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"golang.org/x/arch/x86/x86asm"
)
// AMD64 represents the AMD64 CPU architecture.
type AMD64 struct {
gStructOffset uint64
goos string
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
// to call C functions. This function in go 1.9 (and previous versions) had
// a bad frame descriptor which needs to be fixed to generate good stack
// traces.
crosscall2fn *Function
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
// the signal handler. See comment in FixFrameUnwindContext for a
// description of why this is needed.
sigreturnfn *Function
}
const (
amd64DwarfIPRegNum uint64 = 16
amd64DwarfSPRegNum uint64 = 7
amd64DwarfBPRegNum uint64 = 6
)
var amd64BreakInstruction = []byte{0xCC}
// AMD64Arch returns an initialized AMD64
// struct.
func AMD64Arch(goos string) *AMD64 {
return &AMD64{
goos: goos,
}
}
// PtrSize returns the size of a pointer
// on this architecture.
func (a *AMD64) PtrSize() int {
return 8
}
// MinInstructionLength returns the min lenth
// of the instruction
func (a *AMD64) MinInstructionLength() int {
return 1
}
// BreakpointInstruction returns the Breakpoint
// instruction for this architecture.
func (a *AMD64) BreakpointInstruction() []byte {
return amd64BreakInstruction
}
// BreakpointSize returns the size of the
// breakpoint instruction on this architecture.
func (a *AMD64) BreakpointSize() int {
return len(amd64BreakInstruction)
}
// DerefTLS returns true if the value of regs.TLS()+GStructOffset() is a
// pointer to the G struct
func (a *AMD64) DerefTLS() bool {
return a.goos == "windows"
}
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
// the default frame unwind context if fctxt is nil.
func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
if a.sigreturnfn == nil {
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
}
if fctxt == nil || (a.sigreturnfn != nil && pc >= a.sigreturnfn.Entry && pc < a.sigreturnfn.End) {
// When there's no frame descriptor entry use BP (the frame pointer) instead
// - return register is [bp + a.PtrSize()] (i.e. [cfa-a.PtrSize()])
// - cfa is bp + a.PtrSize()*2
// - bp is [bp] (i.e. [cfa-a.PtrSize()*2])
// - sp is cfa
// When the signal handler runs it will move the execution to the signal
// handling stack (installed using the sigaltstack system call).
// This isn't a proper stack switch: the pointer to g in TLS will still
// refer to whatever g was executing on that thread before the signal was
// received.
// Since go did not execute a stack switch the previous value of sp, pc
// and bp is not saved inside g.sched, as it normally would.
// The only way to recover is to either read sp/pc from the signal context
// parameter (the ucontext_t* parameter) or to unconditionally follow the
// frame pointer when we get to runtime.sigreturn (which is what we do
// here).
return &frame.FrameContext{
RetAddrReg: amd64DwarfIPRegNum,
Regs: map[uint64]frame.DWRule{
amd64DwarfIPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
amd64DwarfBPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
amd64DwarfSPRegNum: frame.DWRule{
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: amd64DwarfBPRegNum,
Offset: int64(2 * a.PtrSize()),
},
}
}
if a.crosscall2fn == nil {
a.crosscall2fn = bi.LookupFunc["crosscall2"]
}
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
rule := fctxt.CFA
if rule.Offset == crosscall2SPOffsetBad {
switch a.goos {
case "windows":
rule.Offset += crosscall2SPOffsetWindows
default:
rule.Offset += crosscall2SPOffsetNonWindows
}
}
fctxt.CFA = rule
}
// We assume that RBP is the frame pointer and we want to keep it updated,
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't a rule already we emit one.
if fctxt.Regs[amd64DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[amd64DwarfBPRegNum] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: amd64DwarfBPRegNum,
Offset: 0,
}
}
return fctxt
}
// RegSize returns the size (in bytes) of register regnum.
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
func (a *AMD64) RegSize(regnum uint64) int {
// XMM registers
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
return 16
}
// x87 registers
if regnum >= 33 && regnum <= 40 {
return 10
}
return 8
}
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
var amd64DwarfToHardware = map[int]x86asm.Reg{
0: x86asm.RAX,
1: x86asm.RDX,
2: x86asm.RCX,
3: x86asm.RBX,
4: x86asm.RSI,
5: x86asm.RDI,
8: x86asm.R8,
9: x86asm.R9,
10: x86asm.R10,
11: x86asm.R11,
12: x86asm.R12,
13: x86asm.R13,
14: x86asm.R14,
15: x86asm.R15,
}
var amd64DwarfToName = map[int]string{
17: "XMM0",
18: "XMM1",
19: "XMM2",
20: "XMM3",
21: "XMM4",
22: "XMM5",
23: "XMM6",
24: "XMM7",
25: "XMM8",
26: "XMM9",
27: "XMM10",
28: "XMM11",
29: "XMM12",
30: "XMM13",
31: "XMM14",
32: "XMM15",
33: "ST(0)",
34: "ST(1)",
35: "ST(2)",
36: "ST(3)",
37: "ST(4)",
38: "ST(5)",
39: "ST(6)",
40: "ST(7)",
49: "Eflags",
50: "Es",
51: "Cs",
52: "Ss",
53: "Ds",
54: "Fs",
55: "Gs",
58: "Fs_base",
59: "Gs_base",
64: "MXCSR",
65: "CW",
66: "SW",
}
func maxAmd64DwarfRegister() int {
max := int(amd64DwarfIPRegNum)
for i := range amd64DwarfToHardware {
if i > max {
max = i
}
}
for i := range amd64DwarfToName {
if i > max {
max = i
}
}
return max
}
// RegistersToDwarfRegisters converts hardware registers to the format used
// by the DWARF expression interpreter.
func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
for dwarfReg, asmReg := range amd64DwarfToHardware {
v, err := regs.Get(int(asmReg))
if err == nil {
dregs[dwarfReg] = op.DwarfRegisterFromUint64(v)
}
}
for _, reg := range regs.Slice(true) {
for dwarfReg, regName := range amd64DwarfToName {
if regName == reg.Name {
dregs[dwarfReg] = op.DwarfRegisterFromBytes(reg.Bytes)
}
}
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
}
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
}

@ -1,17 +1,15 @@
package proc
import (
"encoding/binary"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"golang.org/x/arch/x86/x86asm"
)
// Arch defines an interface for representing a
// CPU architecture.
type Arch interface {
PtrSize() int
MinInstructionLength() int
BreakpointInstruction() []byte
BreakpointSize() int
DerefTLS() bool
@ -21,292 +19,8 @@ type Arch interface {
AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64) op.DwarfRegisters
}
// AMD64 represents the AMD64 CPU architecture.
type AMD64 struct {
gStructOffset uint64
goos string
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
// to call C functions. This function in go 1.9 (and previous versions) had
// a bad frame descriptor which needs to be fixed to generate good stack
// traces.
crosscall2fn *Function
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
// the signal handler. See comment in FixFrameUnwindContext for a
// description of why this is needed.
sigreturnfn *Function
}
const (
amd64DwarfIPRegNum uint64 = 16
amd64DwarfSPRegNum uint64 = 7
amd64DwarfBPRegNum uint64 = 6
)
var amd64BreakInstruction = []byte{0xCC}
// AMD64Arch returns an initialized AMD64
// struct.
func AMD64Arch(goos string) *AMD64 {
return &AMD64{
goos: goos,
}
}
// PtrSize returns the size of a pointer
// on this architecture.
func (a *AMD64) PtrSize() int {
return 8
}
// BreakpointInstruction returns the Breakpoint
// instruction for this architecture.
func (a *AMD64) BreakpointInstruction() []byte {
return amd64BreakInstruction
}
// BreakpointSize returns the size of the
// breakpoint instruction on this architecture.
func (a *AMD64) BreakpointSize() int {
return len(amd64BreakInstruction)
}
// DerefTLS returns true if the value of regs.TLS()+GStructOffset() is a
// pointer to the G struct
func (a *AMD64) DerefTLS() bool {
return a.goos == "windows"
}
const (
crosscall2SPOffsetBad = 0x8
crosscall2SPOffsetWindows = 0x118
crosscall2SPOffsetNonWindows = 0x58
)
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
// the default frame unwind context if fctxt is nil.
func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
if a.sigreturnfn == nil {
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
}
if fctxt == nil || (a.sigreturnfn != nil && pc >= a.sigreturnfn.Entry && pc < a.sigreturnfn.End) {
// When there's no frame descriptor entry use BP (the frame pointer) instead
// - return register is [bp + a.PtrSize()] (i.e. [cfa-a.PtrSize()])
// - cfa is bp + a.PtrSize()*2
// - bp is [bp] (i.e. [cfa-a.PtrSize()*2])
// - sp is cfa
// When the signal handler runs it will move the execution to the signal
// handling stack (installed using the sigaltstack system call).
// This isn't a proper stack switch: the pointer to g in TLS will still
// refer to whatever g was executing on that thread before the signal was
// received.
// Since go did not execute a stack switch the previous value of sp, pc
// and bp is not saved inside g.sched, as it normally would.
// The only way to recover is to either read sp/pc from the signal context
// parameter (the ucontext_t* parameter) or to unconditionally follow the
// frame pointer when we get to runtime.sigreturn (which is what we do
// here).
return &frame.FrameContext{
RetAddrReg: amd64DwarfIPRegNum,
Regs: map[uint64]frame.DWRule{
amd64DwarfIPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
amd64DwarfBPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
amd64DwarfSPRegNum: frame.DWRule{
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: amd64DwarfBPRegNum,
Offset: int64(2 * a.PtrSize()),
},
}
}
if a.crosscall2fn == nil {
a.crosscall2fn = bi.LookupFunc["crosscall2"]
}
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
rule := fctxt.CFA
if rule.Offset == crosscall2SPOffsetBad {
switch a.goos {
case "windows":
rule.Offset += crosscall2SPOffsetWindows
default:
rule.Offset += crosscall2SPOffsetNonWindows
}
}
fctxt.CFA = rule
}
// We assume that RBP is the frame pointer and we want to keep it updated,
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't a rule already we emit one.
if fctxt.Regs[amd64DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[amd64DwarfBPRegNum] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: amd64DwarfBPRegNum,
Offset: 0,
}
}
return fctxt
}
// RegSize returns the size (in bytes) of register regnum.
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
func (a *AMD64) RegSize(regnum uint64) int {
// XMM registers
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
return 16
}
// x87 registers
if regnum >= 33 && regnum <= 40 {
return 10
}
return 8
}
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
var asm64DwarfToHardware = map[int]x86asm.Reg{
0: x86asm.RAX,
1: x86asm.RDX,
2: x86asm.RCX,
3: x86asm.RBX,
4: x86asm.RSI,
5: x86asm.RDI,
8: x86asm.R8,
9: x86asm.R9,
10: x86asm.R10,
11: x86asm.R11,
12: x86asm.R12,
13: x86asm.R13,
14: x86asm.R14,
15: x86asm.R15,
}
var amd64DwarfToName = map[int]string{
17: "XMM0",
18: "XMM1",
19: "XMM2",
20: "XMM3",
21: "XMM4",
22: "XMM5",
23: "XMM6",
24: "XMM7",
25: "XMM8",
26: "XMM9",
27: "XMM10",
28: "XMM11",
29: "XMM12",
30: "XMM13",
31: "XMM14",
32: "XMM15",
33: "ST(0)",
34: "ST(1)",
35: "ST(2)",
36: "ST(3)",
37: "ST(4)",
38: "ST(5)",
39: "ST(6)",
40: "ST(7)",
49: "Eflags",
50: "Es",
51: "Cs",
52: "Ss",
53: "Ds",
54: "Fs",
55: "Gs",
58: "Fs_base",
59: "Gs_base",
64: "MXCSR",
65: "CW",
66: "SW",
}
func maxAmd64DwarfRegister() int {
max := int(amd64DwarfIPRegNum)
for i := range asm64DwarfToHardware {
if i > max {
max = i
}
}
for i := range amd64DwarfToName {
if i > max {
max = i
}
}
return max
}
// RegistersToDwarfRegisters converts hardware registers to the format used
// by the DWARF expression interpreter.
func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
for dwarfReg, asmReg := range asm64DwarfToHardware {
v, err := regs.Get(int(asmReg))
if err == nil {
dregs[dwarfReg] = op.DwarfRegisterFromUint64(v)
}
}
for _, reg := range regs.Slice(true) {
for dwarfReg, regName := range amd64DwarfToName {
if regName == reg.Name {
dregs[dwarfReg] = op.DwarfRegisterFromBytes(reg.Bytes)
}
}
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
}
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
}

288
pkg/proc/arm64_arch.go Normal file

@ -0,0 +1,288 @@
package proc
import (
"encoding/binary"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"golang.org/x/arch/arm64/arm64asm"
)
// ARM64 represents the ARM64 CPU architecture.
type ARM64 struct {
gStructOffset uint64
goos string
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
// to call C functions. This function in go 1.9 (and previous versions) had
// a bad frame descriptor which needs to be fixed to generate good stack
// traces.
crosscall2fn *Function
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
// the signal handler. See comment in FixFrameUnwindContext for a
// description of why this is needed.
sigreturnfn *Function
}
const (
arm64DwarfIPRegNum uint64 = 32
arm64DwarfSPRegNum uint64 = 31
arm64DwarfBPRegNum uint64 = 29
)
var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
// ARM64Arch returns an initialized ARM64
// struct.
func ARM64Arch(goos string) *ARM64 {
return &ARM64{
goos: goos,
}
}
// PtrSize returns the size of a pointer
// on this architecture.
func (a *ARM64) PtrSize() int {
return 8
}
// MinInstructionLength returns the min lenth
// of the instruction
func (a *ARM64) MinInstructionLength() int {
return 4
}
// BreakpointInstruction returns the Breakpoint
// instruction for this architecture.
func (a *ARM64) BreakpointInstruction() []byte {
return arm64BreakInstruction
}
// BreakpointSize returns the size of the
// breakpoint instruction on this architecture.
func (a *ARM64) BreakpointSize() int {
return len(arm64BreakInstruction)
}
// Always return false for now.
func (a *ARM64) DerefTLS() bool {
return false
}
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
// the default frame unwind context if fctxt is nil.
func (a *ARM64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
if a.sigreturnfn == nil {
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
}
if fctxt == nil || (a.sigreturnfn != nil && pc >= a.sigreturnfn.Entry && pc < a.sigreturnfn.End) {
// When there's no frame descriptor entry use BP (the frame pointer) instead
// - return register is [bp + a.PtrSize()] (i.e. [cfa-a.PtrSize()])
// - cfa is bp + a.PtrSize()*2
// - bp is [bp] (i.e. [cfa-a.PtrSize()*2])
// - sp is cfa
// When the signal handler runs it will move the execution to the signal
// handling stack (installed using the sigaltstack system call).
// This isn't a proper stack switch: the pointer to g in TLS will still
// refer to whatever g was executing on that thread before the signal was
// received.
// Since go did not execute a stack switch the previous value of sp, pc
// and bp is not saved inside g.sched, as it normally would.
// The only way to recover is to either read sp/pc from the signal context
// parameter (the ucontext_t* parameter) or to unconditionally follow the
// frame pointer when we get to runtime.sigreturn (which is what we do
// here).
return &frame.FrameContext{
RetAddrReg: arm64DwarfIPRegNum,
Regs: map[uint64]frame.DWRule{
arm64DwarfIPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
arm64DwarfBPRegNum: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
arm64DwarfSPRegNum: frame.DWRule{
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: arm64DwarfBPRegNum,
Offset: int64(2 * a.PtrSize()),
},
}
}
if a.crosscall2fn == nil {
a.crosscall2fn = bi.LookupFunc["crosscall2"]
}
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
rule := fctxt.CFA
if rule.Offset == crosscall2SPOffsetBad {
switch a.goos {
case "windows":
rule.Offset += crosscall2SPOffsetWindows
default:
rule.Offset += crosscall2SPOffsetNonWindows
}
}
fctxt.CFA = rule
}
// We assume that RBP is the frame pointer and we want to keep it updated,
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't a rule already we emit one.
if fctxt.Regs[arm64DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[arm64DwarfBPRegNum] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: arm64DwarfBPRegNum,
Offset: 0,
}
}
return fctxt
}
func (a *ARM64) RegSize(regnum uint64) int {
// fp registers
if regnum >= 64 && regnum <= 95 {
return 16
}
return 8 // general registers
}
// The mapping between hardware registers and DWARF registers is specified
// in the DWARF for the ARM® Architecture page 7,
// Table 1
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf
var arm64DwarfToHardware = map[int]arm64asm.Reg{
0: arm64asm.X0,
1: arm64asm.X1,
2: arm64asm.X2,
3: arm64asm.X3,
4: arm64asm.X4,
5: arm64asm.X5,
6: arm64asm.X6,
7: arm64asm.X7,
8: arm64asm.X8,
9: arm64asm.X9,
10: arm64asm.X10,
11: arm64asm.X11,
12: arm64asm.X12,
13: arm64asm.X13,
14: arm64asm.X14,
15: arm64asm.X15,
16: arm64asm.X16,
17: arm64asm.X17,
18: arm64asm.X18,
19: arm64asm.X19,
20: arm64asm.X20,
21: arm64asm.X21,
22: arm64asm.X22,
23: arm64asm.X23,
24: arm64asm.X24,
25: arm64asm.X25,
26: arm64asm.X26,
27: arm64asm.X27,
28: arm64asm.X28,
29: arm64asm.X29,
30: arm64asm.X30,
31: arm64asm.SP,
64: arm64asm.V0,
65: arm64asm.V1,
66: arm64asm.V2,
67: arm64asm.V3,
68: arm64asm.V4,
69: arm64asm.V5,
70: arm64asm.V6,
71: arm64asm.V7,
72: arm64asm.V8,
73: arm64asm.V9,
74: arm64asm.V10,
75: arm64asm.V11,
76: arm64asm.V12,
77: arm64asm.V13,
78: arm64asm.V14,
79: arm64asm.V15,
80: arm64asm.V16,
81: arm64asm.V17,
82: arm64asm.V18,
83: arm64asm.V19,
84: arm64asm.V20,
85: arm64asm.V21,
86: arm64asm.V22,
87: arm64asm.V23,
88: arm64asm.V24,
89: arm64asm.V25,
90: arm64asm.V26,
91: arm64asm.V27,
92: arm64asm.V28,
93: arm64asm.V29,
94: arm64asm.V30,
95: arm64asm.V31,
}
func maxArm64DwarfRegister() int {
max := int(arm64DwarfIPRegNum)
for i := range arm64DwarfToHardware {
if i > max {
max = i
}
}
return max
}
// RegistersToDwarfRegisters converts hardware registers to the format used
// by the DWARF expression interpreter.
func (a *ARM64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
for dwarfReg, asmReg := range arm64DwarfToHardware {
v, err := regs.Get(int(asmReg))
if err == nil {
dregs[dwarfReg] = op.DwarfRegisterFromUint64(v)
}
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
}
}
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
}
}

@ -98,7 +98,7 @@ type BinaryInfo struct {
}
// ErrUnsupportedLinuxArch is returned when attempting to debug a binary compiled for an unsupported architecture.
var ErrUnsupportedLinuxArch = errors.New("unsupported architecture - only linux/amd64 is supported")
var ErrUnsupportedLinuxArch = errors.New("unsupported architecture - only linux/amd64 and linux/arm64 are supported")
// ErrUnsupportedWindowsArch is returned when attempting to debug a binary compiled for an unsupported architecture.
var ErrUnsupportedWindowsArch = errors.New("unsupported architecture of windows/386 - only windows/amd64 is supported")
@ -262,6 +262,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
switch goarch {
case "amd64":
r.Arch = AMD64Arch(goos)
case "arm64":
r.Arch = ARM64Arch(goos)
}
return r
@ -825,7 +827,7 @@ func (bi *BinaryInfo) openSeparateDebugInfo(image *Image, exe *elf.File, debugIn
return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, err.Error())
}
if elfFile.Machine != elf.EM_X86_64 {
if elfFile.Machine != elf.EM_X86_64 && elfFile.Machine != elf.EM_AARCH64 {
sepFile.Close()
return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, ErrUnsupportedLinuxArch.Error())
}
@ -873,7 +875,7 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w
if err != nil {
return err
}
if elfFile.Machine != elf.EM_X86_64 {
if elfFile.Machine != elf.EM_X86_64 && elfFile.Machine != elf.EM_AARCH64 {
return ErrUnsupportedLinuxArch
}

@ -32,13 +32,14 @@ func Disassemble(mem MemoryReadWriter, regs Registers, breakpoints *BreakpointMa
}
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startAddr, endAddr uint64, singleInstr bool) ([]AsmInstruction, error) {
minInstructionLength := bi.Arch.MinInstructionLength()
mem := make([]byte, int(endAddr-startAddr))
_, err := memrw.ReadMemory(mem, uintptr(startAddr))
if err != nil {
return nil, err
}
r := make([]AsmInstruction, 0, len(mem)/15)
r := make([]AsmInstruction, 0, len(mem)/int(maxInstructionLength))
pc := startAddr
var curpc uint64
@ -58,15 +59,15 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint
inst, err := asmDecode(mem, pc)
if err == nil {
atpc := (regs != nil) && (curpc == pc)
destloc := resolveCallArg(inst, atpc, regs, memrw, bi)
r = append(r, AsmInstruction{Loc: loc, DestLoc: destloc, Bytes: mem[:inst.Len], Breakpoint: atbp, AtPC: atpc, Inst: inst})
destloc := resolveCallArg(inst, pc, atpc, regs, memrw, bi)
r = append(r, AsmInstruction{Loc: loc, DestLoc: destloc, Bytes: mem[:inst.Size()], Breakpoint: atbp, AtPC: atpc, Inst: inst})
pc += uint64(inst.Size())
mem = mem[inst.Size():]
} else {
r = append(r, AsmInstruction{Loc: loc, Bytes: mem[:1], Breakpoint: atbp, Inst: nil})
pc++
mem = mem[1:]
r = append(r, AsmInstruction{Loc: loc, Bytes: mem[:minInstructionLength], Breakpoint: atbp, Inst: nil})
pc += uint64(minInstructionLength)
mem = mem[minInstructionLength:]
}
if singleInstr {
break

@ -1,3 +1,7 @@
// TODO: disassembler support should be compiled in unconditionally,
// instead of being decided by the build-target architecture, and be
// part of the Arch object instead.
package proc
import (
@ -73,7 +77,7 @@ func (inst *AsmInstruction) IsRet() bool {
return inst.Inst.Op == x86asm.RET || inst.Inst.Op == x86asm.LRET
}
func resolveCallArg(inst *archInst, currentGoroutine bool, regs Registers, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
func resolveCallArg(inst *archInst, instAddr uint64, currentGoroutine bool, regs Registers, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
if inst.Op != x86asm.CALL && inst.Op != x86asm.LCALL {
return nil
}

168
pkg/proc/disasm_arm64.go Normal file

@ -0,0 +1,168 @@
// TODO: disassembler support should be compiled in unconditionally,
// instead of being decided by the build-target architecture, and be
// part of the Arch object instead.
package proc
import (
//"encoding/binary"
"golang.org/x/arch/arm64/arm64asm"
)
var maxInstructionLength uint64 = 4
type archInst arm64asm.Inst
func asmDecode(mem []byte, pc uint64) (*archInst, error) {
inst, err := arm64asm.Decode(mem)
if err != nil {
return nil, err
}
r := archInst(inst)
return &r, nil
}
func (inst *archInst) Size() int {
return 4
}
// Text will return the assembly instructions in human readable format according to
// the flavour specified.
func (inst *AsmInstruction) Text(flavour AssemblyFlavour, bi *BinaryInfo) string {
if inst.Inst == nil {
return "?"
}
var text string
switch flavour {
case GNUFlavour:
text = arm64asm.GNUSyntax(arm64asm.Inst(*inst.Inst))
default:
text = arm64asm.GoSyntax(arm64asm.Inst(*inst.Inst), inst.Loc.PC, bi.symLookup, nil)
}
return text
}
// IsCall returns true if the instruction is a BL or BLR instruction.
func (inst *AsmInstruction) IsCall() bool {
if inst.Inst == nil {
return false
}
return inst.Inst.Op == arm64asm.BL || inst.Inst.Op == arm64asm.BLR
}
// IsRet returns true if the instruction is a RET or ERET instruction.
func (inst *AsmInstruction) IsRet() bool {
if inst.Inst == nil {
return false
}
return inst.Inst.Op == arm64asm.RET || inst.Inst.Op == arm64asm.ERET
}
func resolveCallArg(inst *archInst, instAddr uint64, currentGoroutine bool, regs Registers, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
if inst.Op != arm64asm.BL && inst.Op != arm64asm.BLR {
return nil
}
var pc uint64
var err error
switch arg := inst.Args[0].(type) {
case arm64asm.Imm:
pc = uint64(arg.Imm)
case arm64asm.Reg:
if !currentGoroutine || regs == nil {
return nil
}
pc, err = regs.Get(int(arg))
if err != nil {
return nil
}
case arm64asm.PCRel:
pc = uint64(instAddr) + uint64(arg)
default:
return nil
}
file, line, fn := bininfo.PCToLine(pc)
if fn == nil {
return &Location{PC: pc}
}
return &Location{PC: pc, File: file, Line: line, Fn: fn}
}
type instrseq []arm64asm.Op
// Possible stacksplit prologues are inserted by stacksplit in
// $GOROOT/src/cmd/internal/obj/arm64/obj7.go.
// The stacksplit prologue will always begin with loading curg in CX, this
// instruction is added by load_g_cx in the same file and is either 1 or 2
// MOVs.
var prologues []instrseq
func init() {
var tinyStacksplit = instrseq{arm64asm.MOV, arm64asm.CMP, arm64asm.B}
var smallStacksplit = instrseq{arm64asm.SUB, arm64asm.CMP, arm64asm.B}
var bigStacksplit = instrseq{arm64asm.CMP, arm64asm.B, arm64asm.ADD, arm64asm.SUB, arm64asm.MOV, arm64asm.CMP, arm64asm.B}
var unixGetG = instrseq{arm64asm.MOV}
prologues = make([]instrseq, 0, 3)
for _, getG := range []instrseq{unixGetG} {
for _, stacksplit := range []instrseq{tinyStacksplit, smallStacksplit, bigStacksplit} {
prologue := make(instrseq, 0, len(getG)+len(stacksplit))
prologue = append(prologue, getG...)
prologue = append(prologue, stacksplit...)
prologues = append(prologues, prologue)
}
}
}
// firstPCAfterPrologueDisassembly returns the address of the first
// instruction after the prologue for function fn by disassembling fn and
// matching the instructions against known split-stack prologue patterns.
// If sameline is set firstPCAfterPrologueDisassembly will always return an
// address associated with the same line as fn.Entry
func firstPCAfterPrologueDisassembly(p Process, fn *Function, sameline bool) (uint64, error) {
var mem MemoryReadWriter = p.CurrentThread()
breakpoints := p.Breakpoints()
bi := p.BinInfo()
text, err := disassemble(mem, nil, breakpoints, bi, fn.Entry, fn.End, false)
if err != nil {
return fn.Entry, err
}
if len(text) <= 0 {
return fn.Entry, nil
}
for _, prologue := range prologues {
if len(prologue) >= len(text) {
continue
}
if checkPrologue(text, prologue) {
r := &text[len(prologue)]
if sameline {
if r.Loc.Line != text[0].Loc.Line {
return fn.Entry, nil
}
}
return r.Loc.PC, nil
}
}
return fn.Entry, nil
}
func checkPrologue(s []AsmInstruction, prologuePattern instrseq) bool {
line := s[0].Loc.Line
for i, op := range prologuePattern {
if s[i].Inst.Op != op || s[i].Loc.Line != line {
return false
}
}
return true
}

@ -0,0 +1,139 @@
package linutil
import (
"fmt"
"golang.org/x/arch/arm64/arm64asm"
"github.com/go-delve/delve/pkg/proc"
)
// Regs is a wrapper for sys.PtraceRegs.
type ARM64Registers struct {
Regs *ARM64PtraceRegs //general-purpose registers
Fpregs []proc.Register //Formatted floating point registers
Fpregset []byte //holding all floating point register values
}
// ARM64PtraceRegs is the struct used by the linux kernel to return the
// general purpose registers for ARM64 CPUs.
//copy form sys/unix/ztypes_linux_arm64.go:735
type ARM64PtraceRegs struct {
Regs [31]uint64
Sp uint64
Pc uint64
Pstate uint64
}
// Slice returns the registers as a list of (name, value) pairs.
func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register {
var regs64 = []struct {
k string
v uint64
}{
{"X0", r.Regs.Regs[0]},
{"X1", r.Regs.Regs[1]},
{"X2", r.Regs.Regs[2]},
{"X3", r.Regs.Regs[3]},
{"X4", r.Regs.Regs[4]},
{"X5", r.Regs.Regs[5]},
{"X6", r.Regs.Regs[6]},
{"X7", r.Regs.Regs[7]},
{"X8", r.Regs.Regs[8]},
{"X9", r.Regs.Regs[9]},
{"X10", r.Regs.Regs[10]},
{"X11", r.Regs.Regs[11]},
{"X12", r.Regs.Regs[12]},
{"X13", r.Regs.Regs[13]},
{"X14", r.Regs.Regs[14]},
{"X15", r.Regs.Regs[15]},
{"X16", r.Regs.Regs[16]},
{"X17", r.Regs.Regs[17]},
{"X18", r.Regs.Regs[18]},
{"X19", r.Regs.Regs[19]},
{"X20", r.Regs.Regs[20]},
{"X21", r.Regs.Regs[21]},
{"X22", r.Regs.Regs[22]},
{"X23", r.Regs.Regs[23]},
{"X24", r.Regs.Regs[24]},
{"X25", r.Regs.Regs[25]},
{"X26", r.Regs.Regs[26]},
{"X27", r.Regs.Regs[27]},
{"X28", r.Regs.Regs[28]},
{"X29", r.Regs.Regs[29]},
{"X30", r.Regs.Regs[30]},
{"SP", r.Regs.Sp},
{"PC", r.Regs.Pc},
{"PSTATE", r.Regs.Pstate},
}
out := make([]proc.Register, 0, len(regs64)+len(r.Fpregs))
for _, reg := range regs64 {
out = proc.AppendQwordReg(out, reg.k, reg.v)
}
out = append(out, r.Fpregs...)
return out
}
// PC returns the value of RIP register.
func (r *ARM64Registers) PC() uint64 {
return r.Regs.Pc
}
// SP returns the value of RSP register.
func (r *ARM64Registers) SP() uint64 {
return r.Regs.Sp
}
func (r *ARM64Registers) BP() uint64 {
return r.Regs.Regs[29]
}
// CX returns the value of RCX register.
func (r *ARM64Registers) CX() uint64 {
return 0
}
// TLS returns the address of the thread local storage memory segment.
func (r *ARM64Registers) TLS() uint64 {
return 0
}
// GAddr returns the address of the G variable if it is known, 0 and false
// otherwise.
func (r *ARM64Registers) GAddr() (uint64, bool) {
return r.Regs.Regs[28], true
}
// Get returns the value of the n-th register (in x86asm order).
func (r *ARM64Registers) Get(n int) (uint64, error) {
reg := arm64asm.Reg(n)
if reg >= arm64asm.X0 && reg <= arm64asm.X30 {
return r.Regs.Regs[reg-arm64asm.X0], nil
}
return 0, proc.ErrUnknownRegister
}
// Copy returns a copy of these registers that is guarenteed not to change.
func (r *ARM64Registers) Copy() proc.Registers {
var rr ARM64Registers
rr.Regs = &ARM64PtraceRegs{}
*(rr.Regs) = *(r.Regs)
if r.Fpregs != nil {
rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs)
}
if r.Fpregset != nil {
rr.Fpregset = make([]byte, len(r.Fpregset))
copy(rr.Fpregset, r.Fpregset)
}
return &rr
}
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
func Decode(fpregs []byte) (regs []proc.Register) {
for i := 0; i < len(fpregs); i += 16 {
regs = proc.AppendFPReg(regs, fmt.Sprintf("V%d", i/16), fpregs[i:i+16])
}
return
}

@ -0,0 +1,103 @@
package native
import (
"debug/elf"
"fmt"
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
const (
AARCH64_GREGS_SIZE = 34 * 8
AARCH64_FPREGS_SIZE = 32*16 + 8
)
func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: AARCH64_GREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err == syscall.Errno(0) {
err = nil
}
return
}
func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: AARCH64_GREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err == syscall.Errno(0) {
err = nil
}
return
}
// PtraceGetRegset returns floating point registers of the specified thread
// using PTRACE.
func PtraceGetFpRegset(tid int) (fpregset []byte, err error) {
var arm64_fpregs [AARCH64_FPREGS_SIZE]byte
iov := sys.Iovec{Base: &arm64_fpregs[0], Len: AARCH64_FPREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err != syscall.Errno(0) {
if err == syscall.ENODEV {
err = nil
}
return
} else {
err = nil
}
fpregset = arm64_fpregs[:iov.Len-8]
return fpregset, err
}
// SetPC sets PC to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error {
ir, err := registers(thread, false)
if err != nil {
return err
}
r := ir.(*linutil.ARM64Registers)
r.Regs.Pc = pc
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
return err
}
// SetSP sets RSP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread, false)
if err != nil {
return err
}
r := ir.(*linutil.ARM64Registers)
r.Regs.Sp = sp
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
return
}
func (thread *Thread) SetDX(dx uint64) (err error) {
return fmt.Errorf("not supported")
}
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
var (
regs linutil.ARM64PtraceRegs
err error
)
thread.dbp.execPtraceFunc(func() { err = ptraceGetGRegs(thread.ID, &regs) })
if err != nil {
return nil, err
}
r := &linutil.ARM64Registers{&regs, nil, nil}
if floatingPoint {
r.Fpregs, r.Fpregset, err = thread.fpRegisters()
if err != nil {
return nil, err
}
}
return r, nil
}

@ -0,0 +1,43 @@
package native
import (
"debug/elf"
"fmt"
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
func (thread *Thread) fpRegisters() (fpregs []proc.Register, fpregset []byte, err error) {
thread.dbp.execPtraceFunc(func() { fpregset, err = PtraceGetFpRegset(thread.ID) })
fpregs = linutil.Decode(fpregset)
if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
}
return
}
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
sr := savedRegs.(*linutil.ARM64Registers)
var restoreRegistersErr error
t.dbp.execPtraceFunc(func() {
restoreRegistersErr = ptraceSetGRegs(t.ID, sr.Regs)
if restoreRegistersErr != syscall.Errno(0) {
return
}
if sr.Fpregset != nil {
iov := sys.Iovec{Base: &sr.Fpregset[0], Len: uint64(len(sr.Fpregset))}
_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(t.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
}
//return
})
if restoreRegistersErr == syscall.Errno(0) {
restoreRegistersErr = nil
}
return restoreRegistersErr
}

@ -170,6 +170,43 @@ func AppendSSEReg(regs []Register, name string, xmm []byte) []Register {
return append(regs, Register{name, xmm, out.String()})
}
// AppendFPReg appends a 128 bit FP register to regs.
func AppendFPReg(regs []Register, name string, reg_value []byte) []Register {
buf := bytes.NewReader(reg_value)
var out bytes.Buffer
var vi [16]uint8
for i := range vi {
binary.Read(buf, binary.LittleEndian, &vi[i])
}
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
buf.Seek(0, os.SEEK_SET)
var v2 [2]float64
for i := range v2 {
binary.Read(buf, binary.LittleEndian, &v2[i])
}
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
buf.Seek(0, os.SEEK_SET)
var v4 [4]float32
for i := range v4 {
binary.Read(buf, binary.LittleEndian, &v4[i])
}
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
return append(regs, Register{name, reg_value, out.String()})
}
// ErrUnknownRegister is returned when the value of an unknown
// register is requested.
var ErrUnknownRegister = errors.New("unknown register")

@ -1,90 +0,0 @@
package proc
import (
"bytes"
"encoding/binary"
"golang.org/x/arch/x86/x86asm"
)
var dwarfToAsm = map[int]x86asm.Reg{
0: x86asm.RAX,
1: x86asm.RDX,
2: x86asm.RCX,
3: x86asm.RBX,
4: x86asm.RSI,
5: x86asm.RDI,
6: x86asm.RBP,
7: x86asm.RSP,
8: x86asm.R8,
9: x86asm.R9,
10: x86asm.R10,
11: x86asm.R11,
12: x86asm.R12,
13: x86asm.R13,
14: x86asm.R14,
15: x86asm.R15,
16: x86asm.RIP,
}
var dwarfToName = map[int]string{
17: "XMM0",
18: "XMM1",
19: "XMM2",
20: "XMM3",
21: "XMM4",
22: "XMM5",
23: "XMM6",
24: "XMM7",
25: "XMM8",
26: "XMM9",
27: "XMM10",
28: "XMM11",
29: "XMM12",
30: "XMM13",
31: "XMM14",
32: "XMM15",
33: "ST(0)",
34: "ST(1)",
35: "ST(2)",
36: "ST(3)",
37: "ST(4)",
38: "ST(5)",
39: "ST(6)",
40: "ST(7)",
49: "Eflags",
50: "Es",
51: "Cs",
52: "Ss",
53: "Ds",
54: "Fs",
55: "Gs",
58: "Fs_base",
59: "Gs_base",
64: "MXCSR",
65: "CW",
66: "SW",
}
// GetDwarfRegister maps between DWARF register numbers and architecture
// registers.
// The mapping is specified in the System V ABI AMD64 Architecture Processor
// Supplement page 57, figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
func GetDwarfRegister(regs Registers, i int) []byte {
if asmreg, ok := dwarfToAsm[i]; ok {
x, _ := regs.Get(int(asmreg))
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, x)
return buf.Bytes()
}
if regname, ok := dwarfToName[i]; ok {
regslice := regs.Slice(true)
for _, reg := range regslice {
if reg.Name == regname {
return reg.Bytes
}
}
}
return []byte{}
}

494
vendor/golang.org/x/arch/arm64/arm64asm/arg.go generated vendored Executable file

@ -0,0 +1,494 @@
// Generated by ARM internal tool
// DO NOT EDIT
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
// Naming for Go decoder arguments:
//
// - arg_Wd: a W register encoded in the Rd[4:0] field (31 is wzr)
//
// - arg_Xd: a X register encoded in the Rd[4:0] field (31 is xzr)
//
// - arg_Wds: a W register encoded in the Rd[4:0] field (31 is wsp)
//
// - arg_Xds: a X register encoded in the Rd[4:0] field (31 is sp)
//
// - arg_Wn: encoded in Rn[9:5]
//
// - arg_Wm: encoded in Rm[20:16]
//
// - arg_Wm_extend__UXTB_0__UXTH_1__LSL_UXTW_2__UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4:
// a W register encoded in Rm with an extend encoded in option[15:13] and an amount
// encoded in imm3[12:10] in the range [0,4].
//
// - arg_Rm_extend__UXTB_0__UXTH_1__UXTW_2__LSL_UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4:
// a W or X register encoded in Rm with an extend encoded in option[15:13] and an
// amount encoded in imm3[12:10] in the range [0,4]. If the extend is UXTX or SXTX,
// it's an X register else, it's a W register.
//
// - arg_Wm_shift__LSL_0__LSR_1__ASR_2__0_31:
// a W register encoded in Rm with a shift encoded in shift[23:22] and an amount
// encoded in imm6[15:10] in the range [0,31].
//
// - arg_IAddSub:
// An immediate for a add/sub instruction encoded in imm12[21:10] with an optional
// left shift of 12 encoded in shift[23:22].
//
// - arg_Rt_31_1__W_0__X_1:
// a W or X register encoded in Rt[4:0]. The width specifier is encoded in the field
// [31:31] (offset 31, bit count 1) and the register is W for 0 and X for 1.
//
// - arg_[s|u]label_FIELDS_POWER:
// a program label encoded as "FIELDS" times 2^POWER in the range [MIN, MAX] (determined
// by signd/unsigned, FIELDS and POWER), e.g.
// arg_slabel_imm14_2
// arg_slabel_imm19_2
// arg_slabel_imm26_2
// arg_slabel_immhi_immlo_0
// arg_slabel_immhi_immlo_12
//
// - arg_Xns_mem_post_imm7_8_signed:
// addressing mode of post-index with a base register: Xns and a signed offset encoded
// in the "imm7" field times 8
//
// - arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__3_1:
// addressing mode of extended register with a base register: Xns, an offset register
// (<Wm>|<Xm>) with an extend encoded in option[15:13] and a shift amount encoded in
// S[12:12] in the range [0,3] (S=0:0, S=1:3).
//
// - arg_Xns_mem_optional_imm12_4_unsigned:
// addressing mode of unsigned offset with a base register: Xns and an optional unsigned
// offset encoded in the "imm12" field times 4
//
// - arg_Xns_mem_wb_imm7_4_signed:
// addressing mode of pre-index with a base register: Xns and the signed offset encoded
// in the "imm7" field times 4
//
// - arg_Xns_mem_post_size_1_8_unsigned__4_0__8_1__16_2__32_3:
// a post-index immediate offset, encoded in the "size" field. It can have the following values:
// #4 when size = 00
// #8 when size = 01
// #16 when size = 10
// #32 when size = 11
//
// - arg_immediate_0_127_CRm_op2:
// an immediate encoded in "CRm:op2" in the range 0 to 127
//
// - arg_immediate_bitmask_64_N_imms_immr:
// a bitmask immediate for 64-bit variant and encoded in "N:imms:immr"
//
// - arg_immediate_SBFX_SBFM_64M_bitfield_width_64_imms:
// an immediate for the <width> bitfield of SBFX 64-bit variant
//
// - arg_immediate_shift_32_implicit_inverse_imm16_hw:
// a 32-bit immediate of the bitwise inverse of which can be encoded in "imm16:hw"
//
// - arg_cond_[Not]AllowALNV_[Invert|Normal]:
// a standard condition, encoded in the "cond" field, excluding (NotAllow) AL and NV with
// its least significant bit [Yes|No] inverted, e.g.
// arg_cond_AllowALNV_Normal
// arg_cond_NotAllowALNV_Invert
//
// - arg_immediate_OptLSL_amount_16_0_48:
// An immediate for MOV[KNZ] instruction encoded in imm16[20:5] with an optional
// left shift of 16 in the range [0, 48] encoded in hw[22, 21]
//
// - arg_immediate_0_width_m1_immh_immb__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8:
// the left shift amount, in the range 0 to the operand width in bits minus 1,
// encoded in the "immh:immb" field. It can have the following values:
// (UInt(immh:immb)-8) when immh = 0001
// (UInt(immh:immb)-16) when immh = 001x
// (UInt(immh:immb)-32) when immh = 01xx
// (UInt(immh:immb)-64) when immh = 1xxx
//
// - arg_immediate_1_width_immh_immb__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4:
// the right shift amount, in the range 1 to the destination operand width in
// bits, encoded in the "immh:immb" field. It can have the following values:
// (16-UInt(immh:immb)) when immh = 0001
// (32-UInt(immh:immb)) when immh = 001x
// (64-UInt(immh:immb)) when immh = 01xx
//
// - arg_immediate_8x8_a_b_c_d_e_f_g_h:
// a 64-bit immediate 'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh',
// encoded in "a:b:c:d:e:f:g:h".
//
// - arg_immediate_fbits_min_1_max_32_sub_64_scale:
// the number of bits after the binary point in the fixed-point destination,
// in the range 1 to 32, encoded as 64 minus "scale".
//
// - arg_immediate_floatzero: #0.0
//
// - arg_immediate_exp_3_pre_4_a_b_c_d_e_f_g_h:
// a signed floating-point constant with 3-bit exponent and normalized 4 bits of precision,
// encoded in "a:b:c:d:e:f:g:h"
//
// - arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__64UIntimmhimmb_4__128UIntimmhimmb_8:
// the number of fractional bits, in the range 1 to the operand width, encoded
// in the "immh:immb" field. It can have the following values:
// (64-UInt(immh:immb)) when immh = 01xx
// (128-UInt(immh:immb)) when immh = 1xxx
//
// - arg_immediate_index_Q_imm4__imm4lt20gt_00__imm4_10:
// the lowest numbered byte element to be extracted, encoded in the "Q:imm4" field.
// It can have the following values:
// imm4<2:0> when Q = 0, imm4<3> = 0
// imm4 when Q = 1, imm4<3> = x
//
// - arg_sysop_AT_SYS_CR_system:
// system operation for system instruction: AT encoded in the "op1:CRm<0>:op2" field
//
// - arg_prfop_Rt:
// prefectch operation encoded in the "Rt"
//
// - arg_sysreg_o0_op1_CRn_CRm_op2:
// system register name encoded in the "o0:op1:CRn:CRm:op2"
//
// - arg_pstatefield_op1_op2__SPSel_05__DAIFSet_36__DAIFClr_37:
// PSTATE field name encoded in the "op1:op2" field
//
// - arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31:
// one register with arrangement specifier encoded in the "size:Q" field which can have the following values:
// 8B when size = 00, Q = 0
// 16B when size = 00, Q = 1
// 4H when size = 01, Q = 0
// 8H when size = 01, Q = 1
// 2S when size = 10, Q = 0
// 4S when size = 10, Q = 1
// 2D when size = 11, Q = 1
// The encoding size = 11, Q = 0 is reserved.
//
// - arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31:
// three registers with arrangement specifier encoded in the "size:Q" field which can have the following values:
// 8B when size = 00, Q = 0
// 16B when size = 00, Q = 1
// 4H when size = 01, Q = 0
// 8H when size = 01, Q = 1
// 2S when size = 10, Q = 0
// 4S when size = 10, Q = 1
// 2D when size = 11, Q = 1
// The encoding size = 11, Q = 0 is reserved.
//
// - arg_Vt_1_arrangement_H_index__Q_S_size_1:
// one register with arrangement:H and element index encoded in "Q:S:size<1>".
type instArg uint16
const (
_ instArg = iota
arg_Bt
arg_Cm
arg_Cn
arg_cond_AllowALNV_Normal
arg_conditional
arg_cond_NotAllowALNV_Invert
arg_Da
arg_Dd
arg_Dm
arg_Dn
arg_Dt
arg_Dt2
arg_Hd
arg_Hn
arg_Ht
arg_IAddSub
arg_immediate_0_127_CRm_op2
arg_immediate_0_15_CRm
arg_immediate_0_15_nzcv
arg_immediate_0_31_imm5
arg_immediate_0_31_immr
arg_immediate_0_31_imms
arg_immediate_0_63_b5_b40
arg_immediate_0_63_immh_immb__UIntimmhimmb64_8
arg_immediate_0_63_immr
arg_immediate_0_63_imms
arg_immediate_0_65535_imm16
arg_immediate_0_7_op1
arg_immediate_0_7_op2
arg_immediate_0_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4
arg_immediate_0_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8
arg_immediate_0_width_m1_immh_immb__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8
arg_immediate_0_width_size__8_0__16_1__32_2
arg_immediate_1_64_immh_immb__128UIntimmhimmb_8
arg_immediate_1_width_immh_immb__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4
arg_immediate_1_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4
arg_immediate_1_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4__128UIntimmhimmb_8
arg_immediate_8x8_a_b_c_d_e_f_g_h
arg_immediate_ASR_SBFM_32M_bitfield_0_31_immr
arg_immediate_ASR_SBFM_64M_bitfield_0_63_immr
arg_immediate_BFI_BFM_32M_bitfield_lsb_32_immr
arg_immediate_BFI_BFM_32M_bitfield_width_32_imms
arg_immediate_BFI_BFM_64M_bitfield_lsb_64_immr
arg_immediate_BFI_BFM_64M_bitfield_width_64_imms
arg_immediate_BFXIL_BFM_32M_bitfield_lsb_32_immr
arg_immediate_BFXIL_BFM_32M_bitfield_width_32_imms
arg_immediate_BFXIL_BFM_64M_bitfield_lsb_64_immr
arg_immediate_BFXIL_BFM_64M_bitfield_width_64_imms
arg_immediate_bitmask_32_imms_immr
arg_immediate_bitmask_64_N_imms_immr
arg_immediate_exp_3_pre_4_a_b_c_d_e_f_g_h
arg_immediate_exp_3_pre_4_imm8
arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__64UIntimmhimmb_4__128UIntimmhimmb_8
arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__64UIntimmhimmb_4__128UIntimmhimmb_8
arg_immediate_fbits_min_1_max_32_sub_64_scale
arg_immediate_fbits_min_1_max_64_sub_64_scale
arg_immediate_floatzero
arg_immediate_index_Q_imm4__imm4lt20gt_00__imm4_10
arg_immediate_LSL_UBFM_32M_bitfield_0_31_immr
arg_immediate_LSL_UBFM_64M_bitfield_0_63_immr
arg_immediate_LSR_UBFM_32M_bitfield_0_31_immr
arg_immediate_LSR_UBFM_64M_bitfield_0_63_immr
arg_immediate_MSL__a_b_c_d_e_f_g_h_cmode__8_0__16_1
arg_immediate_optional_0_15_CRm
arg_immediate_optional_0_65535_imm16
arg_immediate_OptLSL__a_b_c_d_e_f_g_h_cmode__0_0__8_1
arg_immediate_OptLSL__a_b_c_d_e_f_g_h_cmode__0_0__8_1__16_2__24_3
arg_immediate_OptLSL_amount_16_0_16
arg_immediate_OptLSL_amount_16_0_48
arg_immediate_OptLSLZero__a_b_c_d_e_f_g_h
arg_immediate_SBFIZ_SBFM_32M_bitfield_lsb_32_immr
arg_immediate_SBFIZ_SBFM_32M_bitfield_width_32_imms
arg_immediate_SBFIZ_SBFM_64M_bitfield_lsb_64_immr
arg_immediate_SBFIZ_SBFM_64M_bitfield_width_64_imms
arg_immediate_SBFX_SBFM_32M_bitfield_lsb_32_immr
arg_immediate_SBFX_SBFM_32M_bitfield_width_32_imms
arg_immediate_SBFX_SBFM_64M_bitfield_lsb_64_immr
arg_immediate_SBFX_SBFM_64M_bitfield_width_64_imms
arg_immediate_shift_32_implicit_imm16_hw
arg_immediate_shift_32_implicit_inverse_imm16_hw
arg_immediate_shift_64_implicit_imm16_hw
arg_immediate_shift_64_implicit_inverse_imm16_hw
arg_immediate_UBFIZ_UBFM_32M_bitfield_lsb_32_immr
arg_immediate_UBFIZ_UBFM_32M_bitfield_width_32_imms
arg_immediate_UBFIZ_UBFM_64M_bitfield_lsb_64_immr
arg_immediate_UBFIZ_UBFM_64M_bitfield_width_64_imms
arg_immediate_UBFX_UBFM_32M_bitfield_lsb_32_immr
arg_immediate_UBFX_UBFM_32M_bitfield_width_32_imms
arg_immediate_UBFX_UBFM_64M_bitfield_lsb_64_immr
arg_immediate_UBFX_UBFM_64M_bitfield_width_64_imms
arg_immediate_zero
arg_option_DMB_BO_system_CRm
arg_option_DSB_BO_system_CRm
arg_option_ISB_BI_system_CRm
arg_prfop_Rt
arg_pstatefield_op1_op2__SPSel_05__DAIFSet_36__DAIFClr_37
arg_Qd
arg_Qn
arg_Qt
arg_Qt2
arg_Rm_extend__UXTB_0__UXTH_1__UXTW_2__LSL_UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4
arg_Rn_16_5__W_1__W_2__W_4__X_8
arg_Rt_31_1__W_0__X_1
arg_Sa
arg_Sd
arg_slabel_imm14_2
arg_slabel_imm19_2
arg_slabel_imm26_2
arg_slabel_immhi_immlo_0
arg_slabel_immhi_immlo_12
arg_Sm
arg_Sn
arg_St
arg_St2
arg_sysop_AT_SYS_CR_system
arg_sysop_DC_SYS_CR_system
arg_sysop_IC_SYS_CR_system
arg_sysop_SYS_CR_system
arg_sysop_TLBI_SYS_CR_system
arg_sysreg_o0_op1_CRn_CRm_op2
arg_Vd_16_5__B_1__H_2__S_4__D_8
arg_Vd_19_4__B_1__H_2__S_4
arg_Vd_19_4__B_1__H_2__S_4__D_8
arg_Vd_19_4__D_8
arg_Vd_19_4__S_4__D_8
arg_Vd_22_1__S_0
arg_Vd_22_1__S_0__D_1
arg_Vd_22_1__S_1
arg_Vd_22_2__B_0__H_1__S_2
arg_Vd_22_2__B_0__H_1__S_2__D_3
arg_Vd_22_2__D_3
arg_Vd_22_2__H_0__S_1__D_2
arg_Vd_22_2__H_1__S_2
arg_Vd_22_2__S_1__D_2
arg_Vd_arrangement_16B
arg_Vd_arrangement_2D
arg_Vd_arrangement_4S
arg_Vd_arrangement_D_index__1
arg_Vd_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4__imm5lt4gt_8_1
arg_Vd_arrangement_imm5_Q___8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__2S_40__4S_41__2D_81
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
arg_Vd_arrangement_immh___SEEAdvancedSIMDmodifiedimmediate_0__8H_1__4S_2__2D_4
arg_Vd_arrangement_Q___2S_0__4S_1
arg_Vd_arrangement_Q___4H_0__8H_1
arg_Vd_arrangement_Q___8B_0__16B_1
arg_Vd_arrangement_Q_sz___2S_00__4S_10__2D_11
arg_Vd_arrangement_size___4S_1__2D_2
arg_Vd_arrangement_size___8H_0__1Q_3
arg_Vd_arrangement_size___8H_0__4S_1__2D_2
arg_Vd_arrangement_size_Q___4H_00__8H_01__2S_10__4S_11__1D_20__2D_21
arg_Vd_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
arg_Vd_arrangement_size_Q___8B_00__16B_01
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Vd_arrangement_sz___4S_0__2D_1
arg_Vd_arrangement_sz_Q___2S_00__4S_01
arg_Vd_arrangement_sz_Q___2S_00__4S_01__2D_11
arg_Vd_arrangement_sz_Q___2S_10__4S_11
arg_Vd_arrangement_sz_Q___4H_00__8H_01__2S_10__4S_11
arg_Vm_22_1__S_0__D_1
arg_Vm_22_2__B_0__H_1__S_2__D_3
arg_Vm_22_2__D_3
arg_Vm_22_2__H_1__S_2
arg_Vm_arrangement_4S
arg_Vm_arrangement_Q___8B_0__16B_1
arg_Vm_arrangement_size___8H_0__4S_1__2D_2
arg_Vm_arrangement_size___H_1__S_2_index__size_L_H_M__HLM_1__HL_2_1
arg_Vm_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
arg_Vm_arrangement_size_Q___8B_00__16B_01
arg_Vm_arrangement_size_Q___8B_00__16B_01__1D_30__2D_31
arg_Vm_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
arg_Vm_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Vm_arrangement_sz_Q___2S_00__4S_01__2D_11
arg_Vm_arrangement_sz___S_0__D_1_index__sz_L_H__HL_00__H_10_1
arg_Vn_19_4__B_1__H_2__S_4__D_8
arg_Vn_19_4__D_8
arg_Vn_19_4__H_1__S_2__D_4
arg_Vn_19_4__S_4__D_8
arg_Vn_1_arrangement_16B
arg_Vn_22_1__D_1
arg_Vn_22_1__S_0__D_1
arg_Vn_22_2__B_0__H_1__S_2__D_3
arg_Vn_22_2__D_3
arg_Vn_22_2__H_0__S_1__D_2
arg_Vn_22_2__H_1__S_2
arg_Vn_2_arrangement_16B
arg_Vn_3_arrangement_16B
arg_Vn_4_arrangement_16B
arg_Vn_arrangement_16B
arg_Vn_arrangement_4S
arg_Vn_arrangement_D_index__1
arg_Vn_arrangement_D_index__imm5_1
arg_Vn_arrangement_imm5___B_1__H_2_index__imm5__imm5lt41gt_1__imm5lt42gt_2_1
arg_Vn_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5_imm4__imm4lt30gt_1__imm4lt31gt_2__imm4lt32gt_4__imm4lt3gt_8_1
arg_Vn_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4__imm5lt4gt_8_1
arg_Vn_arrangement_imm5___B_1__H_2__S_4_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4_1
arg_Vn_arrangement_imm5___D_8_index__imm5_1
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__2S_40__4S_41__2D_81
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
arg_Vn_arrangement_immh___SEEAdvancedSIMDmodifiedimmediate_0__8H_1__4S_2__2D_4
arg_Vn_arrangement_Q___8B_0__16B_1
arg_Vn_arrangement_Q_sz___2S_00__4S_10__2D_11
arg_Vn_arrangement_Q_sz___4S_10
arg_Vn_arrangement_S_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4_1
arg_Vn_arrangement_size___2D_3
arg_Vn_arrangement_size___8H_0__4S_1__2D_2
arg_Vn_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
arg_Vn_arrangement_size_Q___8B_00__16B_01
arg_Vn_arrangement_size_Q___8B_00__16B_01__1D_30__2D_31
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__4S_21
arg_Vn_arrangement_sz___2D_1
arg_Vn_arrangement_sz___2S_0__2D_1
arg_Vn_arrangement_sz___4S_0__2D_1
arg_Vn_arrangement_sz_Q___2S_00__4S_01
arg_Vn_arrangement_sz_Q___2S_00__4S_01__2D_11
arg_Vn_arrangement_sz_Q___4H_00__8H_01__2S_10__4S_11
arg_Vt_1_arrangement_B_index__Q_S_size_1
arg_Vt_1_arrangement_D_index__Q_1
arg_Vt_1_arrangement_H_index__Q_S_size_1
arg_Vt_1_arrangement_S_index__Q_S_1
arg_Vt_1_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
arg_Vt_2_arrangement_B_index__Q_S_size_1
arg_Vt_2_arrangement_D_index__Q_1
arg_Vt_2_arrangement_H_index__Q_S_size_1
arg_Vt_2_arrangement_S_index__Q_S_1
arg_Vt_2_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
arg_Vt_2_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Vt_3_arrangement_B_index__Q_S_size_1
arg_Vt_3_arrangement_D_index__Q_1
arg_Vt_3_arrangement_H_index__Q_S_size_1
arg_Vt_3_arrangement_S_index__Q_S_1
arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Vt_4_arrangement_B_index__Q_S_size_1
arg_Vt_4_arrangement_D_index__Q_1
arg_Vt_4_arrangement_H_index__Q_S_size_1
arg_Vt_4_arrangement_S_index__Q_S_1
arg_Vt_4_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
arg_Vt_4_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
arg_Wa
arg_Wd
arg_Wds
arg_Wm
arg_Wm_extend__UXTB_0__UXTH_1__LSL_UXTW_2__UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4
arg_Wm_shift__LSL_0__LSR_1__ASR_2__0_31
arg_Wm_shift__LSL_0__LSR_1__ASR_2__ROR_3__0_31
arg_Wn
arg_Wns
arg_Ws
arg_Wt
arg_Wt2
arg_Xa
arg_Xd
arg_Xds
arg_Xm
arg_Xm_shift__LSL_0__LSR_1__ASR_2__0_63
arg_Xm_shift__LSL_0__LSR_1__ASR_2__ROR_3__0_63
arg_Xn
arg_Xns
arg_Xns_mem
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__1_1
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__2_1
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__3_1
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__4_1
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__absent_0__0_1
arg_Xns_mem_offset
arg_Xns_mem_optional_imm12_16_unsigned
arg_Xns_mem_optional_imm12_1_unsigned
arg_Xns_mem_optional_imm12_2_unsigned
arg_Xns_mem_optional_imm12_4_unsigned
arg_Xns_mem_optional_imm12_8_unsigned
arg_Xns_mem_optional_imm7_16_signed
arg_Xns_mem_optional_imm7_4_signed
arg_Xns_mem_optional_imm7_8_signed
arg_Xns_mem_optional_imm9_1_signed
arg_Xns_mem_post_fixedimm_1
arg_Xns_mem_post_fixedimm_12
arg_Xns_mem_post_fixedimm_16
arg_Xns_mem_post_fixedimm_2
arg_Xns_mem_post_fixedimm_24
arg_Xns_mem_post_fixedimm_3
arg_Xns_mem_post_fixedimm_32
arg_Xns_mem_post_fixedimm_4
arg_Xns_mem_post_fixedimm_6
arg_Xns_mem_post_fixedimm_8
arg_Xns_mem_post_imm7_16_signed
arg_Xns_mem_post_imm7_4_signed
arg_Xns_mem_post_imm7_8_signed
arg_Xns_mem_post_imm9_1_signed
arg_Xns_mem_post_Q__16_0__32_1
arg_Xns_mem_post_Q__24_0__48_1
arg_Xns_mem_post_Q__32_0__64_1
arg_Xns_mem_post_Q__8_0__16_1
arg_Xns_mem_post_size__1_0__2_1__4_2__8_3
arg_Xns_mem_post_size__2_0__4_1__8_2__16_3
arg_Xns_mem_post_size__3_0__6_1__12_2__24_3
arg_Xns_mem_post_size__4_0__8_1__16_2__32_3
arg_Xns_mem_post_Xm
arg_Xns_mem_wb_imm7_16_signed
arg_Xns_mem_wb_imm7_4_signed
arg_Xns_mem_wb_imm7_8_signed
arg_Xns_mem_wb_imm9_1_signed
arg_Xs
arg_Xt
arg_Xt2
)

329
vendor/golang.org/x/arch/arm64/arm64asm/condition.go generated vendored Executable file

@ -0,0 +1,329 @@
// Generated by ARM internal tool
// DO NOT EDIT
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
// Following functions are used as the predicator: canDecode of according instruction
// Refer to instFormat inside decode.go for more details
func at_sys_cr_system_cond(instr uint32) bool {
return sys_op_4((instr>>16)&0x7, 0x7, 0x8, (instr>>5)&0x7) == Sys_AT
}
func bfi_bfm_32m_bitfield_cond(instr uint32) bool {
return (instr>>5)&0x1f != 0x1f && uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func bfi_bfm_64m_bitfield_cond(instr uint32) bool {
return (instr>>5)&0x1f != 0x1f && uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func bfxil_bfm_32m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) >= uint8((instr>>16)&0x3f)
}
func bfxil_bfm_64m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) >= uint8((instr>>16)&0x3f)
}
func cinc_csinc_32_condsel_cond(instr uint32) bool {
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func cinc_csinc_64_condsel_cond(instr uint32) bool {
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func cinv_csinv_32_condsel_cond(instr uint32) bool {
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func cinv_csinv_64_condsel_cond(instr uint32) bool {
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func cneg_csneg_32_condsel_cond(instr uint32) bool {
return instr&0xe000 != 0xe000 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func cneg_csneg_64_condsel_cond(instr uint32) bool {
return instr&0xe000 != 0xe000 && (instr>>5)&0x1f == (instr>>16)&0x1f
}
func csinc_general_cond(instr uint32) bool {
return instr&0xe000 != 0xe000
}
func csinv_general_cond(instr uint32) bool {
return instr&0xe000 != 0xe000
}
func dc_sys_cr_system_cond(instr uint32) bool {
return sys_op_4((instr>>16)&0x7, 0x7, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_DC
}
func ic_sys_cr_system_cond(instr uint32) bool {
return sys_op_4((instr>>16)&0x7, 0x7, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_IC
}
func lsl_ubfm_32m_bitfield_cond(instr uint32) bool {
return instr&0xfc00 != 0x7c00 && (instr>>10)&0x3f+1 == (instr>>16)&0x3f
}
func lsl_ubfm_64m_bitfield_cond(instr uint32) bool {
return instr&0xfc00 != 0xfc00 && (instr>>10)&0x3f+1 == (instr>>16)&0x3f
}
func mov_orr_32_log_imm_cond(instr uint32) bool {
return !move_wide_preferred_4((instr>>31)&0x1, (instr>>22)&0x1, (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func mov_orr_64_log_imm_cond(instr uint32) bool {
return !move_wide_preferred_4((instr>>31)&0x1, (instr>>22)&0x1, (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func mov_movn_32_movewide_cond(instr uint32) bool {
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0) && !is_ones_n16((instr>>5)&0xffff)
}
func mov_movn_64_movewide_cond(instr uint32) bool {
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
}
func mov_add_32_addsub_imm_cond(instr uint32) bool {
return instr&0x1f == 0x1f || (instr>>5)&0x1f == 0x1f
}
func mov_add_64_addsub_imm_cond(instr uint32) bool {
return instr&0x1f == 0x1f || (instr>>5)&0x1f == 0x1f
}
func mov_movz_32_movewide_cond(instr uint32) bool {
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
}
func mov_movz_64_movewide_cond(instr uint32) bool {
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
}
func ror_extr_32_extract_cond(instr uint32) bool {
return (instr>>5)&0x1f == (instr>>16)&0x1f
}
func ror_extr_64_extract_cond(instr uint32) bool {
return (instr>>5)&0x1f == (instr>>16)&0x1f
}
func sbfiz_sbfm_32m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func sbfiz_sbfm_64m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func sbfx_sbfm_32m_bitfield_cond(instr uint32) bool {
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func sbfx_sbfm_64m_bitfield_cond(instr uint32) bool {
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func tlbi_sys_cr_system_cond(instr uint32) bool {
return sys_op_4((instr>>16)&0x7, 0x8, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_TLBI
}
func ubfiz_ubfm_32m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func ubfiz_ubfm_64m_bitfield_cond(instr uint32) bool {
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
}
func ubfx_ubfm_32m_bitfield_cond(instr uint32) bool {
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func ubfx_ubfm_64m_bitfield_cond(instr uint32) bool {
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
}
func fcvtzs_asisdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func fcvtzs_asimdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func fcvtzu_asisdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func fcvtzu_asimdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func mov_umov_asimdins_w_w_cond(instr uint32) bool {
return ((instr>>16)&0x1f)&0x7 == 0x4
}
func mov_umov_asimdins_x_x_cond(instr uint32) bool {
return ((instr>>16)&0x1f)&0xf == 0x8
}
func mov_orr_asimdsame_only_cond(instr uint32) bool {
return (instr>>16)&0x1f == (instr>>5)&0x1f
}
func rshrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func scvtf_asisdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func scvtf_asimdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func shl_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func shl_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func shrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sli_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sli_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqrshrn_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqrshrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqrshrun_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqrshrun_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshl_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshl_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshlu_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshlu_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshrn_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshrun_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sqshrun_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sri_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sri_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func srshr_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func srshr_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func srsra_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func srsra_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sshll_asimdshf_l_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sshr_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sshr_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ssra_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ssra_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func sxtl_sshll_asimdshf_l_cond(instr uint32) bool {
return instr&0x780000 != 0x0 && bit_count((instr>>19)&0xf) == 1
}
func ucvtf_asisdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ucvtf_asimdshf_c_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqrshrn_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqrshrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqshl_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqshl_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqshrn_asisdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uqshrn_asimdshf_n_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func urshr_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func urshr_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ursra_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ursra_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ushll_asimdshf_l_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ushr_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func ushr_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func usra_asisdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func usra_asimdshf_r_cond(instr uint32) bool {
return instr&0x780000 != 0x0
}
func uxtl_ushll_asimdshf_l_cond(instr uint32) bool {
return instr&0x780000 != 0x0 && bit_count((instr>>19)&0xf) == 1
}

81
vendor/golang.org/x/arch/arm64/arm64asm/condition_util.go generated vendored Executable file

@ -0,0 +1,81 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
func extract_bit(value, bit uint32) uint32 {
return (value >> bit) & 1
}
func bfxpreferred_4(sf, opc1, imms, immr uint32) bool {
if imms < immr {
return false
}
if (imms>>5 == sf) && (imms&0x1f == 0x1f) {
return false
}
if immr == 0 {
if sf == 0 && (imms == 7 || imms == 15) {
return false
}
if sf == 1 && opc1 == 0 && (imms == 7 ||
imms == 15 || imms == 31) {
return false
}
}
return true
}
func move_wide_preferred_4(sf, N, imms, immr uint32) bool {
if sf == 1 && N != 1 {
return false
}
if sf == 0 && !(N == 0 && ((imms>>5)&1) == 0) {
return false
}
if imms < 16 {
return (-immr)%16 <= (15 - imms)
}
width := uint32(32)
if sf == 1 {
width = uint32(64)
}
if imms >= (width - 15) {
return (immr % 16) <= (imms - (width - 15))
}
return false
}
type Sys uint8
const (
Sys_AT Sys = iota
Sys_DC
Sys_IC
Sys_TLBI
Sys_SYS
)
func sys_op_4(op1, crn, crm, op2 uint32) Sys {
// TODO: system instruction
return Sys_SYS
}
func is_zero(x uint32) bool {
return x == 0
}
func is_ones_n16(x uint32) bool {
return x == 0xffff
}
func bit_count(x uint32) uint8 {
var count uint8
for count = 0; x > 0; x >>= 1 {
if (x & 1) == 1 {
count++
}
}
return count
}

2768
vendor/golang.org/x/arch/arm64/arm64asm/decode.go generated vendored Executable file

File diff suppressed because it is too large Load Diff

88
vendor/golang.org/x/arch/arm64/arm64asm/decode_test.go generated vendored Executable file

@ -0,0 +1,88 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
import (
"encoding/hex"
"io/ioutil"
"path/filepath"
"strings"
"testing"
)
func testDecode(t *testing.T, syntax string) {
input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil {
t.Fatal(err)
}
all := string(data)
for strings.Contains(all, "\t\t") {
all = strings.Replace(all, "\t\t", "\t", -1)
}
for _, line := range strings.Split(all, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.SplitN(line, "\t", 2)
i := strings.Index(f[0], "|")
if i < 0 {
t.Errorf("parsing %q: missing | separator", f[0])
continue
}
if i%2 != 0 {
t.Errorf("parsing %q: misaligned | separator", f[0])
}
code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
if err != nil {
t.Errorf("parsing %q: %v", f[0], err)
continue
}
asm := f[1]
inst, decodeErr := Decode(code)
if decodeErr != nil && decodeErr != errUnknown {
// Some rarely used system instructions are not supported
// Following logicals will filter such unknown instructions
t.Errorf("parsing %x: %s", code, decodeErr)
continue
}
var out string
switch syntax {
case "gnu":
out = GNUSyntax(inst)
case "plan9":
out = GoSyntax(inst, 0, nil, nil)
default:
t.Errorf("unknown syntax %q", syntax)
continue
}
// TODO: system instruction.
var Todo = strings.Fields(`
sys
dc
at
tlbi
ic
hvc
smc
`)
if strings.Replace(out, " ", "", -1) != strings.Replace(asm, " ", "", -1) && !hasPrefix(asm, Todo...) {
// Exclude MSR since GNU objdump result is incorrect. eg. 0xd504431f msr s0_4_c4_c3_0, xzr
if !strings.HasSuffix(asm, " nv") && !strings.HasPrefix(asm, "msr") {
t.Errorf("Decode(%s) [%s] = %s, want %s", strings.Trim(f[0], "|"), syntax, out, asm)
}
}
}
}
func TestDecodeGNUSyntax(t *testing.T) {
testDecode(t, "gnu")
}
func TestDecodeGoSyntax(t *testing.T) {
testDecode(t, "plan9")
}

604
vendor/golang.org/x/arch/arm64/arm64asm/ext_test.go generated vendored Executable file

@ -0,0 +1,604 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Support for testing against external disassembler program.
// Copied and simplified from ../../arm/armasm/ext_test.go.
package arm64asm
import (
"bufio"
"bytes"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"time"
)
var (
dumpTest = flag.Bool("dump", false, "dump all encodings")
mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
longTest = flag.Bool("long", false, "long test")
keep = flag.Bool("keep", false, "keep object files around")
debug = false
)
// An ExtInst represents a single decoded instruction parsed
// from an external disassembler's output.
type ExtInst struct {
addr uint64
enc [4]byte
nenc int
text string
}
func (r ExtInst) String() string {
return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
}
// An ExtDis is a connection between an external disassembler and a test.
type ExtDis struct {
Arch Mode
Dec chan ExtInst
File *os.File
Size int
KeepFile bool
Cmd *exec.Cmd
}
// InstJson describes instruction fields value got from ARMv8-A Reference Manual
type InstJson struct {
Name string
Bits string
Arch string
Syntax string
Code string
Alias string
Enc uint32
}
// A Mode is an instruction execution mode.
type Mode int
const (
_ Mode = iota
ModeARM64
)
// Run runs the given command - the external disassembler - and returns
// a buffered reader of its standard output.
func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
if *keep {
log.Printf("%s\n", strings.Join(cmd, " "))
}
ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
out, err := ext.Cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("stdoutpipe: %v", err)
}
if err := ext.Cmd.Start(); err != nil {
return nil, fmt.Errorf("exec: %v", err)
}
b := bufio.NewReaderSize(out, 1<<20)
return b, nil
}
// Wait waits for the command started with Run to exit.
func (ext *ExtDis) Wait() error {
return ext.Cmd.Wait()
}
// testExtDis tests a set of byte sequences against an external disassembler.
// The disassembler is expected to produce the given syntax and run
// in the given architecture mode (16, 32, or 64-bit).
// The extdis function must start the external disassembler
// and then parse its output, sending the parsed instructions on ext.Dec.
// The generate function calls its argument f once for each byte sequence
// to be tested. The generate function itself will be called twice, and it must
// make the same sequence of calls to f each time.
// When a disassembly does not match the internal decoding,
// allowedMismatch determines whether this mismatch should be
// allowed, or else considered an error.
func testExtDis(
t *testing.T,
syntax string,
arch Mode,
extdis func(ext *ExtDis) error,
generate func(f func([]byte)),
allowedMismatch func(text string, inst *Inst, dec ExtInst) bool,
) {
start := time.Now()
ext := &ExtDis{
Dec: make(chan ExtInst),
Arch: arch,
}
errc := make(chan error)
// First pass: write instructions to input file for external disassembler.
file, f, size, err := writeInst(generate)
if err != nil {
t.Fatal(err)
}
ext.Size = size
ext.File = f
defer func() {
f.Close()
if !*keep {
os.Remove(file)
}
}()
// Second pass: compare disassembly against our decodings.
var (
totalTests = 0
totalSkips = 0
totalErrors = 0
errors = make([]string, 0, 100) // Sampled errors, at most cap
)
go func() {
errc <- extdis(ext)
}()
generate(func(enc []byte) {
dec, ok := <-ext.Dec
if !ok {
t.Errorf("decoding stream ended early")
return
}
inst, text := disasm(syntax, pad(enc))
totalTests++
if *dumpTest {
fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
}
if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" {
suffix := ""
if allowedMismatch(text, &inst, dec) {
totalSkips++
if !*mismatch {
return
}
suffix += " (allowed mismatch)"
}
totalErrors++
cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix)
if len(errors) >= cap(errors) {
j := rand.Intn(totalErrors)
if j >= cap(errors) {
return
}
errors = append(errors[:j], errors[j+1:]...)
}
errors = append(errors, cmp)
}
})
if *mismatch {
totalErrors -= totalSkips
}
for _, b := range errors {
t.Log(b)
}
if totalErrors > 0 {
t.Fail()
}
t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage())
if err := <-errc; err != nil {
t.Fatalf("external disassembler: %v", err)
}
}
// Start address of text.
const start = 0x8000
// writeInst writes the generated byte sequences to a new file
// starting at offset start. That file is intended to be the input to
// the external disassembler.
func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
f, err = ioutil.TempFile("", "arm64asm")
if err != nil {
return
}
file = f.Name()
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
generate(func(x []byte) {
if debug {
fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):])
}
w.Write(x)
w.Write(zeros[len(x):])
size += len(zeros)
})
return file, f, size, nil
}
var zeros = []byte{0, 0, 0, 0}
// pad pads the code sequence with pops.
func pad(enc []byte) []byte {
if len(enc) < 4 {
enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
}
return enc
}
// disasm returns the decoded instruction and text
// for the given source bytes, using the given syntax and mode.
func disasm(syntax string, src []byte) (inst Inst, text string) {
var err error
inst, err = Decode(src)
if err != nil {
text = "error: " + err.Error()
return
}
text = inst.String()
switch syntax {
case "gnu":
text = GNUSyntax(inst)
case "plan9": // [sic]
text = GoSyntax(inst, 0, nil, nil)
default:
text = "error: unknown syntax " + syntax
}
return
}
// decodecoverage returns a floating point number denoting the
// decoder coverage.
func decodeCoverage() float64 {
n := 0
for _, t := range decoderCover {
if t {
n++
}
}
return 100 * float64(1+n) / float64(1+len(decoderCover))
}
// Helpers for writing disassembler output parsers.
// hasPrefix reports whether any of the space-separated words in the text s
// begins with any of the given prefixes.
func hasPrefix(s string, prefixes ...string) bool {
for _, prefix := range prefixes {
for cur_s := s; cur_s != ""; {
if strings.HasPrefix(cur_s, prefix) {
return true
}
i := strings.Index(cur_s, " ")
if i < 0 {
break
}
cur_s = cur_s[i+1:]
}
}
return false
}
// isHex reports whether b is a hexadecimal character (0-9a-fA-F).
func isHex(b byte) bool {
return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F')
}
// parseHex parses the hexadecimal byte dump in hex,
// appending the parsed bytes to raw and returning the updated slice.
// The returned bool reports whether any invalid hex was found.
// Spaces and tabs between bytes are okay but any other non-hex is not.
func parseHex(hex []byte, raw []byte) ([]byte, bool) {
hex = bytes.TrimSpace(hex)
for j := 0; j < len(hex); {
for hex[j] == ' ' || hex[j] == '\t' {
j++
}
if j >= len(hex) {
break
}
if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
return nil, false
}
raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1]))
j += 2
}
return raw, true
}
func unhex(b byte) byte {
if '0' <= b && b <= '9' {
return b - '0'
} else if 'A' <= b && b <= 'F' {
return b - 'A' + 10
} else if 'a' <= b && b <= 'f' {
return b - 'a' + 10
}
return 0
}
// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
func index(s []byte, t string) int {
i := 0
for {
j := bytes.IndexByte(s[i:], t[0])
if j < 0 {
return -1
}
i = i + j
if i+len(t) > len(s) {
return -1
}
for k := 1; k < len(t); k++ {
if s[i+k] != t[k] {
goto nomatch
}
}
return i
nomatch:
i++
}
}
// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
// If s must be rewritten, it is rewritten in place.
func fixSpace(s []byte) []byte {
s = bytes.TrimSpace(s)
for i := 0; i < len(s); i++ {
if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
goto Fix
}
}
return s
Fix:
b := s
w := 0
for i := 0; i < len(s); i++ {
c := s[i]
if c == '\t' || c == '\n' {
c = ' '
}
if c == ' ' && w > 0 && b[w-1] == ' ' {
continue
}
b[w] = c
w++
}
if w > 0 && b[w-1] == ' ' {
w--
}
return b[:w]
}
// Fllowing regular expressions matches instructions using relative addressing mode.
// pcrel matches B instructions and BL instructions.
// pcrelr matches instrucions which consisted of register arguments and label arguments.
// pcrelim matches instructions which consisted of register arguments, immediate
// arguments and lable arguments.
// pcrelrzr and prcelimzr matches instructions when register arguments is zero register.
// pcrelprfm matches PRFM instructions when arguments consisted of register and lable.
// pcrelprfmim matches PRFM instructions when arguments consisted of immediate and lable.
var (
pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bl)x?(?:\.)?(?:eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|nv)?) 0x([0-9a-f]+)$`)
pcrelr = regexp.MustCompile(`^((?:.*)?(?:ldr|adrp|adr|cbnz|cbz|ldrsw) (?:x|w|s|d|q)(?:[0-9]+,)) 0x([0-9a-f]+)$`)
pcrelrzr = regexp.MustCompile(`^((?:.*)?(?:ldr|adrp|adr|cbnz|cbz|ldrsw) (?:x|w)zr,) 0x([0-9a-f]+)$`)
pcrelim = regexp.MustCompile(`^((?:.*)?(?:tbnz|tbz) (?:x|w)(?:[0-9]+,) (?:#[0-9a-f]+,)) 0x([0-9a-f]+)$`)
pcrelimzr = regexp.MustCompile(`^((?:.*)?(?:tbnz|tbz) (?:x|w)zr, (?:#[0-9a-f]+,)) 0x([0-9a-f]+)$`)
pcrelprfm = regexp.MustCompile(`^((?:.*)?(?:prfm) (?:[0-9a-z]+,)) 0x([0-9a-f]+)$`)
pcrelprfmim = regexp.MustCompile(`^((?:.*)?(?:prfm) (?:#0x[0-9a-f]+,)) 0x([0-9a-f]+)$`)
)
// Round is the multiple of the number of instructions that read from Json file.
// Round used as seed value for pseudo-random number generator provides the same sequence
// in the same round run for the external disassembler and decoder.
var Round int
// condmark is used to mark conditional instructions when need to generate and test
// conditional instructions.
var condmark bool = false
// Generate instruction binary according to Json file
// Encode variable field of instruction with random value
func doFuzzy(inst *InstJson, Ninst int) {
var testdata uint32
var NonDigRE = regexp.MustCompile(`[\D]`)
rand.Seed(int64(Round + Ninst))
off := 0
DigBit := ""
if condmark == true && !strings.Contains(inst.Bits, "cond") {
inst.Enc = 0xffffffff
} else {
for _, f := range strings.Split(inst.Bits, "|") {
if i := strings.Index(f, ":"); i >= 0 {
// consider f contains "01:2" and "Rm:5"
DigBit = f[:i]
m := NonDigRE.FindStringSubmatch(DigBit)
if m == nil {
DigBit = strings.TrimSpace(DigBit)
s := strings.Split(DigBit, "")
for i := 0; i < len(s); i++ {
switch s[i] {
case "1", "(1)":
testdata |= 1 << uint(31-off)
}
off++
}
} else {
// DigBit is "Rn" or "imm3"
n, _ := strconv.Atoi(f[i+1:])
if DigBit == "cond" && condmark == true {
r := uint8(Round)
for i := n - 1; i >= 0; i-- {
switch (r >> uint(i)) & 1 {
case 1:
testdata |= 1 << uint(31-off)
}
off++
}
} else {
for i := 0; i < n; i++ {
r := rand.Intn(2)
switch r {
case 1:
testdata |= 1 << uint(31-off)
}
off++
}
}
}
continue
}
for _, bit := range strings.Fields(f) {
switch bit {
case "0", "(0)":
off++
continue
case "1", "(1)":
testdata |= 1 << uint(31-off)
default:
r := rand.Intn(2)
switch r {
case 1:
testdata |= 1 << uint(31-off)
}
}
off++
}
}
if off != 32 {
log.Printf("incorrect bit count for %s %s: have %d", inst.Name, inst.Bits, off)
}
inst.Enc = testdata
}
}
// Generators.
//
// The test cases are described as functions that invoke a callback repeatedly,
// with a new input sequence each time. These helpers make writing those
// a little easier.
// JSONCases generates ARM64 instructions according to inst.json.
func JSONCases(t *testing.T) func(func([]byte)) {
return func(try func([]byte)) {
data, err := ioutil.ReadFile("inst.json")
if err != nil {
t.Fatal(err)
}
var insts []InstJson
var instsN []InstJson
// Change N value to get more cases only when condmark=false.
N := 100
if condmark == true {
N = 16
}
if err := json.Unmarshal(data, &insts); err != nil {
t.Fatal(err)
}
// Append instructions to get more test cases.
for i := 0; i < N; {
for _, inst := range insts {
instsN = append(instsN, inst)
}
i++
}
Round = 0
for i := range instsN {
if i%len(insts) == 0 {
Round++
}
doFuzzy(&instsN[i], i)
}
for _, inst := range instsN {
if condmark == true && inst.Enc == 0xffffffff {
continue
}
enc := inst.Enc
try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)})
}
}
}
// condCases generates conditional instructions.
func condCases(t *testing.T) func(func([]byte)) {
return func(try func([]byte)) {
condmark = true
JSONCases(t)(func(enc []byte) {
try(enc)
})
}
}
// hexCases generates the cases written in hexadecimal in the encoded string.
// Spaces in 'encoded' separate entire test cases, not individual bytes.
func hexCases(t *testing.T, encoded string) func(func([]byte)) {
return func(try func([]byte)) {
for _, x := range strings.Fields(encoded) {
src, err := hex.DecodeString(x)
if err != nil {
t.Errorf("parsing %q: %v", x, err)
}
try(src)
}
}
}
// testdataCases generates the test cases recorded in testdata/cases.txt.
// It only uses the inputs; it ignores the answers recorded in that file.
func testdataCases(t *testing.T, syntax string) func(func([]byte)) {
var codes [][]byte
input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil {
t.Fatal(err)
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.Fields(line)[0]
i := strings.Index(f, "|")
if i < 0 {
t.Errorf("parsing %q: missing | separator", f)
continue
}
if i%2 != 0 {
t.Errorf("parsing %q: misaligned | separator", f)
}
code, err := hex.DecodeString(f[:i] + f[i+1:])
if err != nil {
t.Errorf("parsing %q: %v", f, err)
continue
}
codes = append(codes, code)
}
return func(try func([]byte)) {
for _, code := range codes {
try(code)
}
}
}

35
vendor/golang.org/x/arch/arm64/arm64asm/gnu.go generated vendored Executable file

@ -0,0 +1,35 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
import (
"strings"
)
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
// This form typically matches the syntax defined in the ARM Reference Manual.
func GNUSyntax(inst Inst) string {
switch inst.Op {
case RET:
if r, ok := inst.Args[0].(Reg); ok && r == X30 {
return "ret"
}
case B:
if _, ok := inst.Args[0].(Cond); ok {
return strings.ToLower("b." + inst.Args[0].String() + " " + inst.Args[1].String())
}
case SYSL:
result := strings.ToLower(inst.String())
return strings.Replace(result, "c", "C", -1)
case DCPS1, DCPS2, DCPS3, CLREX:
return strings.ToLower(strings.TrimSpace(inst.String()))
case ISB:
if strings.Contains(inst.String(), "SY") {
result := strings.TrimSuffix(inst.String(), " SY")
return strings.ToLower(result)
}
}
return strings.ToLower(inst.String())
}

968
vendor/golang.org/x/arch/arm64/arm64asm/inst.go generated vendored Executable file

@ -0,0 +1,968 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
import (
"fmt"
"strings"
)
// An Op is an ARM64 opcode.
type Op uint16
// NOTE: The actual Op values are defined in tables.go.
// They are chosen to simplify instruction decoding and
// are not a dense packing from 0 to N, although the
// density is high, probably at least 90%.
func (op Op) String() string {
if op >= Op(len(opstr)) || opstr[op] == "" {
return fmt.Sprintf("Op(%d)", int(op))
}
return opstr[op]
}
// An Inst is a single instruction.
type Inst struct {
Op Op // Opcode mnemonic
Enc uint32 // Raw encoding bits.
Args Args // Instruction arguments, in ARM manual order.
}
func (i Inst) String() string {
var args []string
for _, arg := range i.Args {
if arg == nil {
break
}
args = append(args, arg.String())
}
return i.Op.String() + " " + strings.Join(args, ", ")
}
// An Args holds the instruction arguments.
// If an instruction has fewer than 5 arguments,
// the final elements in the array are nil.
type Args [5]Arg
// An Arg is a single instruction argument, one of these types:
// Reg, RegSP, ImmShift, RegExtshiftAmount, PCRel, MemImmediate,
// MemExtend, Imm, Imm64, Imm_hint, Imm_clrex, Imm_dcps, Cond,
// Imm_c, Imm_option, Imm_prfop, Pstatefield, Systemreg, Imm_fp
// RegisterWithArrangement, RegisterWithArrangementAndIndex.
type Arg interface {
isArg()
String() string
}
// A Reg is a single register.
// The zero value denotes W0, not the absence of a register.
type Reg uint16
const (
W0 Reg = iota
W1
W2
W3
W4
W5
W6
W7
W8
W9
W10
W11
W12
W13
W14
W15
W16
W17
W18
W19
W20
W21
W22
W23
W24
W25
W26
W27
W28
W29
W30
WZR
X0
X1
X2
X3
X4
X5
X6
X7
X8
X9
X10
X11
X12
X13
X14
X15
X16
X17
X18
X19
X20
X21
X22
X23
X24
X25
X26
X27
X28
X29
X30
XZR
B0
B1
B2
B3
B4
B5
B6
B7
B8
B9
B10
B11
B12
B13
B14
B15
B16
B17
B18
B19
B20
B21
B22
B23
B24
B25
B26
B27
B28
B29
B30
B31
H0
H1
H2
H3
H4
H5
H6
H7
H8
H9
H10
H11
H12
H13
H14
H15
H16
H17
H18
H19
H20
H21
H22
H23
H24
H25
H26
H27
H28
H29
H30
H31
S0
S1
S2
S3
S4
S5
S6
S7
S8
S9
S10
S11
S12
S13
S14
S15
S16
S17
S18
S19
S20
S21
S22
S23
S24
S25
S26
S27
S28
S29
S30
S31
D0
D1
D2
D3
D4
D5
D6
D7
D8
D9
D10
D11
D12
D13
D14
D15
D16
D17
D18
D19
D20
D21
D22
D23
D24
D25
D26
D27
D28
D29
D30
D31
Q0
Q1
Q2
Q3
Q4
Q5
Q6
Q7
Q8
Q9
Q10
Q11
Q12
Q13
Q14
Q15
Q16
Q17
Q18
Q19
Q20
Q21
Q22
Q23
Q24
Q25
Q26
Q27
Q28
Q29
Q30
Q31
V0
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
V11
V12
V13
V14
V15
V16
V17
V18
V19
V20
V21
V22
V23
V24
V25
V26
V27
V28
V29
V30
V31
WSP = WZR // These are different registers with the same encoding.
SP = XZR // These are different registers with the same encoding.
)
func (Reg) isArg() {}
func (r Reg) String() string {
switch {
case r == WZR:
return "WZR"
case r == XZR:
return "XZR"
case W0 <= r && r <= W30:
return fmt.Sprintf("W%d", int(r-W0))
case X0 <= r && r <= X30:
return fmt.Sprintf("X%d", int(r-X0))
case B0 <= r && r <= B31:
return fmt.Sprintf("B%d", int(r-B0))
case H0 <= r && r <= H31:
return fmt.Sprintf("H%d", int(r-H0))
case S0 <= r && r <= S31:
return fmt.Sprintf("S%d", int(r-S0))
case D0 <= r && r <= D31:
return fmt.Sprintf("D%d", int(r-D0))
case Q0 <= r && r <= Q31:
return fmt.Sprintf("Q%d", int(r-Q0))
case V0 <= r && r <= V31:
return fmt.Sprintf("V%d", int(r-V0))
default:
return fmt.Sprintf("Reg(%d)", int(r))
}
}
// A RegSP represent a register and X31/W31 is regarded as SP/WSP.
type RegSP Reg
func (RegSP) isArg() {}
func (r RegSP) String() string {
switch Reg(r) {
case WSP:
return "WSP"
case SP:
return "SP"
default:
return Reg(r).String()
}
}
type ImmShift struct {
imm uint16
shift uint8
}
func (ImmShift) isArg() {}
func (is ImmShift) String() string {
if is.shift == 0 {
return fmt.Sprintf("#%#x", is.imm)
}
if is.shift < 128 {
return fmt.Sprintf("#%#x, LSL #%d", is.imm, is.shift)
}
return fmt.Sprintf("#%#x, MSL #%d", is.imm, is.shift-128)
}
type ExtShift uint8
const (
_ ExtShift = iota
uxtb
uxth
uxtw
uxtx
sxtb
sxth
sxtw
sxtx
lsl
lsr
asr
ror
)
func (extShift ExtShift) String() string {
switch extShift {
case uxtb:
return "UXTB"
case uxth:
return "UXTH"
case uxtw:
return "UXTW"
case uxtx:
return "UXTX"
case sxtb:
return "SXTB"
case sxth:
return "SXTH"
case sxtw:
return "SXTW"
case sxtx:
return "SXTX"
case lsl:
return "LSL"
case lsr:
return "LSR"
case asr:
return "ASR"
case ror:
return "ROR"
}
return ""
}
type RegExtshiftAmount struct {
reg Reg
extShift ExtShift
amount uint8
show_zero bool
}
func (RegExtshiftAmount) isArg() {}
func (rea RegExtshiftAmount) String() string {
buf := rea.reg.String()
if rea.extShift != ExtShift(0) {
buf += ", " + rea.extShift.String()
if rea.amount != 0 {
buf += fmt.Sprintf(" #%d", rea.amount)
} else {
if rea.show_zero == true {
buf += fmt.Sprintf(" #%d", rea.amount)
}
}
}
return buf
}
// A PCRel describes a memory address (usually a code label)
// as a distance relative to the program counter.
type PCRel int64
func (PCRel) isArg() {}
func (r PCRel) String() string {
return fmt.Sprintf(".%+#x", uint64(r))
}
// An AddrMode is an ARM addressing mode.
type AddrMode uint8
const (
_ AddrMode = iota
AddrPostIndex // [R], X - use address R, set R = R + X
AddrPreIndex // [R, X]! - use address R + X, set R = R + X
AddrOffset // [R, X] - use address R + X
AddrPostReg // [Rn], Rm - - use address Rn, set Rn = Rn + Rm
)
// A MemImmediate is a memory reference made up of a base R and immediate X.
// The effective memory address is R or R+X depending on AddrMode.
type MemImmediate struct {
Base RegSP
Mode AddrMode
imm int32
}
func (MemImmediate) isArg() {}
func (m MemImmediate) String() string {
R := m.Base.String()
X := fmt.Sprintf("#%d", m.imm)
switch m.Mode {
case AddrOffset:
if X == "#0" {
return fmt.Sprintf("[%s]", R)
}
return fmt.Sprintf("[%s,%s]", R, X)
case AddrPreIndex:
return fmt.Sprintf("[%s,%s]!", R, X)
case AddrPostIndex:
return fmt.Sprintf("[%s],%s", R, X)
case AddrPostReg:
post := Reg(X0) + Reg(m.imm)
postR := post.String()
return fmt.Sprintf("[%s], %s", R, postR)
}
return fmt.Sprintf("unimplemented!")
}
// A MemExtend is a memory reference made up of a base R and index expression X.
// The effective memory address is R or R+X depending on Index, Extend and Amount.
type MemExtend struct {
Base RegSP
Index Reg
Extend ExtShift
// Amount indicates the index shift amount (but also see ShiftMustBeZero field below).
Amount uint8
// ShiftMustBeZero is set to true when the shift amount must be 0, even if the
// Amount field is not 0. In GNU syntax, a #0 shift amount is printed if Amount
// is not 0 but ShiftMustBeZero is true; #0 is not printed if Amount is 0 and
// ShiftMustBeZero is true. Both cases represent shift by 0 bit.
ShiftMustBeZero bool
}
func (MemExtend) isArg() {}
func (m MemExtend) String() string {
Rbase := m.Base.String()
RIndex := m.Index.String()
if m.ShiftMustBeZero {
if m.Amount != 0 {
return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String())
} else {
if m.Extend != lsl {
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
} else {
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
}
}
} else {
if m.Amount != 0 {
return fmt.Sprintf("[%s,%s,%s #%d]", Rbase, RIndex, m.Extend.String(), m.Amount)
} else {
if m.Extend != lsl {
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
} else {
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
}
}
}
}
// An Imm is an integer constant.
type Imm struct {
Imm uint32
Decimal bool
}
func (Imm) isArg() {}
func (i Imm) String() string {
if !i.Decimal {
return fmt.Sprintf("#%#x", i.Imm)
} else {
return fmt.Sprintf("#%d", i.Imm)
}
}
type Imm64 struct {
Imm uint64
Decimal bool
}
func (Imm64) isArg() {}
func (i Imm64) String() string {
if !i.Decimal {
return fmt.Sprintf("#%#x", i.Imm)
} else {
return fmt.Sprintf("#%d", i.Imm)
}
}
// An Imm_hint is an integer constant for HINT instruction.
type Imm_hint uint8
func (Imm_hint) isArg() {}
func (i Imm_hint) String() string {
return fmt.Sprintf("#%#x", uint32(i))
}
// An Imm_clrex is an integer constant for CLREX instruction.
type Imm_clrex uint8
func (Imm_clrex) isArg() {}
func (i Imm_clrex) String() string {
if i == 15 {
return ""
}
return fmt.Sprintf("#%#x", uint32(i))
}
// An Imm_dcps is an integer constant for DCPS[123] instruction.
type Imm_dcps uint16
func (Imm_dcps) isArg() {}
func (i Imm_dcps) String() string {
if i == 0 {
return ""
}
return fmt.Sprintf("#%#x", uint32(i))
}
// Standard conditions.
type Cond struct {
Value uint8
Invert bool
}
func (Cond) isArg() {}
func (c Cond) String() string {
cond31 := c.Value >> 1
invert := bool((c.Value & 1) == 1)
invert = (invert != c.Invert)
switch cond31 {
case 0:
if invert {
return "NE"
} else {
return "EQ"
}
case 1:
if invert {
return "CC"
} else {
return "CS"
}
case 2:
if invert {
return "PL"
} else {
return "MI"
}
case 3:
if invert {
return "VC"
} else {
return "VS"
}
case 4:
if invert {
return "LS"
} else {
return "HI"
}
case 5:
if invert {
return "LT"
} else {
return "GE"
}
case 6:
if invert {
return "LE"
} else {
return "GT"
}
case 7:
return "AL"
}
return ""
}
// An Imm_c is an integer constant for SYS/SYSL/TLBI instruction.
type Imm_c uint8
func (Imm_c) isArg() {}
func (i Imm_c) String() string {
return fmt.Sprintf("C%d", uint8(i))
}
// An Imm_option is an integer constant for DMB/DSB/ISB instruction.
type Imm_option uint8
func (Imm_option) isArg() {}
func (i Imm_option) String() string {
switch uint8(i) {
case 15:
return "SY"
case 14:
return "ST"
case 13:
return "LD"
case 11:
return "ISH"
case 10:
return "ISHST"
case 9:
return "ISHLD"
case 7:
return "NSH"
case 6:
return "NSHST"
case 5:
return "NSHLD"
case 3:
return "OSH"
case 2:
return "OSHST"
case 1:
return "OSHLD"
}
return fmt.Sprintf("#%#02x", uint8(i))
}
// An Imm_prfop is an integer constant for PRFM instruction.
type Imm_prfop uint8
func (Imm_prfop) isArg() {}
func (i Imm_prfop) String() string {
prf_type := (i >> 3) & (1<<2 - 1)
prf_target := (i >> 1) & (1<<2 - 1)
prf_policy := i & 1
var result string
switch prf_type {
case 0:
result = "PLD"
case 1:
result = "PLI"
case 2:
result = "PST"
case 3:
return fmt.Sprintf("#%#02x", uint8(i))
}
switch prf_target {
case 0:
result += "L1"
case 1:
result += "L2"
case 2:
result += "L3"
case 3:
return fmt.Sprintf("#%#02x", uint8(i))
}
if prf_policy == 0 {
result += "KEEP"
} else {
result += "STRM"
}
return result
}
type Pstatefield uint8
const (
SPSel Pstatefield = iota
DAIFSet
DAIFClr
)
func (Pstatefield) isArg() {}
func (p Pstatefield) String() string {
switch p {
case SPSel:
return "SPSel"
case DAIFSet:
return "DAIFSet"
case DAIFClr:
return "DAIFClr"
default:
return "unimplemented"
}
}
type Systemreg struct {
op0 uint8
op1 uint8
cn uint8
cm uint8
op2 uint8
}
func (Systemreg) isArg() {}
func (s Systemreg) String() string {
return fmt.Sprintf("S%d_%d_C%d_C%d_%d",
s.op0, s.op1, s.cn, s.cm, s.op2)
}
// An Imm_fp is a signed floating-point constant.
type Imm_fp struct {
s uint8
exp int8
pre uint8
}
func (Imm_fp) isArg() {}
func (i Imm_fp) String() string {
var s, pre, numerator, denominator int16
var result float64
if i.s == 0 {
s = 1
} else {
s = -1
}
pre = s * int16(16+i.pre)
if i.exp > 0 {
numerator = (pre << uint8(i.exp))
denominator = 16
} else {
numerator = pre
denominator = (16 << uint8(-1*i.exp))
}
result = float64(numerator) / float64(denominator)
return fmt.Sprintf("#%.18e", result)
}
type Arrangement uint8
const (
_ Arrangement = iota
ArrangementB
Arrangement8B
Arrangement16B
ArrangementH
Arrangement4H
Arrangement8H
ArrangementS
Arrangement2S
Arrangement4S
ArrangementD
Arrangement1D
Arrangement2D
Arrangement1Q
)
func (a Arrangement) String() (result string) {
switch a {
case ArrangementB:
result = ".B"
case Arrangement8B:
result = ".8B"
case Arrangement16B:
result = ".16B"
case ArrangementH:
result = ".H"
case Arrangement4H:
result = ".4H"
case Arrangement8H:
result = ".8H"
case ArrangementS:
result = ".S"
case Arrangement2S:
result = ".2S"
case Arrangement4S:
result = ".4S"
case ArrangementD:
result = ".D"
case Arrangement1D:
result = ".1D"
case Arrangement2D:
result = ".2D"
case Arrangement1Q:
result = ".1Q"
}
return
}
// Register with arrangement: <Vd>.<T>, { <Vt>.8B, <Vt2>.8B},
type RegisterWithArrangement struct {
r Reg
a Arrangement
cnt uint8
}
func (RegisterWithArrangement) isArg() {}
func (r RegisterWithArrangement) String() string {
result := r.r.String()
result += r.a.String()
if r.cnt > 0 {
result = "{" + result
if r.cnt == 2 {
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
result += ", " + r1.String() + r.a.String()
} else if r.cnt > 2 {
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
for i := 1; i < int(r.cnt); i++ {
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
result += ", " + cur.String() + r.a.String()
}
} else {
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
result += "-" + r1.String() + r.a.String()
}
}
result += "}"
}
return result
}
// Register with arrangement and index: <Vm>.<Ts>[<index>],
// { <Vt>.B, <Vt2>.B }[<index>].
type RegisterWithArrangementAndIndex struct {
r Reg
a Arrangement
index uint8
cnt uint8
}
func (RegisterWithArrangementAndIndex) isArg() {}
func (r RegisterWithArrangementAndIndex) String() string {
result := r.r.String()
result += r.a.String()
if r.cnt > 0 {
result = "{" + result
if r.cnt == 2 {
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
result += ", " + r1.String() + r.a.String()
} else if r.cnt > 2 {
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
for i := 1; i < int(r.cnt); i++ {
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
result += ", " + cur.String() + r.a.String()
}
} else {
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
result += "-" + r1.String() + r.a.String()
}
}
result += "}"
}
return fmt.Sprintf("%s[%d]", result, r.index)
}

1219
vendor/golang.org/x/arch/arm64/arm64asm/inst.json generated vendored Executable file

File diff suppressed because it is too large Load Diff

162
vendor/golang.org/x/arch/arm64/arm64asm/objdump_test.go generated vendored Executable file

@ -0,0 +1,162 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
import (
"strings"
"testing"
)
func TestObjdumpARM64TestDecodeGNUSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "gnu"))
}
func TestObjdumpARM64TestDecodeGoSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "plan9"))
}
func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) }
func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) }
func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) }
// objdumpManualTests holds test cases that will be run by TestObjdumpARMManual.
// If you are debugging a few cases that turned up in a longer run, it can be useful
// to list them here and then use -run=Manual, particularly with tracing enabled.
// Note that these are byte sequences, so they must be reversed from the usual
// word presentation.
var objdumpManualTests = `
bf2003d5
9f2003d5
7f2003d5
5f2003d5
3f2003d5
1f2003d5
df4d03d5
ff4d03d5
28d91b14
da6cb530
15e5e514
ff4603d5
df4803d5
bf4100d5
9f3f03d5
9f3e03d5
9f3d03d5
9f3b03d5
9f3a03d5
9f3903d5
9f3703d5
9f3603d5
9f3503d5
9f3303d5
9f3203d5
9f3103d5
ff4603d5
df4803d5
bf4100d5
a3681b53
47dc78d3
0500a012
0500e092
0500a052
0500a0d2
cd5a206e
cd5a202e
743d050e
743d0a0e
743d0c0e
743d084e
`
// allowedMismatchObjdump reports whether the mismatch between text and dec
// should be allowed by the test.
func allowedMismatchObjdump(text string, inst *Inst, dec ExtInst) bool {
// Skip unsupported instructions
if hasPrefix(dec.text, todo...) {
return true
}
// GNU objdump has incorrect alias conditions for following instructions
if inst.Enc&0x000003ff == 0x000003ff && hasPrefix(dec.text, "negs") && hasPrefix(text, "cmp") {
return true
}
// GNU objdump "NV" is equal to our "AL"
if strings.HasSuffix(dec.text, " nv") && strings.HasSuffix(text, " al") {
return true
}
if strings.HasPrefix(dec.text, "b.nv") && strings.HasPrefix(text, "b.al") {
return true
}
// GNU objdump recognizes invalid binaries as following instructions
if hasPrefix(dec.text, "hint", "mrs", "msr", "bfc", "orr", "mov") {
return true
}
if strings.HasPrefix(text, "hint") {
return true
}
// GNU objdump recognizes reserved valuse as valid ones
if strings.Contains(text, "unknown instruction") && hasPrefix(dec.text, "fmla", "fmul", "fmulx", "fcvtzs", "fcvtzu", "fmls", "fmov", "scvtf", "ucvtf") {
return true
}
// Some old objdump recognizes ldur*/stur*/prfum as ldr*/str*/prfm
for k, v := range oldObjdumpMismatch {
if strings.HasPrefix(dec.text, k) && strings.Replace(dec.text, k, v, 1) == text {
return true
}
}
// New objdump supports some newer mnemonics than this package. This
// package should be updated to support the new mnemonics and the sense
// of this reversed to continue passing with older objdumps but that
// requires internal ARM tooling.
if newForm, ok := newMnemonics[text]; ok && newForm == dec.text {
return true
}
// GNU objdump misses spaces between operands for some instructions (e.g., "ld1 {v10.2s, v11.2s}, [x23],#16")
if strings.Replace(text, " ", "", -1) == strings.Replace(dec.text, " ", "", -1) {
return true
}
return false
}
// TODO: system instruction.
var todo = strings.Fields(`
sys
dc
at
tlbi
ic
hvc
smc
`)
// Following instructions can't be covered because they are just aliases to another instructions which are always preferred
var Ncover = strings.Fields(`
sbfm
asrv
bfm
ubfm
lslv
lsrv
rorv
ins
dup
`)
// Some old objdump wrongly decodes following instructions and allow their mismatches to avoid false alarm
var oldObjdumpMismatch = map[string]string{
//oldObjValue correctValue
"ldr": "ldur",
"ldrb": "ldurb",
"ldrh": "ldurh",
"ldrsb": "ldursb",
"ldrsh": "ldursh",
"ldrsw": "ldursw",
"str": "stur",
"strb": "sturb",
"strh": "sturh",
"prfm": "prfum",
}
var newMnemonics = map[string]string{
"dsb #0x00": "ssbb",
"dsb #0x04": "pssbb",
}

299
vendor/golang.org/x/arch/arm64/arm64asm/objdumpext_test.go generated vendored Executable file

@ -0,0 +1,299 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Copied and simplified from ../../arm/armasm/objdumpext_test.go.
package arm64asm
import (
"bytes"
"debug/elf"
"encoding/binary"
"fmt"
"io"
"log"
"os"
"os/exec"
"strconv"
"strings"
"testing"
)
const objdumpPath = "/usr/bin/objdump"
func testObjdumpARM64(t *testing.T, generate func(func([]byte))) {
testObjdumpArch(t, generate, ModeARM64)
}
func testObjdumpArch(t *testing.T, generate func(func([]byte)), arch Mode) {
checkObjdumpAarch64(t)
testExtDis(t, "gnu", arch, objdump, generate, allowedMismatchObjdump)
testExtDis(t, "plan9", arch, objdump, generate, allowedMismatchObjdump)
}
func checkObjdumpAarch64(t *testing.T) {
out, err := exec.Command(objdumpPath, "-i").Output()
if err != nil {
t.Skipf("cannot run objdump: %v\n%s", err, out)
}
if !strings.Contains(string(out), "aarch64") {
t.Skip("objdump does not have aarch64 support")
}
}
func objdump(ext *ExtDis) error {
// File already written with instructions; add ELF header.
if ext.Arch == ModeARM64 {
if err := writeELF64(ext.File, ext.Size); err != nil {
return err
}
} else {
panic("unknown arch")
}
b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
if err != nil {
return err
}
var (
nmatch int
reading bool
next uint64 = start
addr uint64
encbuf [4]byte
enc []byte
text string
)
flush := func() {
if addr == next {
// PC-relative addresses are translated to absolute addresses based on PC by GNU objdump
// Following logical rewrites the absolute addresses back to PC-relative ones for comparing
// with our disassembler output which are PC-relative
if m := pcrelprfmim.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
if m := pcrelprfm.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
if m := pcrelim.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
if m := pcrelimzr.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
if m := pcrelr.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
if strings.Contains(m[1], "adrp") {
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr&0xfffff000)))
} else {
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
}
if m := pcrelrzr.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
if strings.Contains(m[1], "adrp") {
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr&0xfffff000)))
} else {
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
}
if m := pcrel.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
}
if strings.HasPrefix(text, "mov") && strings.Contains(text, "//") {
s := strings.Split(text, " //")
text = s[0]
}
text = strings.Replace(text, "#0.0", "#0", -1)
if text == "undefined" && len(enc) == 4 {
text = "error: unknown instruction"
enc = nil
}
if len(enc) == 4 {
// prints as word but we want to record bytes
enc[0], enc[3] = enc[3], enc[0]
enc[1], enc[2] = enc[2], enc[1]
}
ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
encbuf = [4]byte{}
enc = nil
next += 4
}
}
var textangle = []byte("<.text>:")
for {
line, err := b.ReadSlice('\n')
if err != nil {
if err == io.EOF {
break
}
return fmt.Errorf("reading objdump output: %v", err)
}
if bytes.Contains(line, textangle) {
reading = true
continue
}
if !reading {
continue
}
if debug {
os.Stdout.Write(line)
}
if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
enc = enc1
continue
}
flush()
nmatch++
addr, enc, text = parseLine(line, encbuf[:0])
if addr > next {
return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
}
}
flush()
if next != start+uint64(ext.Size) {
return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
}
if err := ext.Wait(); err != nil {
return fmt.Errorf("exec: %v", err)
}
return nil
}
var (
undefined = []byte("undefined")
unpredictable = []byte("unpredictable")
slashslash = []byte("//")
)
func parseLine(line []byte, encstart []byte) (addr uint64, enc []byte, text string) {
ok := false
oline := line
i := index(line, ":\t")
if i < 0 {
log.Fatalf("cannot parse disassembly: %q", oline)
}
x, err := strconv.ParseUint(string(bytes.TrimSpace(line[:i])), 16, 32)
if err != nil {
log.Fatalf("cannot parse disassembly: %q", oline)
}
addr = uint64(x)
line = line[i+2:]
i = bytes.IndexByte(line, '\t')
if i < 0 {
log.Fatalf("cannot parse disassembly: %q", oline)
}
enc, ok = parseHex(line[:i], encstart)
if !ok {
log.Fatalf("cannot parse disassembly: %q", oline)
}
line = bytes.TrimSpace(line[i:])
if bytes.Contains(line, undefined) {
text = "undefined"
return
}
if false && bytes.Contains(line, unpredictable) {
text = "unpredictable"
return
}
// Strip trailing comment starting with ';'
// e.g: "csinv x23, x2, x19, cc ; xxx"
if i := bytes.IndexByte(line, ';'); i >= 0 {
line = bytes.TrimSpace(line[:i])
}
// Strip trailing comment starting with "//"
// e.g: "fccmpe s2, s9, #0x7, ne // xxx"
if i := bytes.Index(line, slashslash); i >= 0 {
line = bytes.TrimSpace(line[:i])
}
text = string(fixSpace(line))
return
}
func parseContinuation(line []byte, enc []byte) []byte {
i := index(line, ":\t")
if i < 0 {
return nil
}
line = line[i+1:]
enc, _ = parseHex(line, enc)
return enc
}
// writeELF64 writes an ELF64 header to the file, describing a text
// segment that starts at start (0x8000) and extends for size bytes.
func writeELF64(f *os.File, size int) error {
f.Seek(0, io.SeekStart)
var hdr elf.Header64
var prog elf.Prog64
var sect elf.Section64
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, &hdr)
off1 := buf.Len()
binary.Write(&buf, binary.LittleEndian, &prog)
off2 := buf.Len()
binary.Write(&buf, binary.LittleEndian, &sect)
off3 := buf.Len()
buf.Reset()
data := byte(elf.ELFDATA2LSB)
hdr = elf.Header64{
Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
Type: 2,
Machine: uint16(elf.EM_AARCH64),
Version: 1,
Entry: start,
Phoff: uint64(off1),
Shoff: uint64(off2),
Flags: 0x05000002,
Ehsize: uint16(off1),
Phentsize: uint16(off2 - off1),
Phnum: 1,
Shentsize: uint16(off3 - off2),
Shnum: 3,
Shstrndx: 2,
}
binary.Write(&buf, binary.LittleEndian, &hdr)
prog = elf.Prog64{
Type: 1,
Off: start,
Vaddr: start,
Paddr: start,
Filesz: uint64(size),
Memsz: uint64(size),
Flags: 5,
Align: start,
}
binary.Write(&buf, binary.LittleEndian, &prog)
binary.Write(&buf, binary.LittleEndian, &sect) // NULL section
sect = elf.Section64{
Name: 1,
Type: uint32(elf.SHT_PROGBITS),
Addr: start,
Off: start,
Size: uint64(size),
Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
Addralign: 4,
}
binary.Write(&buf, binary.LittleEndian, &sect) // .text
sect = elf.Section64{
Name: uint32(len("\x00.text\x00")),
Type: uint32(elf.SHT_STRTAB),
Addr: 0,
Off: uint64(off2 + (off3-off2)*3),
Size: uint64(len("\x00.text\x00.shstrtab\x00")),
Addralign: 1,
}
binary.Write(&buf, binary.LittleEndian, &sect)
buf.WriteString("\x00.text\x00.shstrtab\x00")
f.Write(buf.Bytes())
return nil
}

702
vendor/golang.org/x/arch/arm64/arm64asm/plan9x.go generated vendored Executable file

@ -0,0 +1,702 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64asm
import (
"fmt"
"io"
"sort"
"strings"
)
// GoSyntax returns the Go assembler syntax for the instruction.
// The syntax was originally defined by Plan 9.
// The pc is the program counter of the instruction, used for
// expanding PC-relative addresses into absolute ones.
// The symname function queries the symbol table for the program
// being disassembled. Given a target address it returns the name
// and base address of the symbol containing the target, if any;
// otherwise it returns "", 0.
// The reader text should read from the text segment using text addresses
// as offsets; it is used to display pc-relative loads as constant loads.
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
if symname == nil {
symname = func(uint64) (string, uint64) { return "", 0 }
}
var args []string
for _, a := range inst.Args {
if a == nil {
break
}
args = append(args, plan9Arg(&inst, pc, symname, a))
}
op := inst.Op.String()
switch inst.Op {
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW:
// Check for PC-relative load.
if offset, ok := inst.Args[1].(PCRel); ok {
addr := pc + uint64(offset)
if _, ok := inst.Args[0].(Reg); !ok {
break
}
if s, base := symname(addr); s != "" && addr == base {
args[1] = fmt.Sprintf("$%s(SB)", s)
}
}
}
// Move addressing mode into opcode suffix.
suffix := ""
switch inst.Op {
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1, ST1:
switch mem := inst.Args[1].(type) {
case MemImmediate:
switch mem.Mode {
case AddrOffset:
// no suffix
case AddrPreIndex:
suffix = ".W"
case AddrPostIndex, AddrPostReg:
suffix = ".P"
}
}
case STP, LDP:
switch mem := inst.Args[2].(type) {
case MemImmediate:
switch mem.Mode {
case AddrOffset:
// no suffix
case AddrPreIndex:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
}
}
}
switch inst.Op {
case BL:
return "CALL " + args[0]
case BLR:
r := inst.Args[0].(Reg)
regno := uint16(r) & 31
return fmt.Sprintf("CALL (R%d)", regno)
case RET:
if r, ok := inst.Args[0].(Reg); ok && r == X30 {
return "RET"
}
case B:
if cond, ok := inst.Args[0].(Cond); ok {
return "B" + cond.String() + " " + args[1]
}
return "JMP" + " " + args[0]
case BR:
r := inst.Args[0].(Reg)
regno := uint16(r) & 31
return fmt.Sprintf("JMP (R%d)", regno)
case MOV:
rno := -1
switch a := inst.Args[0].(type) {
case Reg:
rno = int(a)
case RegSP:
rno = int(a)
case RegisterWithArrangementAndIndex:
op = "VMOV"
case RegisterWithArrangement:
op = "VMOV"
}
if rno >= 0 && rno <= int(WZR) {
op = "MOVW"
} else if rno >= int(X0) && rno <= int(XZR) {
op = "MOVD"
}
if _, ok := inst.Args[1].(RegisterWithArrangementAndIndex); ok {
op = "VMOV"
}
case LDR:
var rno uint16
if r, ok := inst.Args[0].(Reg); ok {
rno = uint16(r)
} else {
rno = uint16(inst.Args[0].(RegSP))
}
if rno <= uint16(WZR) {
op = "MOVWU" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
case LDRB:
op = "MOVBU" + suffix
case LDRH:
op = "MOVHU" + suffix
case LDRSW:
op = "MOVW" + suffix
case LDRSB:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op = "MOVBW" + suffix
} else {
op = "MOVB" + suffix
}
}
case LDRSH:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op = "MOVHW" + suffix
} else {
op = "MOVH" + suffix
}
}
case STR, STUR:
var rno uint16
if r, ok := inst.Args[0].(Reg); ok {
rno = uint16(r)
} else {
rno = uint16(inst.Args[0].(RegSP))
}
if rno <= uint16(WZR) {
op = "MOVW" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
args[0], args[1] = args[1], args[0]
case STRB, STURB:
op = "MOVB" + suffix
args[0], args[1] = args[1], args[0]
case STRH, STURH:
op = "MOVH" + suffix
args[0], args[1] = args[1], args[0]
case TBNZ, TBZ:
args[0], args[1], args[2] = args[2], args[0], args[1]
case MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[2], args[3] = args[3], args[2]
case STLR:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[0], args[1] = args[1], args[0]
case STLRB, STLRH:
args[0], args[1] = args[1], args[0]
case STLXR, STXR:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[1], args[2] = args[2], args[1]
case STLXRB, STLXRH, STXRB, STXRH:
args[1], args[2] = args[2], args[1]
case BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[1], args[2], args[3] = args[3], args[1], args[2]
case LDAXP, LDXP:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
fallthrough
case STP, LDP:
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
args[1] = args[2]
if op == "STP" {
op = op + suffix
return op + " " + args[0] + ", " + args[1]
} else if op == "LDP" {
op = op + suffix
return op + " " + args[1] + ", " + args[0]
} else if op == "LDAXP" || op == "LDXP" || op == "LDAXPW" || op == "LDXPW" {
return op + " " + args[1] + ", " + args[0]
}
case STLXP, STXP:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[1] = fmt.Sprintf("(%s, %s)", args[1], args[2])
args[2] = args[3]
return op + " " + args[1] + ", " + args[2] + ", " + args[0]
case FCCMP, FCCMPE:
args[0], args[1] = args[1], args[0]
fallthrough
case FCMP, FCMPE:
if _, ok := inst.Args[1].(Imm); ok {
args[1] = "$(0.0)"
}
fallthrough
case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL, FMADD, FMSUB, FNMADD, FNMSUB:
if strings.HasSuffix(op, "MADD") || strings.HasSuffix(op, "MSUB") {
args[2], args[3] = args[3], args[2]
}
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
case FCVT:
for i := 1; i >= 0; i-- {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(H0) && rno <= uint16(H31) {
op = fmt.Sprintf("%sH", op)
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
}
case FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
case FCVTZS, FCVTZU, SCVTF, UCVTF:
if _, ok := inst.Args[2].(Imm); !ok {
for i := 1; i >= 0; i-- {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
} else if rno <= uint16(WZR) {
op += "W"
}
}
}
}
case FMOV:
for i := 0; i <= 1; i++ {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
break
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
break
}
}
}
case SYSL:
op1 := int(inst.Args[1].(Imm).Imm)
cn := int(inst.Args[2].(Imm_c))
cm := int(inst.Args[3].(Imm_c))
op2 := int(inst.Args[4].(Imm).Imm)
sysregno := int32(op1<<16 | cn<<12 | cm<<8 | op2<<5)
args[1] = fmt.Sprintf("$%d", sysregno)
return op + " " + args[1] + ", " + args[0]
case CBNZ, CBZ:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[0], args[1] = args[1], args[0]
case ADR, ADRP:
addr := int64(inst.Args[1].(PCRel))
args[1] = fmt.Sprintf("%d(PC)", addr)
case MSR:
args[0] = inst.Args[0].String()
case ST1:
op = fmt.Sprintf("V%s", op) + suffix
args[0], args[1] = args[1], args[0]
case LD1:
op = fmt.Sprintf("V%s", op) + suffix
case UMOV:
op = "VMOV"
default:
index := sort.SearchStrings(noSuffixOpSet, op)
if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
rno := -1
switch a := inst.Args[0].(type) {
case Reg:
rno = int(a)
case RegSP:
rno = int(a)
case RegisterWithArrangement:
op = fmt.Sprintf("V%s", op)
}
if rno >= int(B0) && rno <= int(Q31) && !strings.HasPrefix(op, "F") {
op = fmt.Sprintf("V%s", op)
}
if rno >= 0 && rno <= int(WZR) {
// Add "w" to opcode suffix.
op += "W"
}
}
op = op + suffix
}
// conditional instructions, replace args.
if _, ok := inst.Args[3].(Cond); ok {
if _, ok := inst.Args[2].(Reg); ok {
args[1], args[2] = args[2], args[1]
} else {
args[0], args[2] = args[2], args[0]
}
}
// Reverse args, placing dest last.
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
args[i], args[j] = args[j], args[i]
}
if args != nil {
op += " " + strings.Join(args, ", ")
}
return op
}
// No need add "W" to opcode suffix.
// Opcode must be inserted in ascending order.
var noSuffixOpSet = strings.Fields(`
AESD
AESE
AESIMC
AESMC
CRC32B
CRC32CB
CRC32CH
CRC32CW
CRC32CX
CRC32H
CRC32W
CRC32X
LDARB
LDARH
LDAXRB
LDAXRH
LDTRH
LDXRB
LDXRH
SHA1C
SHA1H
SHA1M
SHA1P
SHA1SU0
SHA1SU1
SHA256H
SHA256H2
SHA256SU0
SHA256SU1
`)
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
switch a := arg.(type) {
case Imm:
return fmt.Sprintf("$%d", uint32(a.Imm))
case Imm64:
return fmt.Sprintf("$%d", int64(a.Imm))
case ImmShift:
if a.shift == 0 {
return fmt.Sprintf("$%d", a.imm)
}
return fmt.Sprintf("$(%d<<%d)", a.imm, a.shift)
case PCRel:
addr := int64(pc) + int64(a)
if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
return fmt.Sprintf("%s(SB)", s)
}
return fmt.Sprintf("%d(PC)", a/4)
case Reg:
regenum := uint16(a)
regno := uint16(a) & 31
if regenum >= uint16(B0) && regenum <= uint16(D31) {
if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") {
// FP registers are the same ones as SIMD registers
// Print Fn for scalar variant to align with assembler (e.g., FCVT, SCVTF, UCVTF, etc.)
return fmt.Sprintf("F%d", regno)
} else {
return fmt.Sprintf("V%d", regno)
}
} else if regenum >= uint16(Q0) && regenum <= uint16(Q31) {
// Print Vn to align with assembler (e.g., SHA256H)
return fmt.Sprintf("V%d", regno)
}
if regno == 31 {
return "ZR"
}
return fmt.Sprintf("R%d", regno)
case RegSP:
regno := uint16(a) & 31
if regno == 31 {
return "RSP"
}
return fmt.Sprintf("R%d", regno)
case RegExtshiftAmount:
reg := ""
regno := uint16(a.reg) & 31
if regno == 31 {
reg = "ZR"
} else {
reg = fmt.Sprintf("R%d", uint16(a.reg)&31)
}
extshift := ""
amount := ""
if a.extShift != ExtShift(0) {
switch a.extShift {
default:
extshift = "." + a.extShift.String()
case lsl:
extshift = "<<"
amount = fmt.Sprintf("%d", a.amount)
return reg + extshift + amount
case lsr:
extshift = ">>"
amount = fmt.Sprintf("%d", a.amount)
return reg + extshift + amount
case asr:
extshift = "->"
amount = fmt.Sprintf("%d", a.amount)
return reg + extshift + amount
case ror:
extshift = "@>"
amount = fmt.Sprintf("%d", a.amount)
return reg + extshift + amount
}
if a.amount != 0 {
amount = fmt.Sprintf("<<%d", a.amount)
}
}
return reg + extshift + amount
case MemImmediate:
off := ""
base := ""
regno := uint16(a.Base) & 31
if regno == 31 {
base = "(RSP)"
} else {
base = fmt.Sprintf("(R%d)", regno)
}
if a.imm != 0 && a.Mode != AddrPostReg {
off = fmt.Sprintf("%d", a.imm)
} else if a.Mode == AddrPostReg {
postR := fmt.Sprintf("(R%d)", a.imm)
return base + postR
}
return off + base
case MemExtend:
base := ""
index := ""
indexreg := ""
regno := uint16(a.Base) & 31
if regno == 31 {
base = "(RSP)"
} else {
base = fmt.Sprintf("(R%d)", regno)
}
regno = uint16(a.Index) & 31
if regno == 31 {
indexreg = "ZR"
} else {
indexreg = fmt.Sprintf("R%d", regno)
}
if a.Extend == lsl {
// a.Amount indicates the index shift amount, encoded in "S" field.
// a.ShiftMustBeZero is set true when the index shift amount must be 0,
// even if the a.Amount field is not 0.
// When a.ShiftMustBeZero is ture, GNU syntax prints #0 shift amount if
// "S" equals to 1, or does not print #0 shift amount if "S" equals to 0.
// Go syntax should never print a zero index shift amount.
if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
} else {
index = fmt.Sprintf("(%s)", indexreg)
}
} else {
if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
} else {
index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
}
}
return base + index
case Cond:
switch arg.String() {
case "CS":
return "HS"
case "CC":
return "LO"
}
case Imm_clrex:
return fmt.Sprintf("$%d", uint32(a))
case Imm_dcps:
return fmt.Sprintf("$%d", uint32(a))
case Imm_option:
return fmt.Sprintf("$%d", uint8(a))
case Imm_hint:
return fmt.Sprintf("$%d", uint8(a))
case Imm_fp:
var s, pre, numerator, denominator int16
var result float64
if a.s == 0 {
s = 1
} else {
s = -1
}
pre = s * int16(16+a.pre)
if a.exp > 0 {
numerator = (pre << uint8(a.exp))
denominator = 16
} else {
numerator = pre
denominator = (16 << uint8(-1*a.exp))
}
result = float64(numerator) / float64(denominator)
return strings.TrimRight(fmt.Sprintf("$%f", result), "0")
case RegisterWithArrangement:
result := a.r.String()
arrange := a.a.String()
c := []rune(arrange)
switch len(c) {
case 3:
c[1], c[2] = c[2], c[1] // .8B -> .B8
case 4:
c[1], c[2], c[3] = c[3], c[1], c[2] // 16B -> B16
}
arrange = string(c)
result += arrange
if a.cnt > 0 {
result = "[" + result
for i := 1; i < int(a.cnt); i++ {
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
result += ", " + cur.String() + arrange
}
result += "]"
}
return result
case RegisterWithArrangementAndIndex:
result := a.r.String()
arrange := a.a.String()
result += arrange
if a.cnt > 1 {
result = "[" + result
for i := 1; i < int(a.cnt); i++ {
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
result += ", " + cur.String() + arrange
}
result += "]"
}
return fmt.Sprintf("%s[%d]", result, a.index)
case Systemreg:
return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
case Imm_prfop:
if strings.Contains(a.String(), "#") {
return fmt.Sprintf("$%d", a)
}
}
return strings.ToUpper(arg.String())
}

3366
vendor/golang.org/x/arch/arm64/arm64asm/tables.go generated vendored Executable file

File diff suppressed because it is too large Load Diff

9
vendor/golang.org/x/arch/arm64/arm64asm/testdata/Makefile generated vendored Executable file

@ -0,0 +1,9 @@
go test command:
cd ..; go test -run 'ObjdumpARM64Cond' -v -timeout 10h -long 2>&1 | tee log
cd ..; go test -run 'ObjdumpARM64TestGUNSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64TestGoSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64Manual' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'TestDecodeGNUSyntax'
cd ..; go test -run 'TestDecodeGoSyntax'
cd ..; go test -run '.*'