Coverage Report

Created: 2025-11-24 06:12

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
15
static bool testFeatureBits(const MCInst *MI, uint32_t Value)
16
140k
{
17
140k
  assert(MI && MI->csh);
18
140k
  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
8.46k
  case CS_ARCH_ARM:
24
8.46k
    return ARM_getFeatureBits(MI->csh->mode, Value);
25
0
#endif
26
0
#ifdef CAPSTONE_HAS_POWERPC
27
3.61k
  case CS_ARCH_PPC:
28
3.61k
    return PPC_getFeatureBits(MI->csh->mode, Value);
29
0
#endif
30
0
#ifdef CAPSTONE_HAS_MIPS
31
17.6k
  case CS_ARCH_MIPS:
32
17.6k
    return Mips_getFeatureBits(MI->csh->mode, Value);
33
0
#endif
34
0
#ifdef CAPSTONE_HAS_AARCH64
35
107k
  case CS_ARCH_AARCH64:
36
107k
    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
3.77k
  case CS_ARCH_SPARC:
44
3.77k
    return Sparc_getFeatureBits(MI->csh->mode, Value);
45
140k
#endif
46
140k
  }
47
140k
}
48
49
static bool matchAliasCondition(MCInst *MI, const MCRegisterInfo *MRI,
50
        unsigned *OpIdx, const AliasMatchingData *M,
51
        const AliasPatternCond *C,
52
        bool *OrPredicateResult)
53
1.31M
{
54
  // Feature tests are special, they don't consume operands.
55
1.31M
  if (C->Kind == AliasPatternCond_K_Feature)
56
16.6k
    return testFeatureBits(MI, C->Value);
57
1.29M
  if (C->Kind == AliasPatternCond_K_NegFeature)
58
14.3k
    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
1.28M
  if (C->Kind == AliasPatternCond_K_OrFeature) {
63
108k
    *OrPredicateResult |= testFeatureBits(MI, C->Value);
64
108k
    return true;
65
108k
  }
66
1.17M
  if (C->Kind == AliasPatternCond_K_OrNegFeature) {
67
1.23k
    *OrPredicateResult |= !(testFeatureBits(MI, C->Value));
68
1.23k
    return true;
69
1.23k
  }
70
1.17M
  if (C->Kind == AliasPatternCond_K_EndOrFeatures) {
71
46.2k
    bool Res = *OrPredicateResult;
72
46.2k
    *OrPredicateResult = false;
73
46.2k
    return Res;
74
46.2k
  }
75
76
  // Get and consume an operand.
77
1.12M
  MCOperand *Opnd = MCInst_getOperand(MI, *OpIdx);
78
1.12M
  ++(*OpIdx);
79
80
  // Check the specific condition for the operand.
81
1.12M
  switch (C->Kind) {
82
0
  default:
83
0
    assert(0 && "invalid kind");
84
360k
  case AliasPatternCond_K_Imm:
85
    // Operand must be a specific immediate.
86
360k
    return MCOperand_isImm(Opnd) &&
87
360k
           MCOperand_getImm(Opnd) == (int32_t)C->Value;
88
79.9k
  case AliasPatternCond_K_Reg:
89
    // Operand must be a specific register.
90
79.9k
    return MCOperand_isReg(Opnd) &&
91
79.9k
           MCOperand_getReg(Opnd) == C->Value;
92
4.95k
  case AliasPatternCond_K_TiedReg:
93
    // Operand must match the register of another operand.
94
4.95k
    return MCOperand_isReg(Opnd) &&
95
4.95k
           MCOperand_getReg(Opnd) ==
96
4.95k
             MCOperand_getReg(
97
4.95k
               MCInst_getOperand(MI, C->Value));
98
488k
  case AliasPatternCond_K_RegClass:
99
    // Operand must be a register in this class. Value is a register class
100
    // id.
101
488k
    return MCOperand_isReg(Opnd) &&
102
488k
           MCRegisterClass_contains(
103
488k
             MCRegisterInfo_getRegClass(MRI, C->Value),
104
488k
             MCOperand_getReg(Opnd));
105
33.8k
  case AliasPatternCond_K_Custom:
106
    // Operand must match some custom criteria.
107
33.8k
    assert(M->ValidateMCOperand &&
108
33.8k
           "A custom validator should be set but isn't.");
109
33.8k
    return M->ValidateMCOperand(Opnd, C->Value);
110
162k
  case AliasPatternCond_K_Ignore:
111
    // Operand can be anything.
112
162k
    return true;
113
0
  case AliasPatternCond_K_Feature:
114
0
  case AliasPatternCond_K_NegFeature:
115
0
  case AliasPatternCond_K_OrFeature:
116
0
  case AliasPatternCond_K_OrNegFeature:
117
0
  case AliasPatternCond_K_EndOrFeatures:
118
0
    assert(0 && "handled earlier");
119
1.12M
  }
120
0
  return false;
121
1.12M
}
122
123
/// Check if PatternsForOpcode is all zero.
124
static inline bool validOpToPatter(const PatternsForOpcode *P)
125
254M
{
126
254M
  return !(P->Opcode == 0 && P->PatternStart == 0 && P->NumPatterns == 0);
127
254M
}
128
129
const char *matchAliasPatterns(MCInst *MI, const AliasMatchingData *M)
130
1.70M
{
131
  // TODO Rewrite to C
132
133
  // auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),
134
  //                       [](const PatternsForOpcode &L, unsigned Opcode) {
135
  //                         return L.Opcode < Opcode;
136
  //                       });
137
  // if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())
138
  //   return nullptr;
139
140
  // Binary search by opcode. Return false if there are no aliases for this
141
  // opcode.
142
1.70M
  unsigned MIOpcode = MI->Opcode;
143
1.70M
  size_t i = 0;
144
1.70M
  uint32_t PatternOpcode = M->OpToPatterns[i].Opcode;
145
255M
  while (PatternOpcode < MIOpcode && validOpToPatter(&M->OpToPatterns[i]))
146
254M
    PatternOpcode = M->OpToPatterns[++i].Opcode;
147
1.70M
  if (PatternOpcode != MI->Opcode ||
148
196k
      !validOpToPatter(&M->OpToPatterns[i]))
149
1.51M
    return NULL;
150
151
  // // Try all patterns for this opcode.
152
196k
  uint32_t AsmStrOffset = ~0U;
153
196k
  const AliasPattern *Patterns =
154
196k
    M->Patterns + M->OpToPatterns[i].PatternStart;
155
196k
  for (const AliasPattern *P = Patterns;
156
609k
       P != Patterns + M->OpToPatterns[i].NumPatterns; ++P) {
157
    // Check operand count first.
158
487k
    if (MCInst_getNumOperands(MI) != P->NumOperands)
159
0
      return NULL;
160
161
    // Test all conditions for this pattern.
162
487k
    const AliasPatternCond *Conds =
163
487k
      M->PatternConds + P->AliasCondStart;
164
487k
    unsigned OpIdx = 0;
165
487k
    bool OrPredicateResult = false;
166
487k
    bool allMatch = true;
167
487k
    for (const AliasPatternCond *C = Conds;
168
1.39M
         C != Conds + P->NumConds; ++C) {
169
1.31M
      if (!matchAliasCondition(MI, MI->MRI, &OpIdx, M, C,
170
1.31M
             &OrPredicateResult)) {
171
412k
        allMatch = false;
172
412k
        break;
173
412k
      }
174
1.31M
    }
175
487k
    if (allMatch) {
176
74.8k
      AsmStrOffset = P->AsmStrOffset;
177
74.8k
      break;
178
74.8k
    }
179
487k
  }
180
  // If no alias matched, don't print an alias.
181
196k
  if (AsmStrOffset == ~0U)
182
121k
    return NULL;
183
184
  // Go to offset AsmStrOffset and use the null terminated string there. The
185
  // offset should point to the beginning of an alias string, so it should
186
  // either be zero or be preceded by a null byte.
187
74.8k
  return M->AsmStrings + AsmStrOffset;
188
196k
}
189
190
// TODO Add functionality to toggle the flag.
191
bool getUseMarkup(void)
192
9.24M
{
193
9.24M
  return false;
194
9.24M
}
195
196
/// Utility functions to make adding mark ups simpler.
197
const char *markup(const char *s)
198
9.10M
{
199
9.10M
  static const char *no_markup = "";
200
9.10M
  if (getUseMarkup())
201
0
    return s;
202
9.10M
  else
203
9.10M
    return no_markup;
204
9.10M
}
205
206
// binary search for encoding in IndexType array
207
// return -1 if not found, or index if found
208
unsigned int binsearch_IndexTypeEncoding(const struct IndexType *index,
209
           size_t size, uint16_t encoding)
210
156k
{
211
  // binary searching since the index is sorted in encoding order
212
156k
  size_t left, right, m;
213
214
156k
  right = size - 1;
215
216
156k
  if (encoding < index[0].encoding || encoding > index[right].encoding)
217
    // not found
218
28.3k
    return -1;
219
220
128k
  left = 0;
221
222
615k
  while (left <= right) {
223
575k
    m = (left + right) / 2;
224
575k
    if (encoding == index[m].encoding) {
225
      // LLVM actually uses lower_bound for the index table search
226
      // Here we need to check if a previous entry is of the same encoding
227
      // and return the first one.
228
87.9k
      while (m > 0 && encoding == index[m - 1].encoding)
229
0
        --m;
230
87.9k
      return m;
231
87.9k
    }
232
233
487k
    if (encoding < index[m].encoding)
234
188k
      right = m - 1;
235
298k
    else
236
298k
      left = m + 1;
237
487k
  }
238
239
  // not found
240
40.4k
  return -1;
241
128k
}
242
243
// binary search for encoding in IndexTypeStr array
244
// return -1 if not found, or index if found
245
unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index,
246
              size_t size, const char *name)
247
3.63k
{
248
  // binary searching since the index is sorted in encoding order
249
3.63k
  size_t left, right, m;
250
251
3.63k
  right = size - 1;
252
253
3.63k
  int str_left_cmp = strcmp(name, index[0].name);
254
3.63k
  int str_right_cmp = strcmp(name, index[right].name);
255
3.63k
  if (str_left_cmp < 0 || str_right_cmp > 0)
256
    // not found
257
0
    return -1;
258
259
3.63k
  left = 0;
260
261
35.8k
  while (left <= right) {
262
35.7k
    m = (left + right) / 2;
263
35.7k
    if (strcmp(name, index[m].name) == 0) {
264
      // LLVM actually uses lower_bound for the index table search
265
      // Here we need to check if a previous entry is of the same encoding
266
      // and return the first one.
267
3.54k
      while (m > 0 && (strcmp(name, index[m - 1].name) == 0))
268
0
        --m;
269
3.54k
      return m;
270
3.54k
    }
271
272
32.2k
    if (strcmp(name, index[m].name) < 0)
273
13.4k
      right = m - 1;
274
18.7k
    else
275
18.7k
      left = m + 1;
276
32.2k
  }
277
278
  // not found
279
88
  return -1;
280
3.63k
}