Coverage Report

Created: 2023-12-08 06:05

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