Coverage Report

Created: 2023-09-25 06:24

/src/capstonenext/Mapping.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine */
2
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */
3
/*    Rot127 <unisono@quyllur.org>, 2022-2023 */
4
5
#include "Mapping.h"
6
#include "capstone/capstone.h"
7
8
// create a cache for fast id lookup
9
static unsigned short *make_id2insn(const insn_map *insns, unsigned int size)
10
23.3k
{
11
  // NOTE: assume that the max id is always put at the end of insns array
12
23.3k
  unsigned short max_id = insns[size - 1].id;
13
23.3k
  unsigned short i;
14
15
23.3k
  unsigned short *cache =
16
23.3k
    (unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache));
17
18
70.4M
  for (i = 1; i < size; i++)
19
70.4M
    cache[insns[i].id] = i;
20
21
23.3k
  return cache;
22
23.3k
}
23
24
// look for @id in @insns, given its size in @max. first time call will update
25
// @cache. return 0 if not found
26
unsigned short insn_find(const insn_map *insns, unsigned int max,
27
       unsigned int id, unsigned short **cache)
28
1.79M
{
29
1.79M
  if (id > insns[max - 1].id)
30
0
    return 0;
31
32
1.79M
  if (*cache == NULL)
33
23.3k
    *cache = make_id2insn(insns, max);
34
35
1.79M
  return (*cache)[id];
36
1.79M
}
37
38
// Gives the id for the given @name if it is saved in @map.
39
// Returns the id or -1 if not found.
40
int name2id(const name_map *map, int max, const char *name)
41
80.6k
{
42
80.6k
  int i;
43
44
15.5M
  for (i = 0; i < max; i++) {
45
15.5M
    if (!strcmp(map[i].name, name)) {
46
47.0k
      return map[i].id;
47
47.0k
    }
48
15.5M
  }
49
50
  // nothing match
51
33.5k
  return -1;
52
80.6k
}
53
54
// Gives the name for the given @id if it is saved in @map.
55
// Returns the name or NULL if not found.
56
const char *id2name(const name_map *map, int max, const unsigned int id)
57
2.54M
{
58
2.54M
  int i;
59
60
41.9M
  for (i = 0; i < max; i++) {
61
41.9M
    if (map[i].id == id) {
62
2.54M
      return map[i].name;
63
2.54M
    }
64
41.9M
  }
65
66
  // nothing match
67
0
  return NULL;
68
2.54M
}
69
70
/// Adds a register to the implicit write register list.
71
/// It will not add the same register twice.
72
void map_add_implicit_write(MCInst *MI, uint32_t Reg)
73
385k
{
74
385k
  if (!MI->flat_insn->detail)
75
0
    return;
76
77
385k
  uint16_t *regs_write = MI->flat_insn->detail->regs_write;
78
388k
  for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
79
388k
    if (i == MI->flat_insn->detail->regs_write_count) {
80
365k
      regs_write[i] = Reg;
81
365k
      MI->flat_insn->detail->regs_write_count++;
82
365k
      return;
83
365k
    }
84
22.5k
    if (regs_write[i] == Reg)
85
19.9k
      return;
86
22.5k
  }
87
385k
}
88
89
/// Adds a register to the implicit read register list.
90
/// It will not add the same register twice.
91
void map_add_implicit_read(MCInst *MI, uint32_t Reg)
92
188k
{
93
188k
  if (!MI->flat_insn->detail)
94
0
    return;
95
96
188k
  uint16_t *regs_read = MI->flat_insn->detail->regs_read;
97
197k
  for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
98
197k
    if (i == MI->flat_insn->detail->regs_read_count) {
99
170k
      regs_read[i] = Reg;
100
170k
      MI->flat_insn->detail->regs_read_count++;
101
170k
      return;
102
170k
    }
103
26.9k
    if (regs_read[i] == Reg)
104
17.6k
      return;
105
26.9k
  }
106
188k
}
107
108
/// Removes a register from the implicit write register list.
109
void map_remove_implicit_write(MCInst *MI, uint32_t Reg)
110
32.2k
{
111
32.2k
  if (!MI->flat_insn->detail)
112
0
    return;
113
114
32.2k
  uint16_t *regs_write = MI->flat_insn->detail->regs_write;
115
32.2k
  bool shorten_list = false;
116
35.1k
  for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
117
35.1k
    if (shorten_list) {
118
2.89k
      regs_write[i - 1] = regs_write[i];
119
2.89k
    }
120
35.1k
    if (i >= MI->flat_insn->detail->regs_write_count)
121
32.2k
      return;
122
123
2.89k
    if (regs_write[i] == Reg) {
124
2.89k
      MI->flat_insn->detail->regs_write_count--;
125
      // The register should exist only once in the list.
126
2.89k
      assert(!shorten_list);
127
2.89k
      shorten_list = true;
128
2.89k
    }
129
2.89k
  }
130
32.2k
}
131
132
/// Copies the implicit read registers of @imap to @MI->flat_insn.
133
/// Already present registers will be preserved.
134
void map_implicit_reads(MCInst *MI, const insn_map *imap)
135
1.28M
{
136
1.28M
#ifndef CAPSTONE_DIET
137
1.28M
  if (!MI->flat_insn->detail)
138
0
    return;
139
140
1.28M
  cs_detail *detail = MI->flat_insn->detail;
141
1.28M
  unsigned Opcode = MCInst_getOpcode(MI);
142
1.28M
  unsigned i = 0;
143
1.28M
  uint16_t reg = imap[Opcode].regs_use[i];
144
1.33M
  while (reg != 0) {
145
52.1k
    if (i >= MAX_IMPL_R_REGS ||
146
52.1k
        detail->regs_read_count >= MAX_IMPL_R_REGS) {
147
0
      printf("ERROR: Too many implicit read register defined in "
148
0
             "instruction mapping.\n");
149
0
      return;
150
0
    }
151
52.1k
    detail->regs_read[detail->regs_read_count++] = reg;
152
52.1k
    reg = imap[Opcode].regs_use[++i];
153
52.1k
  }
154
1.28M
#endif // CAPSTONE_DIET
155
1.28M
}
156
157
/// Copies the implicit write registers of @imap to @MI->flat_insn.
158
/// Already present registers will be preserved.
159
void map_implicit_writes(MCInst *MI, const insn_map *imap)
160
1.28M
{
161
1.28M
#ifndef CAPSTONE_DIET
162
1.28M
  if (!MI->flat_insn->detail)
163
0
    return;
164
165
1.28M
  cs_detail *detail = MI->flat_insn->detail;
166
1.28M
  unsigned Opcode = MCInst_getOpcode(MI);
167
1.28M
  unsigned i = 0;
168
1.28M
  uint16_t reg = imap[Opcode].regs_mod[i];
169
1.48M
  while (reg != 0) {
170
199k
    if (i >= MAX_IMPL_W_REGS ||
171
199k
        detail->regs_write_count >= MAX_IMPL_W_REGS) {
172
0
      printf("ERROR: Too many implicit write register defined in "
173
0
             "instruction mapping.\n");
174
0
      return;
175
0
    }
176
199k
    detail->regs_write[detail->regs_write_count++] = reg;
177
199k
    reg = imap[Opcode].regs_mod[++i];
178
199k
  }
179
1.28M
#endif // CAPSTONE_DIET
180
1.28M
}
181
182
/// Adds a given group to @MI->flat_insn.
183
void add_group(MCInst *MI, unsigned /* arch_group */ group)
184
48.9k
{
185
48.9k
#ifndef CAPSTONE_DIET
186
48.9k
  if (!MI->flat_insn->detail)
187
0
    return;
188
189
48.9k
  cs_detail *detail = MI->flat_insn->detail;
190
48.9k
  if (detail->groups_count >= MAX_NUM_GROUPS) {
191
0
    printf("ERROR: Too many groups defined.\n");
192
0
    return;
193
0
  }
194
48.9k
  detail->groups[detail->groups_count++] = group;
195
48.9k
#endif // CAPSTONE_DIET
196
48.9k
}
197
198
/// Copies the groups from @imap to @MI->flat_insn.
199
/// Already present groups will be preserved.
200
void map_groups(MCInst *MI, const insn_map *imap)
201
1.28M
{
202
1.28M
#ifndef CAPSTONE_DIET
203
1.28M
  if (!MI->flat_insn->detail)
204
0
    return;
205
206
1.28M
  cs_detail *detail = MI->flat_insn->detail;
207
1.28M
  unsigned Opcode = MCInst_getOpcode(MI);
208
1.28M
  unsigned i = 0;
209
1.28M
  uint16_t group = imap[Opcode].groups[i];
210
2.77M
  while (group != 0) {
211
1.48M
    if (detail->groups_count >= MAX_NUM_GROUPS) {
212
0
      printf("ERROR: Too many groups defined in instruction mapping.\n");
213
0
      return;
214
0
    }
215
1.48M
    detail->groups[detail->groups_count++] = group;
216
1.48M
    group = imap[Opcode].groups[++i];
217
1.48M
  }
218
1.28M
#endif // CAPSTONE_DIET
219
1.28M
}
220
221
// Search for the CS instruction id for the given @MC_Opcode in @imap.
222
// return -1 if none is found.
223
unsigned int find_cs_id(unsigned MC_Opcode, const insn_map *imap,
224
      unsigned imap_size)
225
1.28M
{
226
  // binary searching since the IDs are sorted in order
227
1.28M
  unsigned int left, right, m;
228
1.28M
  unsigned int max = imap_size;
229
230
1.28M
  right = max - 1;
231
232
1.28M
  if (MC_Opcode < imap[0].id || MC_Opcode > imap[right].id)
233
    // not found
234
0
    return -1;
235
236
1.28M
  left = 0;
237
238
14.4M
  while (left <= right) {
239
14.4M
    m = (left + right) / 2;
240
14.4M
    if (MC_Opcode == imap[m].id) {
241
1.28M
      return m;
242
1.28M
    }
243
244
13.1M
    if (MC_Opcode < imap[m].id)
245
3.79M
      right = m - 1;
246
9.33M
    else
247
9.33M
      left = m + 1;
248
13.1M
  }
249
250
0
  return -1;
251
1.28M
}
252
253
/// Sets the Capstone instruction id which maps to the @MI opcode.
254
/// If no mapping is found the function returns and prints an error.
255
void map_cs_id(MCInst *MI, const insn_map *imap, unsigned int imap_size)
256
1.28M
{
257
1.28M
  unsigned int i = find_cs_id(MCInst_getOpcode(MI), imap, imap_size);
258
1.28M
  if (i != -1) {
259
1.28M
    MI->flat_insn->id = imap[i].mapid;
260
1.28M
    return;
261
1.28M
  }
262
0
  printf("ERROR: Could not find CS id for MCInst opcode: %d\n",
263
0
         MCInst_getOpcode(MI));
264
0
  return;
265
1.28M
}
266
267
/// Returns the operand type information from the
268
/// mapping table for instruction operands.
269
/// Only usable by `auto-sync` archs!
270
const cs_op_type mapping_get_op_type(MCInst *MI, unsigned OpNum,
271
             const map_insn_ops *insn_ops_map,
272
             size_t map_size)
273
11.3M
{
274
11.3M
  assert(MI);
275
11.3M
  assert(MI->Opcode < map_size);
276
11.3M
  assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
277
11.3M
             sizeof(insn_ops_map[MI->Opcode].ops[0]));
278
279
11.3M
  return insn_ops_map[MI->Opcode].ops[OpNum].type;
280
11.3M
}
281
282
/// Returns the operand access flags from the
283
/// mapping table for instruction operands.
284
/// Only usable by `auto-sync` archs!
285
const cs_ac_type mapping_get_op_access(MCInst *MI, unsigned OpNum,
286
               const map_insn_ops *insn_ops_map,
287
               size_t map_size)
288
3.77M
{
289
3.77M
  assert(MI);
290
3.77M
  assert(MI->Opcode < map_size);
291
3.77M
  assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
292
3.77M
             sizeof(insn_ops_map[MI->Opcode].ops[0]));
293
294
3.77M
  cs_ac_type access = insn_ops_map[MI->Opcode].ops[OpNum].access;
295
3.77M
  if (MCInst_opIsTied(MI, OpNum) || MCInst_opIsTying(MI, OpNum))
296
295k
    access |= (access == CS_AC_READ) ? CS_AC_WRITE : CS_AC_READ;
297
3.77M
  return access;
298
3.77M
}
299
300
/// Returns the operand at detail->arch.operands[op_count + offset]
301
/// Or NULL if detail is not set.
302
#define DEFINE_get_detail_op(arch, ARCH) \
303
  cs_##arch##_op *ARCH##_get_detail_op(MCInst *MI, int offset) \
304
14.5M
  { \
305
14.5M
    if (!MI->flat_insn->detail) \
306
14.5M
      return NULL; \
307
14.5M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
308
14.5M
    assert(OpIdx >= 0 && OpIdx < MAX_MC_OPS); \
309
14.5M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
310
14.5M
  }
ARM_get_detail_op
Line
Count
Source
304
13.9M
  { \
305
13.9M
    if (!MI->flat_insn->detail) \
306
13.9M
      return NULL; \
307
13.9M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
308
13.9M
    assert(OpIdx >= 0 && OpIdx < MAX_MC_OPS); \
309
13.9M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
310
13.9M
  }
PPC_get_detail_op
Line
Count
Source
304
657k
  { \
305
657k
    if (!MI->flat_insn->detail) \
306
657k
      return NULL; \
307
657k
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
308
657k
    assert(OpIdx >= 0 && OpIdx < MAX_MC_OPS); \
309
657k
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
310
657k
  }
Unexecuted instantiation: TriCore_get_detail_op
311
312
DEFINE_get_detail_op(arm, ARM);
313
DEFINE_get_detail_op(ppc, PPC);
314
DEFINE_get_detail_op(tricore, TriCore);
315
316
/// Returns true if for this architecture the
317
/// alias operands should be filled.
318
/// TODO: Replace this with a proper option.
319
///       So it can be toggled between disas() calls.
320
127k
bool map_use_alias_details(const MCInst *MI) {
321
127k
  assert(MI);
322
127k
  return !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL);
323
127k
}
324
325
/// Sets the setDetailOps flag to @p Val.
326
/// If detail == NULLit refuses to set the flag to true.
327
114k
void map_set_fill_detail_ops(MCInst *MI, bool Val) {
328
114k
  assert(MI);
329
114k
  if (!detail_is_set(MI)) {
330
0
    MI->fillDetailOps = false;
331
0
    return;
332
0
  }
333
334
114k
  MI->fillDetailOps = Val;
335
114k
}
336
337
/// Sets the instruction alias flags and the given alias id.
338
0
void map_set_is_alias_insn(MCInst *MI, bool Val, uint64_t Alias) {
339
0
  assert(MI);
340
0
  MI->isAliasInstr = Val;
341
0
  MI->flat_insn->is_alias = Val;
342
0
  MI->flat_insn->alias_id = Alias;
343
0
}
344
345
/// Sets an alternative id for some instruction.
346
/// Or -1 if it fails.
347
/// You must add (<ARCH>_INS_ALIAS_BEGIN + 1) to the id to get the real id.
348
63.8k
void map_set_alias_id(MCInst *MI, const SStream *O, const name_map *alias_mnem_id_map, int map_size) {
349
63.8k
  if (!MCInst_isAlias(MI))
350
53.2k
    return;
351
352
10.5k
  char alias_mnem[16] = { 0 };
353
10.5k
  int i = 0, j = 0;
354
10.5k
  const char *asm_str_buf = O->buffer;
355
  // Skip spaces and tabs
356
10.5k
  while (asm_str_buf[i] == ' ' || asm_str_buf[i] == '\t') {
357
0
    if (!asm_str_buf[i]) {
358
0
      MI->flat_insn->alias_id = -1;
359
0
      return;
360
0
    }
361
0
    ++i;
362
0
  }
363
73.5k
  for (; j < sizeof(alias_mnem) - 1; ++j, ++i) {
364
73.5k
    if (!asm_str_buf[i] || asm_str_buf[i] == ' ' || asm_str_buf[i] == '\t')
365
10.5k
      break;
366
62.9k
    alias_mnem[j] = O->buffer[i];
367
62.9k
  }
368
369
10.5k
  MI->flat_insn->alias_id = name2id(alias_mnem_id_map, map_size, alias_mnem);
370
10.5k
}
371