-
Notifications
You must be signed in to change notification settings - Fork 43
/
arm_decomposer.go
155 lines (139 loc) · 3.59 KB
/
arm_decomposer.go
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
/*
Gapstone is a Go binding for the Capstone disassembly library. For examples,
try reading the *_test.go files.
Library Author: Nguyen Anh Quynh
Binding Author: Ben Nagy
License: BSD style - see LICENSE file for details
(c) 2013 COSEINC. All Rights Reserved.
*/
package gapstone
// #cgo LDFLAGS: -lcapstone
// #cgo freebsd CFLAGS: -I/usr/local/include
// #cgo freebsd LDFLAGS: -L/usr/local/lib
// #include <stdlib.h>
// #include <capstone/capstone.h>
import "C"
import (
"reflect"
"unsafe"
)
// Accessed via insn.Arm.XXX
type ArmInstruction struct {
UserMode bool
VectorSize int
VectorData int
CPSMode int
CPSFlag int
CC uint
UpdateFlags bool
Writeback bool
MemBarrier int
Operands []ArmOperand
}
type ArmShifter struct {
Type uint
Value uint
}
type ArmOperand struct {
VectorIndex int
Shift ArmShifter
Type uint // ARM_OP_* - determines which field is set below
Reg uint
Imm int32
FP float64
Mem ArmMemoryOperand
Setend int
Subtracted bool
Access uint
NeonLane int
}
type ArmMemoryOperand struct {
Base uint
Index uint
Scale int
Disp int
LShift int
}
// Number of Operands of a given ARM_OP_* type
func (insn ArmInstruction) OpCount(optype uint) int {
count := 0
for _, op := range insn.Operands {
if op.Type == optype {
count++
}
}
return count
}
func fillArmHeader(raw C.cs_insn, insn *Instruction) {
if raw.detail == nil {
return
}
// Cast the cs_detail union
cs_arm := (*C.cs_arm)(unsafe.Pointer(&raw.detail.anon0[0]))
arm := ArmInstruction{
UserMode: bool(cs_arm.usermode),
VectorSize: int(cs_arm.vector_size),
VectorData: int(cs_arm.vector_data),
CPSMode: int(cs_arm.cps_mode),
CPSFlag: int(cs_arm.cps_flag),
CC: uint(cs_arm.cc),
UpdateFlags: bool(cs_arm.update_flags),
Writeback: bool(cs_arm.writeback),
MemBarrier: int(cs_arm.mem_barrier),
}
// Cast the op_info to a []C.cs_arm_op
var ops []C.cs_arm_op
h := (*reflect.SliceHeader)(unsafe.Pointer(&ops))
h.Data = uintptr(unsafe.Pointer(&cs_arm.operands[0]))
h.Len = int(cs_arm.op_count)
h.Cap = int(cs_arm.op_count)
// Create the Go object for each operand
for _, cop := range ops {
if cop._type == ARM_OP_INVALID {
break
}
gop := ArmOperand{
Shift: ArmShifter{
Type: uint(cop.shift._type),
Value: uint(cop.shift.value),
},
Type: uint(cop._type),
VectorIndex: int(cop.vector_index),
Subtracted: bool(cop.subtracted),
Access: uint(cop.access),
NeonLane: int(cop.neon_lane),
}
switch cop._type {
// fake a union by setting only the correct struct member
case ARM_OP_IMM, ARM_OP_CIMM, ARM_OP_PIMM:
gop.Imm = int32(*(*C.int32_t)(unsafe.Pointer(&cop.anon0[0])))
case ARM_OP_FP:
gop.FP = float64(*(*C.double)(unsafe.Pointer(&cop.anon0[0])))
case ARM_OP_REG, ARM_OP_SYSREG:
gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0])))
case ARM_OP_MEM:
cmop := (*C.arm_op_mem)(unsafe.Pointer(&cop.anon0[0]))
gop.Mem = ArmMemoryOperand{
Base: uint(cmop.base),
Index: uint(cmop.index),
Scale: int(cmop.scale),
Disp: int(cmop.disp),
LShift: int(cmop.lshift),
}
case ARM_OP_SETEND:
gop.Setend = int(*(*C.int)(unsafe.Pointer(&cop.anon0[0])))
}
arm.Operands = append(arm.Operands, gop)
}
insn.Arm = &arm
}
func decomposeArm(e *Engine, raws []C.cs_insn) []Instruction {
decomposed := []Instruction{}
for _, raw := range raws {
decomp := new(Instruction)
fillGenericHeader(e, raw, decomp)
fillArmHeader(raw, decomp)
decomposed = append(decomposed, *decomp)
}
return decomposed
}