Coverage Report

Created: 2023-09-25 06:24

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