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 {
|
} else {
|
||||||
switch syntax {
|
switch syntax {
|
||||||
case "gnu":
|
case "gnu":
|
||||||
out = GNUSyntax(inst)
|
out = GNUSyntax(inst, 0)
|
||||||
case "plan9":
|
case "plan9":
|
||||||
out = GoSyntax(inst, 0, nil)
|
out = GoSyntax(inst, 0, nil)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -245,7 +245,7 @@ func disasm(syntax string, src []byte) (inst Inst, text string) {
|
||||||
//case "arm":
|
//case "arm":
|
||||||
// text = ARMSyntax(inst)
|
// text = ARMSyntax(inst)
|
||||||
case "gnu":
|
case "gnu":
|
||||||
text = GNUSyntax(inst)
|
text = GNUSyntax(inst, 0)
|
||||||
//case "plan9":
|
//case "plan9":
|
||||||
// text = GoSyntax(inst, 0, nil)
|
// text = GoSyntax(inst, 0, nil)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -10,9 +10,14 @@ import (
|
||||||
"strings"
|
"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.
|
// 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.
|
// 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
|
var buf bytes.Buffer
|
||||||
// When there are all 0s, identify them as the disassembler
|
// When there are all 0s, identify them as the disassembler
|
||||||
// in binutils would.
|
// in binutils would.
|
||||||
|
@ -21,13 +26,125 @@ func GNUSyntax(inst Inst) string {
|
||||||
} else if inst.Op == 0 {
|
} else if inst.Op == 0 {
|
||||||
return "error: unknown instruction"
|
return "error: unknown instruction"
|
||||||
}
|
}
|
||||||
buf.WriteString(inst.Op.String())
|
|
||||||
|
PC := pc
|
||||||
|
// Special handling for some ops
|
||||||
|
startArg := 0
|
||||||
sep := " "
|
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[:] {
|
for i, arg := range inst.Args[:] {
|
||||||
if arg == nil {
|
if arg == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
text := gnuArg(&inst, i, arg)
|
if i < startArg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
text := gnuArg(&inst, i, arg, PC)
|
||||||
if text == "" {
|
if text == "" {
|
||||||
continue
|
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.
|
// 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
|
// 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.
|
// 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
|
// special cases for load/store instructions
|
||||||
if _, ok := arg.(Offset); ok {
|
if _, ok := arg.(Offset); ok {
|
||||||
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
|
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()
|
return arg.String()
|
||||||
case CondReg:
|
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") {
|
if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
|
||||||
return "" // don't show cr0 for cmp instructions
|
return "" // don't show cr0 for cmp instructions
|
||||||
} else if arg >= CR0 {
|
} else if arg >= CR0 {
|
||||||
return fmt.Sprintf("cr%d", int(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 {
|
if arg <= Cond0SO {
|
||||||
return bit
|
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:
|
case Imm:
|
||||||
return fmt.Sprintf("%d", arg)
|
return fmt.Sprintf("%d", arg)
|
||||||
case SpReg:
|
case SpReg:
|
||||||
|
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))
|
return fmt.Sprintf("%d", int(arg))
|
||||||
|
}
|
||||||
case PCRel:
|
case PCRel:
|
||||||
|
// 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))
|
return fmt.Sprintf(".%+#x", int(arg))
|
||||||
|
}
|
||||||
|
addr := pc + uint64(int64(arg))
|
||||||
|
return fmt.Sprintf("%#x", addr)
|
||||||
case Label:
|
case Label:
|
||||||
return fmt.Sprintf("%#x", uint32(arg))
|
return fmt.Sprintf("%#x", uint32(arg))
|
||||||
case Offset:
|
case Offset:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
00002000| gnu error: unknown instruction
|
00002000| gnu error: unknown instruction
|
||||||
a1841e80| gnu lhz r12,7808(r4)
|
a1841e80| gnu lhz r12,7808(r4)
|
||||||
a1841e80| plan9 MOVHZ 7808(R4),R12
|
a1841e80| plan9 MOVHZ 7808(R4),R12
|
||||||
42093d10| gnu bc 16,4*cr2+gt,.+0x3d10
|
42000004| gnu bdnz 0x4
|
||||||
e38d5b90| gnu lq r28,23440(r13)
|
e38d5b90| gnu lq r28,23440(r13)
|
||||||
84127a20| gnu lwzu r0,31264(r18)
|
84127a20| gnu lwzu r0,31264(r18)
|
||||||
84127a20| plan9 MOVWZU 31264(R18),R0
|
84127a20| plan9 MOVWZU 31264(R18),R0
|
||||||
|
@ -54,3 +54,23 @@ fbe1ffd1| plan9 MOVDU R31,-48(R1)
|
||||||
7c941f19| plan9 STXVW4X VS36,(R3)(R20)
|
7c941f19| plan9 STXVW4X VS36,(R3)(R20)
|
||||||
7c6520a8| gnu ldarx r3,r5,r4
|
7c6520a8| gnu ldarx r3,r5,r4
|
||||||
7c6520a8| plan9 LDAR (R4)(R5),R3
|
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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче