Coverage Report

Created: 2026-07-16 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonenext/MCInstPrinter.c
Line
Count
Source
1
/* Capstone Disassembly Engine */
2
/* By Rot127 <unisono@quyllur.org>, 2023 */
3
4
#include "MCInstPrinter.h"
5
#include "cs_priv.h"
6
#include <capstone/platform.h>
7
8
extern bool ARM_getFeatureBits(unsigned int mode, unsigned int feature);
9
extern bool PPC_getFeatureBits(unsigned int mode, unsigned int feature);
10
extern bool Mips_getFeatureBits(unsigned int mode, unsigned int feature);
11
extern bool AArch64_getFeatureBits(unsigned int mode, unsigned int feature);
12
extern bool TriCore_getFeatureBits(unsigned int mode, unsigned int feature);
13
extern bool Sparc_getFeatureBits(unsigned int mode, unsigned int feature);
14
extern bool RISCV_getFeatureBits(unsigned int mode, unsigned int feature);
15
16
static bool testFeatureBits(const MCInst *MI, uint32_t Value)
17
96.9k
{
18
96.9k
  assert(MI && MI->csh);
19
96.9k
  switch (MI->csh->arch) {
20
0
  default:
21
0
    assert(0 && "Not implemented for current arch.");
22
0
    return false;
23
0
#ifdef CAPSTONE_HAS_ARM
24
6.60k
  case CS_ARCH_ARM:
25
6.60k
    return ARM_getFeatureBits(MI->csh->mode, Value);
26
0
#endif
27
0
#ifdef CAPSTONE_HAS_POWERPC
28
589
  case CS_ARCH_PPC:
29
589
    return PPC_getFeatureBits(MI->csh->mode, Value);
30
0
#endif
31
0
#ifdef CAPSTONE_HAS_MIPS
32
14.4k
  case CS_ARCH_MIPS:
33
14.4k
    return Mips_getFeatureBits(MI->csh->mode, Value);
34
0
#endif
35
0
#ifdef CAPSTONE_HAS_AARCH64
36
72.2k
  case CS_ARCH_AARCH64:
37
72.2k
    return AArch64_getFeatureBits(MI->csh->mode, Value);
38
0
#endif
39
0
#ifdef CAPSTONE_HAS_TRICORE
40
0
  case CS_ARCH_TRICORE:
41
0
    return TriCore_getFeatureBits(MI->csh->mode, Value);
42
0
#endif
43
0
#ifdef CAPSTONE_HAS_SPARC
44
2.57k
  case CS_ARCH_SPARC:
45
2.57k
    return Sparc_getFeatureBits(MI->csh->mode, Value);
46
0
#endif
47
0
#ifdef CAPSTONE_HAS_RISCV
48
495
  case CS_ARCH_RISCV:
49
495
    return RISCV_getFeatureBits(MI->csh->mode, Value);
50
96.9k
#endif
51
96.9k
  }
52
96.9k
}
53
54
static bool matchAliasCondition(MCInst *MI, const MCRegisterInfo *MRI,
55
        unsigned *OpIdx, const AliasMatchingData *M,
56
        const AliasPatternCond *C,
57
        bool *OrPredicateResult)
58
1.06M
{
59
  // Feature tests are special, they don't consume operands.
60
1.06M
  if (C->Kind == AliasPatternCond_K_Feature)
61
14.6k
    return testFeatureBits(MI, C->Value);
62
1.05M
  if (C->Kind == AliasPatternCond_K_NegFeature)
63
9.63k
    return !testFeatureBits(MI, C->Value);
64
  // For feature tests where just one feature is required in a list, set the
65
  // predicate result bit to whether the expression will return true, and only
66
  // return the real result at the end of list marker.
67
1.04M
  if (C->Kind == AliasPatternCond_K_OrFeature) {
68
72.5k
    *OrPredicateResult |= testFeatureBits(MI, C->Value);
69
72.5k
    return true;
70
72.5k
  }
71
972k
  if (C->Kind == AliasPatternCond_K_OrNegFeature) {
72
99
    *OrPredicateResult |= !(testFeatureBits(MI, C->Value));
73
99
    return true;
74
99
  }
75
972k
  if (C->Kind == AliasPatternCond_K_EndOrFeatures) {
76
30.3k
    bool Res = *OrPredicateResult;
77
30.3k
    *OrPredicateResult = false;
78
30.3k
    return Res;
79
30.3k
  }
80
81
  // Get and consume an operand.
82
942k
  MCOperand *Opnd = MCInst_getOperand(MI, *OpIdx);
83
942k
  ++(*OpIdx);
84
85
  // Check the specific condition for the operand.
86
942k
  switch (C->Kind) {
87
0
  default:
88
0
    assert(0 && "invalid kind");
89
273k
  case AliasPatternCond_K_Imm:
90
    // Operand must be a specific immediate.
91
273k
    return MCOperand_isImm(Opnd) &&
92
273k
           MCOperand_getImm(Opnd) == (int32_t)C->Value;
93
128k
  case AliasPatternCond_K_Reg:
94
    // Operand must be a specific register.
95
128k
    return MCOperand_isReg(Opnd) &&
96
128k
           MCOperand_getReg(Opnd) == C->Value;
97
3.18k
  case AliasPatternCond_K_TiedReg:
98
    // Operand must match the register of another operand.
99
3.18k
    return MCOperand_isReg(Opnd) &&
100
3.18k
           MCOperand_getReg(Opnd) ==
101
3.18k
             MCOperand_getReg(
102
3.18k
               MCInst_getOperand(MI, C->Value));
103
396k
  case AliasPatternCond_K_RegClass:
104
    // Operand must be a register in this class. Value is a register class
105
    // id.
106
396k
    return MCOperand_isReg(Opnd) &&
107
396k
           MCRegisterClass_contains(
108
396k
             MCRegisterInfo_getRegClass(MRI, C->Value),
109
396k
             MCOperand_getReg(Opnd));
110
36.6k
  case AliasPatternCond_K_Custom:
111
    // Operand must match some custom criteria.
112
36.6k
    assert(M->ValidateMCOperand &&
113
36.6k
           "A custom validator should be set but isn't.");
114
36.6k
    return M->ValidateMCOperand(Opnd, C->Value);
115
104k
  case AliasPatternCond_K_Ignore:
116
    // Operand can be anything.
117
104k
    return true;
118
0
  case AliasPatternCond_K_Feature:
119
0
  case AliasPatternCond_K_NegFeature:
120
0
  case AliasPatternCond_K_OrFeature:
121
0
  case AliasPatternCond_K_OrNegFeature:
122
0
  case AliasPatternCond_K_EndOrFeatures:
123
0
    assert(0 && "handled earlier");
124
942k
  }
125
0
  return false;
126
942k
}
127
128
/// Check if PatternsForOpcode is all zero.
129
static inline bool validOpToPatter(const PatternsForOpcode *P)
130
211M
{
131
211M
  return !(P->Opcode == 0 && P->PatternStart == 0 && P->NumPatterns == 0);
132
211M
}
133
134
const char *matchAliasPatterns(MCInst *MI, const AliasMatchingData *M)
135
1.98M
{
136
  // TODO Rewrite to C
137
138
  // auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),
139
  //                       [](const PatternsForOpcode &L, unsigned Opcode) {
140
  //                         return L.Opcode < Opcode;
141
  //                       });
142
  // if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())
143
  //   return nullptr;
144
145
  // Binary search by opcode. Return false if there are no aliases for this
146
  // opcode.
147
1.98M
  unsigned MIOpcode = MI->Opcode;
148
1.98M
  size_t i = 0;
149
1.98M
  uint32_t PatternOpcode = M->OpToPatterns[i].Opcode;
150
212M
  while (PatternOpcode < MIOpcode && validOpToPatter(&M->OpToPatterns[i]))
151
210M
    PatternOpcode = M->OpToPatterns[++i].Opcode;
152
1.98M
  if (PatternOpcode != MI->Opcode ||
153
191k
      !validOpToPatter(&M->OpToPatterns[i]))
154
1.79M
    return NULL;
155
156
  // // Try all patterns for this opcode.
157
191k
  uint32_t AsmStrOffset = ~0U;
158
191k
  const AliasPattern *Patterns =
159
191k
    M->Patterns + M->OpToPatterns[i].PatternStart;
160
191k
  for (const AliasPattern *P = Patterns;
161
548k
       P != Patterns + M->OpToPatterns[i].NumPatterns; ++P) {
162
    // Check operand count first.
163
428k
    if (MCInst_getNumOperands(MI) != P->NumOperands)
164
0
      return NULL;
165
166
    // Test all conditions for this pattern.
167
428k
    const AliasPatternCond *Conds =
168
428k
      M->PatternConds + P->AliasCondStart;
169
428k
    unsigned OpIdx = 0;
170
428k
    bool OrPredicateResult = false;
171
428k
    bool allMatch = true;
172
428k
    for (const AliasPatternCond *C = Conds;
173
1.14M
         C != Conds + P->NumConds; ++C) {
174
1.06M
      if (!matchAliasCondition(MI, MI->MRI, &OpIdx, M, C,
175
1.06M
             &OrPredicateResult)) {
176
356k
        allMatch = false;
177
356k
        break;
178
356k
      }
179
1.06M
    }
180
428k
    if (allMatch) {
181
71.7k
      AsmStrOffset = P->AsmStrOffset;
182
71.7k
      break;
183
71.7k
    }
184
428k
  }
185
  // If no alias matched, don't print an alias.
186
191k
  if (AsmStrOffset == ~0U)
187
119k
    return NULL;
188
189
  // Go to offset AsmStrOffset and use the null terminated string there. The
190
  // offset should point to the beginning of an alias string, so it should
191
  // either be zero or be preceded by a null byte.
192
71.7k
  return M->AsmStrings + AsmStrOffset;
193
191k
}
194
195
// TODO Add functionality to toggle the flag.
196
bool getUseMarkup(void)
197
9.92M
{
198
9.92M
  return false;
199
9.92M
}
200
201
/// Utility functions to make adding mark ups simpler.
202
const char *markup(const char *s)
203
9.75M
{
204
9.75M
  static const char *no_markup = "";
205
9.75M
  if (getUseMarkup())
206
0
    return s;
207
9.75M
  else
208
9.75M
    return no_markup;
209
9.75M
}
210
211
// binary search for encoding in IndexType array
212
// return -1 if not found, or index if found
213
unsigned int binsearch_IndexTypeEncoding(const struct IndexType *index,
214
           size_t size, uint16_t encoding)
215
96.5k
{
216
  // binary searching since the index is sorted in encoding order
217
96.5k
  size_t left, right, m;
218
219
96.5k
  right = size - 1;
220
221
96.5k
  if (encoding < index[0].encoding || encoding > index[right].encoding)
222
    // not found
223
12.6k
    return -1;
224
225
83.8k
  left = 0;
226
227
439k
  while (left <= right) {
228
407k
    m = (left + right) / 2;
229
407k
    if (encoding == index[m].encoding) {
230
      // LLVM actually uses lower_bound for the index table search
231
      // Here we need to check if a previous entry is of the same encoding
232
      // and return the first one.
233
51.3k
      while (m > 0 && encoding == index[m - 1].encoding)
234
0
        --m;
235
51.3k
      return m;
236
51.3k
    }
237
238
355k
    if (encoding < index[m].encoding)
239
129k
      right = m - 1;
240
226k
    else
241
226k
      left = m + 1;
242
355k
  }
243
244
  // not found
245
32.5k
  return -1;
246
83.8k
}
247
248
// binary search for encoding in IndexTypeStr array
249
// return -1 if not found, or index if found
250
unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index,
251
              size_t size, const char *name)
252
1.35k
{
253
  // binary searching since the index is sorted in encoding order
254
1.35k
  size_t left, right, m;
255
256
1.35k
  right = size - 1;
257
258
1.35k
  int str_left_cmp = strcmp(name, index[0].name);
259
1.35k
  int str_right_cmp = strcmp(name, index[right].name);
260
1.35k
  if (str_left_cmp < 0 || str_right_cmp > 0)
261
    // not found
262
0
    return -1;
263
264
1.35k
  left = 0;
265
266
14.2k
  while (left <= right) {
267
14.1k
    m = (left + right) / 2;
268
14.1k
    if (strcmp(name, index[m].name) == 0) {
269
      // LLVM actually uses lower_bound for the index table search
270
      // Here we need to check if a previous entry is of the same encoding
271
      // and return the first one.
272
1.30k
      while (m > 0 && (strcmp(name, index[m - 1].name) == 0))
273
0
        --m;
274
1.30k
      return m;
275
1.30k
    }
276
277
12.8k
    if (strcmp(name, index[m].name) < 0)
278
5.75k
      right = m - 1;
279
7.13k
    else
280
7.13k
      left = m + 1;
281
12.8k
  }
282
283
  // not found
284
50
  return -1;
285
1.35k
}