Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/capstone/Mapping.c
4387 views
1
/* Capstone Disassembly Engine */
2
/* By Nguyen Anh Quynh <[email protected]>, 2013-2019 */
3
/* Rot127 <[email protected]>, 2022-2023 */
4
5
#include "Mapping.h"
6
7
// create a cache for fast id lookup
8
static unsigned short *make_id2insn(const insn_map *insns, unsigned int size)
9
{
10
// NOTE: assume that the max id is always put at the end of insns array
11
unsigned short max_id = insns[size - 1].id;
12
unsigned int i;
13
14
unsigned short *cache =
15
(unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache));
16
17
for (i = 1; i < size; i++)
18
cache[insns[i].id] = i;
19
20
return cache;
21
}
22
23
// look for @id in @insns, given its size in @max. first time call will update
24
// @cache. return 0 if not found
25
unsigned short insn_find(const insn_map *insns, unsigned int max,
26
unsigned int id, unsigned short **cache)
27
{
28
if (id > insns[max - 1].id)
29
return 0;
30
31
if (*cache == NULL)
32
*cache = make_id2insn(insns, max);
33
34
return (*cache)[id];
35
}
36
37
// Gives the id for the given @name if it is saved in @map.
38
// Returns the id or -1 if not found.
39
int name2id(const name_map *map, int max, const char *name)
40
{
41
int i;
42
43
for (i = 0; i < max; i++) {
44
if (!strcmp(map[i].name, name)) {
45
return map[i].id;
46
}
47
}
48
49
// nothing match
50
return -1;
51
}
52
53
// Gives the name for the given @id if it is saved in @map.
54
// Returns the name or NULL if not found.
55
const char *id2name(const name_map *map, int max, const unsigned int id)
56
{
57
int i;
58
59
for (i = 0; i < max; i++) {
60
if (map[i].id == id) {
61
return map[i].name;
62
}
63
}
64
65
// nothing match
66
return NULL;
67
}
68
69
/// Adds a register to the implicit write register list.
70
/// It will not add the same register twice.
71
void map_add_implicit_write(MCInst *MI, uint32_t Reg)
72
{
73
if (!MI->flat_insn->detail)
74
return;
75
76
uint16_t *regs_write = MI->flat_insn->detail->regs_write;
77
for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
78
if (i == MI->flat_insn->detail->regs_write_count) {
79
regs_write[i] = Reg;
80
MI->flat_insn->detail->regs_write_count++;
81
return;
82
}
83
if (regs_write[i] == Reg)
84
return;
85
}
86
}
87
88
/// Copies the implicit read registers of @imap to @MI->flat_insn.
89
/// Already present registers will be preserved.
90
void map_implicit_reads(MCInst *MI, const insn_map *imap)
91
{
92
#ifndef CAPSTONE_DIET
93
if (!MI->flat_insn->detail)
94
return;
95
96
cs_detail *detail = MI->flat_insn->detail;
97
unsigned Opcode = MCInst_getOpcode(MI);
98
unsigned i = 0;
99
uint16_t reg = imap[Opcode].regs_use[i];
100
while (reg != 0) {
101
if (i >= MAX_IMPL_R_REGS ||
102
detail->regs_read_count >= MAX_IMPL_R_REGS) {
103
#if 0 /* disabled in Wine */
104
printf("ERROR: Too many implicit read register defined in "
105
"instruction mapping.\n");
106
#endif
107
return;
108
}
109
detail->regs_read[detail->regs_read_count++] = reg;
110
reg = imap[Opcode].regs_use[++i];
111
}
112
#endif // CAPSTONE_DIET
113
}
114
115
/// Copies the implicit write registers of @imap to @MI->flat_insn.
116
/// Already present registers will be preserved.
117
void map_implicit_writes(MCInst *MI, const insn_map *imap)
118
{
119
#ifndef CAPSTONE_DIET
120
if (!MI->flat_insn->detail)
121
return;
122
123
cs_detail *detail = MI->flat_insn->detail;
124
unsigned Opcode = MCInst_getOpcode(MI);
125
unsigned i = 0;
126
uint16_t reg = imap[Opcode].regs_mod[i];
127
while (reg != 0) {
128
if (i >= MAX_IMPL_W_REGS ||
129
detail->regs_write_count >= MAX_IMPL_W_REGS) {
130
#if 0 /* disabled in Wine */
131
printf("ERROR: Too many implicit write register defined in "
132
"instruction mapping.\n");
133
#endif
134
return;
135
}
136
detail->regs_write[detail->regs_write_count++] = reg;
137
reg = imap[Opcode].regs_mod[++i];
138
}
139
#endif // CAPSTONE_DIET
140
}
141
142
/// Copies the groups from @imap to @MI->flat_insn.
143
/// Already present groups will be preserved.
144
void map_groups(MCInst *MI, const insn_map *imap)
145
{
146
#ifndef CAPSTONE_DIET
147
if (!MI->flat_insn->detail)
148
return;
149
150
cs_detail *detail = MI->flat_insn->detail;
151
unsigned Opcode = MCInst_getOpcode(MI);
152
unsigned i = 0;
153
uint16_t group = imap[Opcode].groups[i];
154
while (group != 0) {
155
if (detail->groups_count >= MAX_NUM_GROUPS) {
156
#if 0 /* disabled in Wine */
157
printf("ERROR: Too many groups defined in instruction mapping.\n");
158
#endif
159
return;
160
}
161
detail->groups[detail->groups_count++] = group;
162
group = imap[Opcode].groups[++i];
163
}
164
#endif // CAPSTONE_DIET
165
}
166
167
// Search for the CS instruction id for the given @MC_Opcode in @imap.
168
// return -1 if none is found.
169
unsigned int find_cs_id(unsigned MC_Opcode, const insn_map *imap,
170
unsigned imap_size)
171
{
172
// binary searching since the IDs are sorted in order
173
unsigned int left, right, m;
174
unsigned int max = imap_size;
175
176
right = max - 1;
177
178
if (MC_Opcode < imap[0].id || MC_Opcode > imap[right].id)
179
// not found
180
return -1;
181
182
left = 0;
183
184
while (left <= right) {
185
m = (left + right) / 2;
186
if (MC_Opcode == imap[m].id) {
187
return m;
188
}
189
190
if (MC_Opcode < imap[m].id)
191
right = m - 1;
192
else
193
left = m + 1;
194
}
195
196
return -1;
197
}
198
199
/// Sets the Capstone instruction id which maps to the @MI opcode.
200
/// If no mapping is found the function returns and prints an error.
201
void map_cs_id(MCInst *MI, const insn_map *imap, unsigned int imap_size)
202
{
203
unsigned int i = find_cs_id(MCInst_getOpcode(MI), imap, imap_size);
204
if (i != -1) {
205
MI->flat_insn->id = imap[i].mapid;
206
return;
207
}
208
#if 0 /* disabled in Wine */
209
printf("ERROR: Could not find CS id for MCInst opcode: %d\n",
210
MCInst_getOpcode(MI));
211
#endif
212
return;
213
}
214
215
/// Returns the operand type information from the
216
/// mapping table for instruction operands.
217
/// Only usable by `auto-sync` archs!
218
const cs_op_type mapping_get_op_type(MCInst *MI, unsigned OpNum,
219
const map_insn_ops *insn_ops_map,
220
size_t map_size)
221
{
222
assert(MI);
223
assert(MI->Opcode < map_size);
224
assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
225
sizeof(insn_ops_map[MI->Opcode].ops[0]));
226
227
return insn_ops_map[MI->Opcode].ops[OpNum].type;
228
}
229
230
/// Returns the operand access flags from the
231
/// mapping table for instruction operands.
232
/// Only usable by `auto-sync` archs!
233
const cs_ac_type mapping_get_op_access(MCInst *MI, unsigned OpNum,
234
const map_insn_ops *insn_ops_map,
235
size_t map_size)
236
{
237
assert(MI);
238
assert(MI->Opcode < map_size);
239
assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
240
sizeof(insn_ops_map[MI->Opcode].ops[0]));
241
242
cs_ac_type access = insn_ops_map[MI->Opcode].ops[OpNum].access;
243
if (MCInst_opIsTied(MI, OpNum) || MCInst_opIsTying(MI, OpNum))
244
access |= (access == CS_AC_READ) ? CS_AC_WRITE : CS_AC_READ;
245
return access;
246
}
247
248
/// Returns the operand at detail->arch.operands[op_count + offset]
249
/// Or NULL if detail is not set.
250
#define DEFINE_get_detail_op(arch, ARCH) \
251
cs_##arch##_op *ARCH##_get_detail_op(MCInst *MI, int offset) \
252
{ \
253
if (!MI->flat_insn->detail) \
254
return NULL; \
255
int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
256
assert(OpIdx >= 0 && OpIdx < MAX_MC_OPS); \
257
return &MI->flat_insn->detail->arch.operands[OpIdx]; \
258
}
259
260
DEFINE_get_detail_op(arm, ARM);
261
DEFINE_get_detail_op(ppc, PPC);
262
DEFINE_get_detail_op(tricore, TriCore);
263
264