gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

plan9x.go (7267B)


      1 // Copyright 2014 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package x86asm
      6 
      7 import (
      8 	"fmt"
      9 	"strings"
     10 )
     11 
     12 type SymLookup func(uint64) (string, uint64)
     13 
     14 // GoSyntax returns the Go assembler syntax for the instruction.
     15 // The syntax was originally defined by Plan 9.
     16 // The pc is the program counter of the instruction, used for expanding
     17 // PC-relative addresses into absolute ones.
     18 // The symname function queries the symbol table for the program
     19 // being disassembled. Given a target address it returns the name and base
     20 // address of the symbol containing the target, if any; otherwise it returns "", 0.
     21 func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
     22 	if symname == nil {
     23 		symname = func(uint64) (string, uint64) { return "", 0 }
     24 	}
     25 	var args []string
     26 	for i := len(inst.Args) - 1; i >= 0; i-- {
     27 		a := inst.Args[i]
     28 		if a == nil {
     29 			continue
     30 		}
     31 		args = append(args, plan9Arg(&inst, pc, symname, a))
     32 	}
     33 
     34 	var rep string
     35 	var last Prefix
     36 	for _, p := range inst.Prefix {
     37 		if p == 0 || p.IsREX() || p.IsVEX() {
     38 			break
     39 		}
     40 
     41 		switch {
     42 		// Don't show prefixes implied by the instruction text.
     43 		case p&0xFF00 == PrefixImplicit:
     44 			continue
     45 		// Only REP and REPN are recognized repeaters. Plan 9 syntax
     46 		// treats them as separate opcodes.
     47 		case p&0xFF == PrefixREP:
     48 			rep = "REP; "
     49 		case p&0xFF == PrefixREPN:
     50 			rep = "REPNE; "
     51 		default:
     52 			last = p
     53 		}
     54 	}
     55 
     56 	prefix := ""
     57 	switch last & 0xFF {
     58 	case 0, 0x66, 0x67:
     59 		// ignore
     60 	default:
     61 		prefix += last.String() + " "
     62 	}
     63 
     64 	op := inst.Op.String()
     65 	if plan9Suffix[inst.Op] {
     66 		s := inst.DataSize
     67 		if inst.MemBytes != 0 {
     68 			s = inst.MemBytes * 8
     69 		} else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX
     70 			if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
     71 				s = 64
     72 			}
     73 		}
     74 		switch s {
     75 		case 8:
     76 			op += "B"
     77 		case 16:
     78 			op += "W"
     79 		case 32:
     80 			op += "L"
     81 		case 64:
     82 			op += "Q"
     83 		}
     84 	}
     85 
     86 	if args != nil {
     87 		op += " " + strings.Join(args, ", ")
     88 	}
     89 
     90 	return rep + prefix + op
     91 }
     92 
     93 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
     94 	switch a := arg.(type) {
     95 	case Reg:
     96 		return plan9Reg[a]
     97 	case Rel:
     98 		if pc == 0 {
     99 			break
    100 		}
    101 		// If the absolute address is the start of a symbol, use the name.
    102 		// Otherwise use the raw address, so that things like relative
    103 		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
    104 		// It is usually easier to search for 0x123 than to do the mental
    105 		// arithmetic to find f+10.
    106 		addr := pc + uint64(inst.Len) + uint64(a)
    107 		if s, base := symname(addr); s != "" && addr == base {
    108 			return fmt.Sprintf("%s(SB)", s)
    109 		}
    110 		return fmt.Sprintf("%#x", addr)
    111 
    112 	case Imm:
    113 		if s, base := symname(uint64(a)); s != "" {
    114 			suffix := ""
    115 			if uint64(a) != base {
    116 				suffix = fmt.Sprintf("%+d", uint64(a)-base)
    117 			}
    118 			return fmt.Sprintf("$%s%s(SB)", s, suffix)
    119 		}
    120 		if inst.Mode == 32 {
    121 			return fmt.Sprintf("$%#x", uint32(a))
    122 		}
    123 		if Imm(int32(a)) == a {
    124 			return fmt.Sprintf("$%#x", int64(a))
    125 		}
    126 		return fmt.Sprintf("$%#x", uint64(a))
    127 	case Mem:
    128 		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
    129 			suffix := ""
    130 			if disp != 0 {
    131 				suffix = fmt.Sprintf("%+d", disp)
    132 			}
    133 			return fmt.Sprintf("%s%s(SB)", s, suffix)
    134 		}
    135 		s := ""
    136 		if a.Segment != 0 {
    137 			s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
    138 		}
    139 		if a.Disp != 0 {
    140 			s += fmt.Sprintf("%#x", a.Disp)
    141 		} else {
    142 			s += "0"
    143 		}
    144 		if a.Base != 0 {
    145 			s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
    146 		}
    147 		if a.Index != 0 && a.Scale != 0 {
    148 			s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
    149 		}
    150 		return s
    151 	}
    152 	return arg.String()
    153 }
    154 
    155 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
    156 	if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
    157 		return "", 0
    158 	}
    159 
    160 	var disp uint64
    161 	switch a.Base {
    162 	case IP, EIP, RIP:
    163 		disp = uint64(a.Disp + int64(pc) + int64(instrLen))
    164 	case 0:
    165 		disp = uint64(a.Disp)
    166 	default:
    167 		return "", 0
    168 	}
    169 
    170 	s, base := symname(disp)
    171 	return s, int64(disp) - int64(base)
    172 }
    173 
    174 var plan9Suffix = [maxOp + 1]bool{
    175 	ADC:       true,
    176 	ADD:       true,
    177 	AND:       true,
    178 	BSF:       true,
    179 	BSR:       true,
    180 	BT:        true,
    181 	BTC:       true,
    182 	BTR:       true,
    183 	BTS:       true,
    184 	CMP:       true,
    185 	CMPXCHG:   true,
    186 	CVTSI2SD:  true,
    187 	CVTSI2SS:  true,
    188 	CVTSD2SI:  true,
    189 	CVTSS2SI:  true,
    190 	CVTTSD2SI: true,
    191 	CVTTSS2SI: true,
    192 	DEC:       true,
    193 	DIV:       true,
    194 	FLDENV:    true,
    195 	FRSTOR:    true,
    196 	IDIV:      true,
    197 	IMUL:      true,
    198 	IN:        true,
    199 	INC:       true,
    200 	LEA:       true,
    201 	MOV:       true,
    202 	MOVNTI:    true,
    203 	MUL:       true,
    204 	NEG:       true,
    205 	NOP:       true,
    206 	NOT:       true,
    207 	OR:        true,
    208 	OUT:       true,
    209 	POP:       true,
    210 	POPA:      true,
    211 	POPCNT:    true,
    212 	PUSH:      true,
    213 	PUSHA:     true,
    214 	RCL:       true,
    215 	RCR:       true,
    216 	ROL:       true,
    217 	ROR:       true,
    218 	SAR:       true,
    219 	SBB:       true,
    220 	SHL:       true,
    221 	SHLD:      true,
    222 	SHR:       true,
    223 	SHRD:      true,
    224 	SUB:       true,
    225 	TEST:      true,
    226 	XADD:      true,
    227 	XCHG:      true,
    228 	XOR:       true,
    229 }
    230 
    231 var plan9Reg = [...]string{
    232 	AL:   "AL",
    233 	CL:   "CL",
    234 	BL:   "BL",
    235 	DL:   "DL",
    236 	AH:   "AH",
    237 	CH:   "CH",
    238 	BH:   "BH",
    239 	DH:   "DH",
    240 	SPB:  "SP",
    241 	BPB:  "BP",
    242 	SIB:  "SI",
    243 	DIB:  "DI",
    244 	R8B:  "R8",
    245 	R9B:  "R9",
    246 	R10B: "R10",
    247 	R11B: "R11",
    248 	R12B: "R12",
    249 	R13B: "R13",
    250 	R14B: "R14",
    251 	R15B: "R15",
    252 	AX:   "AX",
    253 	CX:   "CX",
    254 	BX:   "BX",
    255 	DX:   "DX",
    256 	SP:   "SP",
    257 	BP:   "BP",
    258 	SI:   "SI",
    259 	DI:   "DI",
    260 	R8W:  "R8",
    261 	R9W:  "R9",
    262 	R10W: "R10",
    263 	R11W: "R11",
    264 	R12W: "R12",
    265 	R13W: "R13",
    266 	R14W: "R14",
    267 	R15W: "R15",
    268 	EAX:  "AX",
    269 	ECX:  "CX",
    270 	EDX:  "DX",
    271 	EBX:  "BX",
    272 	ESP:  "SP",
    273 	EBP:  "BP",
    274 	ESI:  "SI",
    275 	EDI:  "DI",
    276 	R8L:  "R8",
    277 	R9L:  "R9",
    278 	R10L: "R10",
    279 	R11L: "R11",
    280 	R12L: "R12",
    281 	R13L: "R13",
    282 	R14L: "R14",
    283 	R15L: "R15",
    284 	RAX:  "AX",
    285 	RCX:  "CX",
    286 	RDX:  "DX",
    287 	RBX:  "BX",
    288 	RSP:  "SP",
    289 	RBP:  "BP",
    290 	RSI:  "SI",
    291 	RDI:  "DI",
    292 	R8:   "R8",
    293 	R9:   "R9",
    294 	R10:  "R10",
    295 	R11:  "R11",
    296 	R12:  "R12",
    297 	R13:  "R13",
    298 	R14:  "R14",
    299 	R15:  "R15",
    300 	IP:   "IP",
    301 	EIP:  "IP",
    302 	RIP:  "IP",
    303 	F0:   "F0",
    304 	F1:   "F1",
    305 	F2:   "F2",
    306 	F3:   "F3",
    307 	F4:   "F4",
    308 	F5:   "F5",
    309 	F6:   "F6",
    310 	F7:   "F7",
    311 	M0:   "M0",
    312 	M1:   "M1",
    313 	M2:   "M2",
    314 	M3:   "M3",
    315 	M4:   "M4",
    316 	M5:   "M5",
    317 	M6:   "M6",
    318 	M7:   "M7",
    319 	X0:   "X0",
    320 	X1:   "X1",
    321 	X2:   "X2",
    322 	X3:   "X3",
    323 	X4:   "X4",
    324 	X5:   "X5",
    325 	X6:   "X6",
    326 	X7:   "X7",
    327 	X8:   "X8",
    328 	X9:   "X9",
    329 	X10:  "X10",
    330 	X11:  "X11",
    331 	X12:  "X12",
    332 	X13:  "X13",
    333 	X14:  "X14",
    334 	X15:  "X15",
    335 	CS:   "CS",
    336 	SS:   "SS",
    337 	DS:   "DS",
    338 	ES:   "ES",
    339 	FS:   "FS",
    340 	GS:   "GS",
    341 	GDTR: "GDTR",
    342 	IDTR: "IDTR",
    343 	LDTR: "LDTR",
    344 	MSW:  "MSW",
    345 	TASK: "TASK",
    346 	CR0:  "CR0",
    347 	CR1:  "CR1",
    348 	CR2:  "CR2",
    349 	CR3:  "CR3",
    350 	CR4:  "CR4",
    351 	CR5:  "CR5",
    352 	CR6:  "CR6",
    353 	CR7:  "CR7",
    354 	CR8:  "CR8",
    355 	CR9:  "CR9",
    356 	CR10: "CR10",
    357 	CR11: "CR11",
    358 	CR12: "CR12",
    359 	CR13: "CR13",
    360 	CR14: "CR14",
    361 	CR15: "CR15",
    362 	DR0:  "DR0",
    363 	DR1:  "DR1",
    364 	DR2:  "DR2",
    365 	DR3:  "DR3",
    366 	DR4:  "DR4",
    367 	DR5:  "DR5",
    368 	DR6:  "DR6",
    369 	DR7:  "DR7",
    370 	DR8:  "DR8",
    371 	DR9:  "DR9",
    372 	DR10: "DR10",
    373 	DR11: "DR11",
    374 	DR12: "DR12",
    375 	DR13: "DR13",
    376 	DR14: "DR14",
    377 	DR15: "DR15",
    378 	TR0:  "TR0",
    379 	TR1:  "TR1",
    380 	TR2:  "TR2",
    381 	TR3:  "TR3",
    382 	TR4:  "TR4",
    383 	TR5:  "TR5",
    384 	TR6:  "TR6",
    385 	TR7:  "TR7",
    386 }