Coverage Report

Created: 2024-09-08 06:22

/src/capstonenext/arch/Mips/MipsMapping.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine */
2
/* By Giovanni Dante Grazioli, deroad <wargio@libero.it>, 2024 */
3
4
#ifdef CAPSTONE_HAS_MIPS
5
6
#include <stdio.h>
7
#include <string.h>
8
9
#include <capstone/capstone.h>
10
#include <capstone/mips.h>
11
12
#include "../../Mapping.h"
13
#include "../../MCDisassembler.h"
14
#include "../../cs_priv.h"
15
#include "../../cs_simple_types.h"
16
17
#include "MipsMapping.h"
18
#include "MipsLinkage.h"
19
#include "MipsDisassembler.h"
20
21
#define GET_REGINFO_ENUM
22
#define GET_REGINFO_MC_DESC
23
#include "MipsGenRegisterInfo.inc"
24
25
#define GET_INSTRINFO_ENUM
26
#include "MipsGenInstrInfo.inc"
27
28
void Mips_init_mri(MCRegisterInfo *MRI)
29
2.88k
{
30
2.88k
  MCRegisterInfo_InitMCRegisterInfo(MRI, MipsRegDesc, sizeof(MipsRegDesc),
31
2.88k
            0, 0, MipsMCRegisterClasses,
32
2.88k
            ARR_SIZE(MipsMCRegisterClasses), 0, 0,
33
2.88k
            MipsRegDiffLists, 0,
34
2.88k
            MipsSubRegIdxLists,
35
2.88k
            ARR_SIZE(MipsSubRegIdxLists), 0);
36
2.88k
}
37
38
const char *Mips_reg_name(csh handle, unsigned int reg)
39
14.7k
{
40
14.7k
  int syntax_opt = ((cs_struct *)(uintptr_t)handle)->syntax;
41
14.7k
  return Mips_LLVM_getRegisterName(reg,
42
14.7k
           syntax_opt & CS_OPT_SYNTAX_NOREGNAME);
43
14.7k
}
44
45
void Mips_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
46
67.9k
{
47
  // Not used by Mips. Information is set after disassembly.
48
67.9k
}
49
50
static const char *const insn_name_maps[] = {
51
#include "MipsGenCSMappingInsnName.inc"
52
};
53
54
const char *Mips_insn_name(csh handle, unsigned int id)
55
67.9k
{
56
67.9k
#ifndef CAPSTONE_DIET
57
67.9k
  if (id < ARR_SIZE(insn_name_maps))
58
67.9k
    return insn_name_maps[id];
59
  // not found
60
0
  return NULL;
61
#else
62
  return NULL;
63
#endif
64
67.9k
}
65
66
#ifndef CAPSTONE_DIET
67
static const name_map group_name_maps[] = {
68
  { MIPS_GRP_INVALID, NULL },
69
70
  { MIPS_GRP_JUMP, "jump" },
71
  { MIPS_GRP_CALL, "call" },
72
  { MIPS_GRP_RET, "return" },
73
  { MIPS_GRP_INT, "int" },
74
  { MIPS_GRP_IRET, "iret" },
75
  { MIPS_GRP_PRIVILEGE, "privilege" },
76
  { MIPS_GRP_BRANCH_RELATIVE, "branch_relative" },
77
78
// architecture-specific groups
79
#include "MipsGenCSFeatureName.inc"
80
};
81
#endif
82
83
const char *Mips_group_name(csh handle, unsigned int id)
84
401k
{
85
401k
#ifndef CAPSTONE_DIET
86
401k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
87
#else
88
  return NULL;
89
#endif
90
401k
}
91
92
const insn_map mips_insns[] = {
93
#include "MipsGenCSMappingInsn.inc"
94
};
95
96
void Mips_reg_access(const cs_insn *insn, cs_regs regs_read,
97
         uint8_t *regs_read_count, cs_regs regs_write,
98
         uint8_t *regs_write_count)
99
0
{
100
0
  uint8_t i;
101
0
  uint8_t read_count, write_count;
102
0
  cs_mips *mips = &(insn->detail->mips);
103
104
0
  read_count = insn->detail->regs_read_count;
105
0
  write_count = insn->detail->regs_write_count;
106
107
  // implicit registers
108
0
  memcpy(regs_read, insn->detail->regs_read,
109
0
         read_count * sizeof(insn->detail->regs_read[0]));
110
0
  memcpy(regs_write, insn->detail->regs_write,
111
0
         write_count * sizeof(insn->detail->regs_write[0]));
112
113
  // explicit registers
114
0
  for (i = 0; i < mips->op_count; i++) {
115
0
    cs_mips_op *op = &(mips->operands[i]);
116
0
    switch ((int)op->type) {
117
0
    case MIPS_OP_REG:
118
0
      if ((op->access & CS_AC_READ) &&
119
0
          !arr_exist(regs_read, read_count, op->reg)) {
120
0
        regs_read[read_count] = (uint16_t)op->reg;
121
0
        read_count++;
122
0
      }
123
0
      if ((op->access & CS_AC_WRITE) &&
124
0
          !arr_exist(regs_write, write_count, op->reg)) {
125
0
        regs_write[write_count] = (uint16_t)op->reg;
126
0
        write_count++;
127
0
      }
128
0
      break;
129
0
    case MIPS_OP_MEM:
130
      // registers appeared in memory references always being read
131
0
      if ((op->mem.base != MIPS_REG_INVALID) &&
132
0
          !arr_exist(regs_read, read_count, op->mem.base)) {
133
0
        regs_read[read_count] = (uint16_t)op->mem.base;
134
0
        read_count++;
135
0
      }
136
0
      if ((insn->detail->writeback) &&
137
0
          (op->mem.base != MIPS_REG_INVALID) &&
138
0
          !arr_exist(regs_write, write_count, op->mem.base)) {
139
0
        regs_write[write_count] =
140
0
          (uint16_t)op->mem.base;
141
0
        write_count++;
142
0
      }
143
0
    default:
144
0
      break;
145
0
    }
146
0
  }
147
148
0
  *regs_read_count = read_count;
149
0
  *regs_write_count = write_count;
150
0
}
151
152
void Mips_set_instr_map_data(MCInst *MI)
153
67.9k
{
154
  // Fixes for missing groups.
155
67.9k
  if (MCInst_getOpcode(MI) == Mips_JR) {
156
88
    unsigned Reg = MCInst_getOpVal(MI, 0);
157
88
    switch (Reg) {
158
0
    case MIPS_REG_RA:
159
0
    case MIPS_REG_RA_64:
160
0
      add_group(MI, MIPS_GRP_RET);
161
0
      break;
162
88
    }
163
88
  }
164
165
67.9k
  map_cs_id(MI, mips_insns, ARR_SIZE(mips_insns));
166
67.9k
  map_implicit_reads(MI, mips_insns);
167
67.9k
  map_implicit_writes(MI, mips_insns);
168
67.9k
  map_groups(MI, mips_insns);
169
67.9k
}
170
171
bool Mips_getInstruction(csh handle, const uint8_t *code, size_t code_len,
172
       MCInst *instr, uint16_t *size, uint64_t address,
173
       void *info)
174
69.8k
{
175
69.8k
  uint64_t size64;
176
69.8k
  Mips_init_cs_detail(instr);
177
69.8k
  instr->MRI = (MCRegisterInfo *)info;
178
69.8k
  map_set_fill_detail_ops(instr, true);
179
180
69.8k
  bool result = Mips_LLVM_getInstruction(instr, &size64, code, code_len,
181
69.8k
                 address,
182
69.8k
                 info) != MCDisassembler_Fail;
183
69.8k
  if (result) {
184
67.9k
    Mips_set_instr_map_data(instr);
185
67.9k
  }
186
69.8k
  *size = size64;
187
69.8k
  return result;
188
69.8k
}
189
190
void Mips_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info)
191
67.9k
{
192
67.9k
  MCRegisterInfo *MRI = (MCRegisterInfo *)info;
193
67.9k
  MI->MRI = MRI;
194
195
67.9k
  Mips_LLVM_printInst(MI, MI->address, O);
196
67.9k
}
197
198
static void Mips_setup_op(cs_mips_op *op)
199
698k
{
200
698k
  memset(op, 0, sizeof(cs_mips_op));
201
698k
  op->type = MIPS_OP_INVALID;
202
698k
}
203
204
void Mips_init_cs_detail(MCInst *MI)
205
69.8k
{
206
69.8k
  if (detail_is_set(MI)) {
207
69.8k
    unsigned int i;
208
209
69.8k
    memset(get_detail(MI), 0,
210
69.8k
           offsetof(cs_detail, mips) + sizeof(cs_mips));
211
212
767k
    for (i = 0; i < ARR_SIZE(Mips_get_detail(MI)->operands); i++)
213
698k
      Mips_setup_op(&Mips_get_detail(MI)->operands[i]);
214
69.8k
  }
215
69.8k
}
216
217
static const map_insn_ops insn_operands[] = {
218
#include "MipsGenCSMappingInsnOp.inc"
219
};
220
221
static void Mips_set_detail_op_mem_reg(MCInst *MI, unsigned OpNum, mips_reg Reg)
222
16.1k
{
223
16.1k
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_MEM;
224
16.1k
  Mips_get_detail_op(MI, 0)->mem.base = Reg;
225
16.1k
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
226
16.1k
}
227
228
static void Mips_set_detail_op_mem_disp(MCInst *MI, unsigned OpNum, int64_t Imm)
229
16.2k
{
230
16.2k
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_MEM;
231
16.2k
  Mips_get_detail_op(MI, 0)->mem.disp = Imm;
232
16.2k
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
233
16.2k
}
234
235
static void Mips_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm)
236
24.4k
{
237
24.4k
  if (!detail_is_set(MI))
238
0
    return;
239
240
24.4k
  if (doing_mem(MI)) {
241
16.2k
    Mips_set_detail_op_mem_disp(MI, OpNum, Imm);
242
16.2k
    return;
243
16.2k
  }
244
245
8.28k
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_IMM;
246
8.28k
  Mips_get_detail_op(MI, 0)->imm = Imm;
247
8.28k
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
248
8.28k
  Mips_inc_op_count(MI);
249
8.28k
}
250
251
static void Mips_set_detail_op_uimm(MCInst *MI, unsigned OpNum, uint64_t Imm)
252
27.6k
{
253
27.6k
  if (!detail_is_set(MI))
254
0
    return;
255
256
27.6k
  if (doing_mem(MI)) {
257
0
    Mips_set_detail_op_mem_disp(MI, OpNum, Imm);
258
0
    return;
259
0
  }
260
261
27.6k
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_IMM;
262
27.6k
  Mips_get_detail_op(MI, 0)->uimm = Imm;
263
27.6k
  Mips_get_detail_op(MI, 0)->is_unsigned = true;
264
27.6k
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
265
27.6k
  Mips_inc_op_count(MI);
266
27.6k
}
267
268
static void Mips_set_detail_op_reg(MCInst *MI, unsigned OpNum, mips_reg Reg,
269
           bool is_reglist)
270
117k
{
271
117k
  if (!detail_is_set(MI))
272
0
    return;
273
274
117k
  if (doing_mem(MI)) {
275
16.1k
    Mips_set_detail_op_mem_reg(MI, OpNum, Reg);
276
16.1k
    return;
277
16.1k
  }
278
279
100k
  CS_ASSERT((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_REG);
280
100k
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_REG;
281
100k
  Mips_get_detail_op(MI, 0)->reg = Reg;
282
100k
  Mips_get_detail_op(MI, 0)->is_reglist = is_reglist;
283
100k
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
284
100k
  Mips_inc_op_count(MI);
285
100k
}
286
287
static void Mips_set_detail_op_operand(MCInst *MI, unsigned OpNum)
288
140k
{
289
140k
  cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
290
140k
  int64_t value = MCInst_getOpVal(MI, OpNum);
291
140k
  if (op_type == CS_OP_IMM) {
292
24.4k
    Mips_set_detail_op_imm(MI, OpNum, value);
293
115k
  } else if (op_type == CS_OP_REG) {
294
115k
    Mips_set_detail_op_reg(MI, OpNum, value, false);
295
115k
  } else
296
460
    printf("Operand type %d not handled!\n", op_type);
297
140k
}
298
299
static void Mips_set_detail_op_branch(MCInst *MI, unsigned OpNum)
300
14.0k
{
301
14.0k
  cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
302
14.0k
  if (op_type == CS_OP_IMM) {
303
13.8k
    uint64_t Target = (uint64_t)MCInst_getOpVal(MI, OpNum);
304
13.8k
    Mips_set_detail_op_uimm(MI, OpNum, Target + MI->address);
305
13.8k
  } else if (op_type == CS_OP_REG) {
306
267
    Mips_set_detail_op_reg(MI, OpNum, MCInst_getOpVal(MI, OpNum),
307
267
               false);
308
267
  } else
309
0
    printf("Operand type %d not handled!\n", op_type);
310
14.0k
}
311
312
static void Mips_set_detail_op_unsigned(MCInst *MI, unsigned OpNum)
313
0
{
314
0
  Mips_set_detail_op_uimm(MI, OpNum, MCInst_getOpVal(MI, OpNum));
315
0
}
316
317
static void Mips_set_detail_op_unsigned_offset(MCInst *MI, unsigned OpNum,
318
                 unsigned Bits, uint64_t Offset)
319
13.7k
{
320
13.7k
  uint64_t Imm = MCInst_getOpVal(MI, OpNum);
321
13.7k
  Imm -= Offset;
322
13.7k
  Imm &= (((uint64_t)1) << Bits) - 1;
323
13.7k
  Imm += Offset;
324
13.7k
  Mips_set_detail_op_uimm(MI, OpNum, Imm);
325
13.7k
}
326
327
static void Mips_set_detail_op_mem_nanomips(MCInst *MI, unsigned OpNum)
328
0
{
329
0
  CS_ASSERT(doing_mem(MI))
330
331
0
  MCOperand *Op = MCInst_getOperand(MI, OpNum);
332
0
  Mips_get_detail_op(MI, 0)->type = MIPS_OP_MEM;
333
  // Base is a register, but nanoMips uses the Imm value as register.
334
0
  Mips_get_detail_op(MI, 0)->mem.base = MCOperand_getImm(Op);
335
0
  Mips_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
336
0
}
337
338
static void Mips_set_detail_op_reglist(MCInst *MI, unsigned OpNum,
339
               bool isNanoMips)
340
464
{
341
464
  if (isNanoMips) {
342
0
    for (unsigned i = OpNum; i < MCInst_getNumOperands(MI); i++) {
343
0
      Mips_set_detail_op_reg(MI, i, MCInst_getOpVal(MI, i),
344
0
                 true);
345
0
    }
346
0
    return;
347
0
  }
348
  // -2 because register List is always first operand of instruction
349
  // and it is always followed by memory operand (base + offset).
350
1.91k
  for (unsigned i = OpNum, e = MCInst_getNumOperands(MI) - 2; i != e;
351
1.45k
       ++i) {
352
1.45k
    Mips_set_detail_op_reg(MI, i, MCInst_getOpVal(MI, i), true);
353
1.45k
  }
354
464
}
355
356
static void Mips_set_detail_op_unsigned_address(MCInst *MI, unsigned OpNum)
357
0
{
358
0
  uint64_t Target = MI->address + (uint64_t)MCInst_getOpVal(MI, OpNum);
359
0
  Mips_set_detail_op_imm(MI, OpNum, Target);
360
0
}
361
362
void Mips_add_cs_detail(MCInst *MI, mips_op_group op_group, va_list args)
363
168k
{
364
168k
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
365
0
    return;
366
367
168k
  unsigned OpNum = va_arg(args, unsigned);
368
369
168k
  switch (op_group) {
370
0
  default:
371
0
    printf("Operand group %d not handled!\n", op_group);
372
0
    return;
373
0
  case Mips_OP_GROUP_MemOperand:
374
    // this is only used by nanoMips.
375
0
    return Mips_set_detail_op_mem_nanomips(MI, OpNum);
376
12.1k
  case Mips_OP_GROUP_BranchOperand:
377
    /* fall-thru */
378
14.0k
  case Mips_OP_GROUP_JumpOperand:
379
14.0k
    return Mips_set_detail_op_branch(MI, OpNum);
380
140k
  case Mips_OP_GROUP_Operand:
381
140k
    return Mips_set_detail_op_operand(MI, OpNum);
382
244
  case Mips_OP_GROUP_UImm_1_0:
383
244
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 1, 0);
384
218
  case Mips_OP_GROUP_UImm_2_0:
385
218
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 2, 0);
386
1.11k
  case Mips_OP_GROUP_UImm_3_0:
387
1.11k
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 3, 0);
388
0
  case Mips_OP_GROUP_UImm_32_0:
389
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 32, 0);
390
4.02k
  case Mips_OP_GROUP_UImm_16_0:
391
4.02k
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 16, 0);
392
377
  case Mips_OP_GROUP_UImm_8_0:
393
377
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 8, 0);
394
3.61k
  case Mips_OP_GROUP_UImm_5_0:
395
3.61k
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 5, 0);
396
278
  case Mips_OP_GROUP_UImm_6_0:
397
278
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 6, 0);
398
850
  case Mips_OP_GROUP_UImm_4_0:
399
850
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 4, 0);
400
0
  case Mips_OP_GROUP_UImm_7_0:
401
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 7, 0);
402
1.80k
  case Mips_OP_GROUP_UImm_10_0:
403
1.80k
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 10, 0);
404
0
  case Mips_OP_GROUP_UImm_6_1:
405
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 6, 1);
406
321
  case Mips_OP_GROUP_UImm_5_1:
407
321
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 5, 1);
408
0
  case Mips_OP_GROUP_UImm_5_33:
409
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 5, 33);
410
0
  case Mips_OP_GROUP_UImm_5_32:
411
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 5, 32);
412
0
  case Mips_OP_GROUP_UImm_6_2:
413
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 6, 2);
414
535
  case Mips_OP_GROUP_UImm_2_1:
415
535
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 2, 1);
416
83
  case Mips_OP_GROUP_UImm_0_0:
417
83
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 0, 0);
418
0
  case Mips_OP_GROUP_UImm_26_0:
419
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 26, 0);
420
0
  case Mips_OP_GROUP_UImm_12_0:
421
0
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 12, 0);
422
317
  case Mips_OP_GROUP_UImm_20_0:
423
317
    return Mips_set_detail_op_unsigned_offset(MI, OpNum, 20, 0);
424
464
  case Mips_OP_GROUP_RegisterList:
425
464
    return Mips_set_detail_op_reglist(MI, OpNum, false);
426
0
  case Mips_OP_GROUP_NanoMipsRegisterList:
427
0
    return Mips_set_detail_op_reglist(MI, OpNum, true);
428
0
  case Mips_OP_GROUP_PCRel:
429
    /* fall-thru */
430
0
  case Mips_OP_GROUP_Hi20PCRel:
431
0
    return Mips_set_detail_op_unsigned_address(MI, OpNum);
432
0
  case Mips_OP_GROUP_Hi20:
433
0
    return Mips_set_detail_op_unsigned(MI, OpNum);
434
168k
  }
435
168k
}
436
437
void Mips_set_mem_access(MCInst *MI, bool status)
438
32.8k
{
439
32.8k
  if (!detail_is_set(MI))
440
0
    return;
441
32.8k
  set_doing_mem(MI, status);
442
32.8k
  if (status) {
443
16.4k
    if (Mips_get_detail(MI)->op_count > 0 &&
444
16.4k
        Mips_get_detail_op(MI, -1)->type == MIPS_OP_MEM &&
445
16.4k
        Mips_get_detail_op(MI, -1)->mem.disp == 0) {
446
      // Previous memory operand not done yet. Select it.
447
0
      Mips_dec_op_count(MI);
448
0
      return;
449
0
    }
450
451
    // Init a new one.
452
16.4k
    Mips_get_detail_op(MI, 0)->type = MIPS_OP_MEM;
453
16.4k
    Mips_get_detail_op(MI, 0)->mem.base = MIPS_REG_INVALID;
454
16.4k
    Mips_get_detail_op(MI, 0)->mem.disp = 0;
455
456
16.4k
#ifndef CAPSTONE_DIET
457
16.4k
    uint8_t access =
458
16.4k
      map_get_op_access(MI, Mips_get_detail(MI)->op_count);
459
16.4k
    Mips_get_detail_op(MI, 0)->access = access;
460
16.4k
#endif
461
16.4k
  } else {
462
    // done, select the next operand slot
463
16.4k
    Mips_inc_op_count(MI);
464
16.4k
  }
465
32.8k
}
466
467
#endif