forked from knightsc/gapstone
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patharm_decomposer.go
More file actions
169 lines (150 loc) · 5.14 KB
/
Copy patharm_decomposer.go
File metadata and controls
169 lines (150 loc) · 5.14 KB
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
/*
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"
)
// FIXME: somthing goes wrond for thumb2 decomposing for ex..
// Accessed via insn.Arm.XXX
type ArmInstruction struct {
UserMode bool ///< User-mode registers to be loaded (for LDM/STM instructions)
VectorSize int ///< Scalar size for vector instructions
VectorData int ///< Data type for elements of vector instructions
CPSMode int ///< CPS mode for CPS instruction
CPSFlag int ///< CPS mode for CPS instruction //? flag
CC uint ///< conditional code for this insn
UpdateFlags bool ///< does this insn update flags?
Writeback bool ///< does this insn write-back?
MemBarrier int ///< Option for some memory barrier instructions
Operands []ArmOperand ///< operands for this instruction.
}
type ArmShifter struct {
Type uint
Value uint
}
type ArmOperand struct {
VectorIndex int ///< Vector Index for some vector operands (or -1 if irrelevant)///< Vector Index for some vector operands (or -1 if irrelevant)
Shift ArmShifter
// operand type
Type uint // ARM_OP_* - determines which field is set below
Reg uint ///< register value for REG/SYSREG operand
Imm int32 ///< immediate value for C-IMM, P-IMM or IMM operand
FP float64 ///< floating point value for FP operand
Mem ArmMemoryOperand ///< base/index/scale/disp value for MEM operand
Setend int ///< SETEND instruction's operand type
/// in some instructions, an operand can be subtracted or added to
/// the base register,
/// if TRUE, this operand is subtracted. otherwise, it is added.
Subtracted bool
/// How is this operand accessed? (READ, WRITE or READ|WRITE)
/// This field is combined of cs_ac_type.
/// NOTE: this field is irrelevant if engine is compiled in DIET mode.
Access uint8
/// Neon lane index for NEON instructions (or -1 if irrelevant)
NeonLane int8
}
type ArmMemoryOperand struct {
Base uint ///< base register
Index uint ///< index register
Scale int ///< scale for index register (can be 1, or -1)
Disp int ///< displacement/offset value
/// left-shift on index register, or 0 if irrelevant
/// INFO: this value can also be fetched via operand.shift.value
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: uint8(cop.access),
NeonLane: int8(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.int)(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
}