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:
parent
be98a8503c
commit
2a68058b4a
2
go.mod
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
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
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,
|
||||
}
|
||||
}
|
||||
288
pkg/proc/arch.go
288
pkg/proc/arch.go
@ -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
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
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
|
||||
}
|
||||
139
pkg/proc/linutil/regs_arm64_arch.go
Normal file
139
pkg/proc/linutil/regs_arm64_arch.go
Normal file
@ -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
|
||||
}
|
||||
103
pkg/proc/native/registers_linux_arm64.go
Normal file
103
pkg/proc/native/registers_linux_arm64.go
Normal file
@ -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, ®s) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &linutil.ARM64Registers{®s, nil, nil}
|
||||
if floatingPoint {
|
||||
r.Fpregs, r.Fpregset, err = thread.fpRegisters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
43
pkg/proc/native/threads_linux_arm64.go
Normal file
43
pkg/proc/native/threads_linux_arm64.go
Normal file
@ -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
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
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
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
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
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
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
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
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
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
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
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, §)
|
||||
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, §) // 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, §) // .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, §)
|
||||
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
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
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
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 '.*'
|
||||
Loading…
Reference in New Issue
Block a user