ppc64/ppc64asm: improve disassembly for ppc64
The following improvements are included in this change: - Display common special purpose registers for mtlr,mflr,mtctr,mfctr, mtxer,mfxer,mftb; for others use mtspr and mfspr. - Provide branch condition information (lt, gt, eq, ne, ge, le). - Add cr number if cr1-cr7 is used. - Pass pc to gnuArg to generate branch targets that are not relative. Change-Id: Ia3ef6cb248c484a3ad72545e68d1ca59e32ae645 Reviewed-on: https://go-review.googlesource.com/c/arch/+/194597 Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Родитель
46d78d1859
Коммит
7fe50f7625
|
@ -49,7 +49,7 @@ func TestDecode(t *testing.T) {
|
|||
} else {
|
||||
switch syntax {
|
||||
case "gnu":
|
||||
out = GNUSyntax(inst)
|
||||
out = GNUSyntax(inst, 0)
|
||||
case "plan9":
|
||||
out = GoSyntax(inst, 0, nil)
|
||||
default:
|
||||
|
|
|
@ -245,7 +245,7 @@ func disasm(syntax string, src []byte) (inst Inst, text string) {
|
|||
//case "arm":
|
||||
// text = ARMSyntax(inst)
|
||||
case "gnu":
|
||||
text = GNUSyntax(inst)
|
||||
text = GNUSyntax(inst, 0)
|
||||
//case "plan9":
|
||||
// text = GoSyntax(inst, 0, nil)
|
||||
default:
|
||||
|
|
|
@ -10,9 +10,14 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
condBit = [4]string{"lt", "gt", "eq", "so"}
|
||||
condBitNeg = [4]string{"ge", "le", "ne", "so"}
|
||||
)
|
||||
|
||||
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
|
||||
// This form typically matches the syntax defined in the Power ISA Reference Manual.
|
||||
func GNUSyntax(inst Inst) string {
|
||||
func GNUSyntax(inst Inst, pc uint64) string {
|
||||
var buf bytes.Buffer
|
||||
// When there are all 0s, identify them as the disassembler
|
||||
// in binutils would.
|
||||
|
@ -21,13 +26,125 @@ func GNUSyntax(inst Inst) string {
|
|||
} else if inst.Op == 0 {
|
||||
return "error: unknown instruction"
|
||||
}
|
||||
buf.WriteString(inst.Op.String())
|
||||
|
||||
PC := pc
|
||||
// Special handling for some ops
|
||||
startArg := 0
|
||||
sep := " "
|
||||
switch inst.Op.String() {
|
||||
case "bc":
|
||||
bo := gnuArg(&inst, 0, inst.Args[0], PC)
|
||||
bi := inst.Args[1]
|
||||
switch bi := bi.(type) {
|
||||
case CondReg:
|
||||
if bi >= CR0 {
|
||||
if bi == CR0 && bo == "16" {
|
||||
buf.WriteString("bdnz")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("bc cr%d", bi-CR0))
|
||||
}
|
||||
cr := bi / 4
|
||||
switch bo {
|
||||
case "4":
|
||||
bit := condBitNeg[(bi-Cond0LT)%4]
|
||||
if cr == 0 {
|
||||
buf.WriteString(fmt.Sprintf("b%s", bit))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("b%s cr%d,", bit, cr))
|
||||
sep = ""
|
||||
}
|
||||
case "12":
|
||||
bit := condBit[(bi-Cond0LT)%4]
|
||||
if cr == 0 {
|
||||
buf.WriteString(fmt.Sprintf("b%s", bit))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("b%s cr%d,", bit, cr))
|
||||
sep = ""
|
||||
}
|
||||
case "8":
|
||||
bit := condBit[(bi-Cond0LT)%4]
|
||||
sep = ""
|
||||
if cr == 0 {
|
||||
buf.WriteString(fmt.Sprintf("bdnzt %s,", bit))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("bdnzt cr%d,%s,", cr, bit))
|
||||
}
|
||||
case "16":
|
||||
if cr == 0 && bi == Cond0LT {
|
||||
buf.WriteString("bdnz")
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("bdnz cr%d,", cr))
|
||||
sep = ""
|
||||
}
|
||||
}
|
||||
startArg = 2
|
||||
default:
|
||||
fmt.Printf("Unexpected bi: %d for bc with bo: %s\n", bi, bo)
|
||||
}
|
||||
startArg = 2
|
||||
case "mtspr":
|
||||
opcode := inst.Op.String()
|
||||
buf.WriteString(opcode[0:2])
|
||||
switch spr := inst.Args[0].(type) {
|
||||
case SpReg:
|
||||
switch spr {
|
||||
case 1:
|
||||
buf.WriteString("xer")
|
||||
startArg = 1
|
||||
case 8:
|
||||
buf.WriteString("lr")
|
||||
startArg = 1
|
||||
case 9:
|
||||
buf.WriteString("ctr")
|
||||
startArg = 1
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
|
||||
case "mfspr":
|
||||
opcode := inst.Op.String()
|
||||
buf.WriteString(opcode[0:2])
|
||||
arg := inst.Args[0]
|
||||
switch spr := inst.Args[1].(type) {
|
||||
case SpReg:
|
||||
switch spr {
|
||||
case 1:
|
||||
buf.WriteString("xer ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 8:
|
||||
buf.WriteString("lr ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 9:
|
||||
buf.WriteString("ctr ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 268:
|
||||
buf.WriteString("tb ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
|
||||
default:
|
||||
buf.WriteString(inst.Op.String())
|
||||
}
|
||||
for i, arg := range inst.Args[:] {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
text := gnuArg(&inst, i, arg)
|
||||
if i < startArg {
|
||||
continue
|
||||
}
|
||||
text := gnuArg(&inst, i, arg, PC)
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
|
@ -41,7 +158,7 @@ func GNUSyntax(inst Inst) string {
|
|||
// gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules.
|
||||
// NOTE: because GNUSyntax is the only caller of this func, and it receives a copy
|
||||
// of inst, it's ok to modify inst.Args here.
|
||||
func gnuArg(inst *Inst, argIndex int, arg Arg) string {
|
||||
func gnuArg(inst *Inst, argIndex int, arg Arg, pc uint64) string {
|
||||
// special cases for load/store instructions
|
||||
if _, ok := arg.(Offset); ok {
|
||||
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
|
||||
|
@ -55,22 +172,43 @@ func gnuArg(inst *Inst, argIndex int, arg Arg) string {
|
|||
}
|
||||
return arg.String()
|
||||
case CondReg:
|
||||
// The CondReg can either be found in a CMP, where the
|
||||
// condition register field is being set, or in an instruction
|
||||
// like a branch or isel that is testing a bit in a condition
|
||||
// register field.
|
||||
if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
|
||||
return "" // don't show cr0 for cmp instructions
|
||||
} else if arg >= CR0 {
|
||||
return fmt.Sprintf("cr%d", int(arg-CR0))
|
||||
}
|
||||
bit := [4]string{"lt", "gt", "eq", "so"}[(arg-Cond0LT)%4]
|
||||
bit := condBit[(arg-Cond0LT)%4]
|
||||
if arg <= Cond0SO {
|
||||
return bit
|
||||
}
|
||||
return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
|
||||
return fmt.Sprintf("%s cr%d", bit, int(arg-Cond0LT)/4)
|
||||
case Imm:
|
||||
return fmt.Sprintf("%d", arg)
|
||||
case SpReg:
|
||||
return fmt.Sprintf("%d", int(arg))
|
||||
switch int(arg) {
|
||||
case 1:
|
||||
return "xer"
|
||||
case 8:
|
||||
return "lr"
|
||||
case 9:
|
||||
return "ctr"
|
||||
case 268:
|
||||
return "tb"
|
||||
default:
|
||||
return fmt.Sprintf("%d", int(arg))
|
||||
}
|
||||
case PCRel:
|
||||
return fmt.Sprintf(".%+#x", int(arg))
|
||||
// If the arg is 0, use the relative address format.
|
||||
// Otherwise the pc is meaningful, use absolute address.
|
||||
if int(arg) == 0 {
|
||||
return fmt.Sprintf(".%+#x", int(arg))
|
||||
}
|
||||
addr := pc + uint64(int64(arg))
|
||||
return fmt.Sprintf("%#x", addr)
|
||||
case Label:
|
||||
return fmt.Sprintf("%#x", uint32(arg))
|
||||
case Offset:
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
00002000| gnu error: unknown instruction
|
||||
a1841e80| gnu lhz r12,7808(r4)
|
||||
a1841e80| plan9 MOVHZ 7808(R4),R12
|
||||
42093d10| gnu bc 16,4*cr2+gt,.+0x3d10
|
||||
42000004| gnu bdnz 0x4
|
||||
e38d5b90| gnu lq r28,23440(r13)
|
||||
84127a20| gnu lwzu r0,31264(r18)
|
||||
84127a20| plan9 MOVWZU 31264(R18),R0
|
||||
|
@ -54,3 +54,23 @@ fbe1ffd1| plan9 MOVDU R31,-48(R1)
|
|||
7c941f19| plan9 STXVW4X VS36,(R3)(R20)
|
||||
7c6520a8| gnu ldarx r3,r5,r4
|
||||
7c6520a8| plan9 LDAR (R4)(R5),R3
|
||||
7c6803a6| plan9 MOVD R3,LR
|
||||
7c6802a6| plan9 MOVD LR,R3
|
||||
7c6803a6| gnu mtlr r3
|
||||
7c6802a6| gnu mflr r3
|
||||
7c6903a6| plan9 MOVD R3,CTR
|
||||
7c6902a6| plan9 MOVD CTR,R3
|
||||
7c6903a6| gnu mtctr r3
|
||||
7c6902a6| gnu mfctr r3
|
||||
7c6c42a6| gnu mftb r3
|
||||
7c6c42a6| plan9 MOVD SPR(268),R3
|
||||
7c8202a6| plan9 MOVD SPR(2),R4
|
||||
7c8202a6| gnu mfspr r4,2
|
||||
41820010| plan9 BEQ 0x10
|
||||
41820010| gnu beq 0x10
|
||||
4086000c| plan9 BNE CR1,0xc
|
||||
4086000c| gnu bne cr1,0xc
|
||||
41880008| plan9 BLT CR2,0x8
|
||||
41880008| gnu blt cr2,0x8
|
||||
418d0004| plan9 BGT CR3,0x4
|
||||
418d0004| gnu bgt cr3,0x4
|
||||
|
|
Загрузка…
Ссылка в новой задаче