Coverage Report

Created: 2024-09-08 06:22

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