Coverage Report

Created: 2025-07-01 07:03

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