1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
package proc
import (
"encoding/binary"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"golang.org/x/arch/ppc64/ppc64asm"
)
// Possible stacksplit prologues are inserted by stacksplit in
// $GOROOT/src/cmd/internal/obj/ppc64/obj9.go.
var prologuesPPC64LE []opcodeSeq
func init() {
// Note: these will be the gnu opcodes and not the Go opcodes. Verify the sequences are as expected.
var tinyStacksplit = opcodeSeq{uint64(ppc64asm.ADDI), uint64(ppc64asm.CMPLD), uint64(ppc64asm.BC)}
var smallStacksplit = opcodeSeq{uint64(ppc64asm.ADDI), uint64(ppc64asm.CMPLD), uint64(ppc64asm.BC)}
var bigStacksplit = opcodeSeq{uint64(ppc64asm.ADDI), uint64(ppc64asm.CMPLD), uint64(ppc64asm.BC), uint64(ppc64asm.STD), uint64(ppc64asm.STD), uint64(ppc64asm.MFSPR)}
var adjustTOCPrologueOnPIE = opcodeSeq{uint64(ppc64asm.ADDIS), uint64(ppc64asm.ADDI)}
var unixGetG = opcodeSeq{uint64(ppc64asm.LD)}
var prologue opcodeSeq
prologuesPPC64LE = make([]opcodeSeq, 0, 3)
prologue = make(opcodeSeq, 0, 1)
for _, getG := range []opcodeSeq{unixGetG} {
for _, stacksplit := range []opcodeSeq{tinyStacksplit, smallStacksplit, bigStacksplit} {
prologue = append(prologue, getG...)
prologue = append(prologue, stacksplit...)
prologuesPPC64LE = append(prologuesPPC64LE, prologue)
}
}
// On PIE mode special prologue is generated two instructions before the function entry point that correlates to call target
// address, Teach delve to recognize this sequence to appropriately adjust PC address so that the breakpoint is actually hit
// while doing step
TOCprologue := make(opcodeSeq, 0, len(adjustTOCPrologueOnPIE))
TOCprologue = append(TOCprologue, adjustTOCPrologueOnPIE...)
prologuesPPC64LE = append(prologuesPPC64LE, TOCprologue)
}
func ppc64leAsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error {
asmInst.Size = 4
asmInst.Bytes = mem[:asmInst.Size]
inst, err := ppc64asm.Decode(mem, binary.LittleEndian)
if err != nil {
asmInst.Inst = (*ppc64ArchInst)(nil)
return err
}
asmInst.Inst = (*ppc64ArchInst)(&inst)
asmInst.Kind = OtherInstruction
switch inst.Op {
case ppc64asm.BL, ppc64asm.BLA, ppc64asm.BCL, ppc64asm.BCLA, ppc64asm.BCLRL, ppc64asm.BCCTRL, ppc64asm.BCTARL:
// Pages 38-40 Book I v3.0
asmInst.Kind = CallInstruction
case ppc64asm.RFEBB, ppc64asm.RFID, ppc64asm.HRFID, ppc64asm.BCLR:
asmInst.Kind = RetInstruction
case ppc64asm.B, ppc64asm.BA, ppc64asm.BC, ppc64asm.BCA, ppc64asm.BCCTR, ppc64asm.BCTAR:
// Pages 38-40 Book I v3.0
asmInst.Kind = JmpInstruction
case ppc64asm.TD, ppc64asm.TDI, ppc64asm.TW, ppc64asm.TWI:
asmInst.Kind = HardBreakInstruction
}
asmInst.DestLoc = resolveCallArgPPC64LE(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi)
return nil
}
func resolveCallArgPPC64LE(inst *ppc64asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
switch inst.Op {
case ppc64asm.BCLRL, ppc64asm.BCLR:
if regs != nil && regs.PC() == instAddr {
pc := regs.Reg(bininfo.Arch.LRRegNum).Uint64Val
file, line, fn := bininfo.PCToLine(pc)
if fn == nil {
return &Location{PC: pc}
}
return &Location{PC: pc, File: file, Line: line, Fn: fn}
}
return nil
case ppc64asm.B, ppc64asm.BL, ppc64asm.BLA, ppc64asm.BCL, ppc64asm.BCLA, ppc64asm.BCCTRL, ppc64asm.BCTARL:
// ok
default:
return nil
}
var pc uint64
var err error
switch arg := inst.Args[0].(type) {
case ppc64asm.Imm:
pc = uint64(arg)
case ppc64asm.Reg:
if !currentGoroutine || regs == nil {
return nil
}
pc, err = bininfo.Arch.getAsmRegister(regs, int(arg))
if err != nil {
return nil
}
case ppc64asm.PCRel:
pc = 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 ppc64ArchInst ppc64asm.Inst
func (inst *ppc64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string {
if inst == nil {
return "?"
}
var text string
switch flavour {
case GNUFlavour:
text = ppc64asm.GNUSyntax(ppc64asm.Inst(*inst), pc)
default:
text = ppc64asm.GoSyntax(ppc64asm.Inst(*inst), pc, symLookup)
}
return text
}
func (inst *ppc64ArchInst) OpcodeEquals(op uint64) bool {
if inst == nil {
return false
}
return uint64(inst.Op) == op
}
var ppc64leAsmRegisters = func() map[int]asmRegister {
r := make(map[int]asmRegister)
// General Purpose Registers: from R0 to R31
for i := ppc64asm.R0; i <= ppc64asm.R31; i++ {
r[int(i)] = asmRegister{regnum.PPC64LE_R0 + uint64(i-ppc64asm.R0), 0, 0}
}
// Floating point registers: from F0 to F31
for i := ppc64asm.F0; i <= ppc64asm.F31; i++ {
r[int(i)] = asmRegister{regnum.PPC64LE_F0 + uint64(i-ppc64asm.F0), 0, 0}
}
// Vector (Altivec/VMX) registers: from V0 to V31
for i := ppc64asm.V0; i <= ppc64asm.V31; i++ {
r[int(i)] = asmRegister{regnum.PPC64LE_V0 + uint64(i-ppc64asm.V0), 0, 0}
}
// Vector Scalar (VSX) registers: from VS0 to VS63
for i := ppc64asm.VS0; i <= ppc64asm.VS63; i++ {
r[int(i)] = asmRegister{regnum.PPC64LE_VS0 + uint64(i-ppc64asm.VS0), 0, 0}
}
// Condition Registers: from CR0 to CR7
for i := ppc64asm.CR0; i <= ppc64asm.CR7; i++ {
r[int(i)] = asmRegister{regnum.PPC64LE_CR0 + uint64(i-ppc64asm.CR0), 0, 0}
}
return r
}()
|