Coverage Report

Created: 2025-07-01 07:03

/src/capstonenext/utils.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine */
2
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */
3
4
#if defined(CAPSTONE_HAS_OSXKERNEL)
5
#include <Availability.h>
6
#include <libkern/libkern.h>
7
#else
8
#include <stdlib.h>
9
#endif
10
#include <string.h>
11
#include <ctype.h>
12
13
#include "utils.h"
14
15
// count number of positive members in a list.
16
// NOTE: list must be guaranteed to end in 0
17
unsigned int count_positive(const uint16_t *list)
18
1.29M
{
19
1.29M
  unsigned int c;
20
21
2.09M
  for (c = 0; list[c] > 0; c++);
22
23
1.29M
  return c;
24
1.29M
}
25
26
// count number of positive members in a list.
27
// NOTE: list must be guaranteed to end in 0
28
unsigned int count_positive8(const unsigned char *list)
29
647k
{
30
647k
  unsigned int c;
31
32
898k
  for (c = 0; list[c] > 0; c++);
33
34
647k
  return c;
35
647k
}
36
37
char *cs_strdup(const char *str)
38
0
{
39
0
  size_t len = strlen(str) + 1;
40
0
  void *new = cs_mem_malloc(len);
41
42
0
  if (new == NULL)
43
0
    return NULL;
44
45
0
  return (char *)memmove(new, str, len);
46
0
}
47
48
// we need this since Windows doesn't have snprintf()
49
int cs_snprintf(char *buffer, size_t size, const char *fmt, ...)
50
36.1k
{
51
36.1k
  int ret;
52
53
36.1k
  va_list ap;
54
36.1k
  va_start(ap, fmt);
55
36.1k
  ret = cs_vsnprintf(buffer, size, fmt, ap);
56
36.1k
  va_end(ap);
57
58
36.1k
  return ret;
59
36.1k
}
60
61
bool arr_exist8(unsigned char *arr, unsigned char max, unsigned int id)
62
0
{
63
0
  int i;
64
65
0
  for (i = 0; i < max; i++) {
66
0
    if (arr[i] == id)
67
0
      return true;
68
0
  }
69
70
0
  return false;
71
0
}
72
73
bool arr_exist(uint16_t *arr, unsigned char max, unsigned int id)
74
0
{
75
0
  int i;
76
77
0
  for (i = 0; i < max; i++) {
78
0
    if (arr[i] == id)
79
0
      return true;
80
0
  }
81
82
0
  return false;
83
0
}
84
85
/// @brief Checks if the @id is in the @table. @table has @table_size elements.
86
/// @param table The table with the values to compare to.
87
/// @param table_size The number elements in the table.
88
/// @param id The identifier to search for in the table.
89
/// @return True if @id is part of the @table, false otherwise.
90
bool arr_exist_int(int *table, size_t table_size, int id)
91
0
{
92
0
  int i;
93
0
  for (i = 0; i < table_size; i++) {
94
0
    if (table[i] == id)
95
0
      return true;
96
0
  }
97
98
0
  return false;
99
0
}
100
101
/// Reads 8 bytes in the endian order specified in MI->cs->mode.
102
uint64_t readBytes64(MCInst *MI, const uint8_t *Bytes)
103
0
{
104
0
  assert(MI && Bytes);
105
0
  uint64_t Insn;
106
0
  if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
107
0
    Insn = ((uint64_t)Bytes[7] << 0) | ((uint64_t)Bytes[6] << 8) |
108
0
           ((uint64_t)Bytes[5] << 16) | ((uint64_t)Bytes[4] << 24) |
109
0
           ((uint64_t)Bytes[3] << 32) | ((uint64_t)Bytes[2] << 40) |
110
0
           ((uint64_t)Bytes[1] << 48) | ((uint64_t)Bytes[0] << 56);
111
0
  else
112
0
    Insn = ((uint64_t)Bytes[7] << 56) | ((uint64_t)Bytes[6] << 48) |
113
0
           ((uint64_t)Bytes[5] << 40) | ((uint64_t)Bytes[4] << 32) |
114
0
           ((uint64_t)Bytes[3] << 24) | ((uint64_t)Bytes[2] << 16) |
115
0
           ((uint64_t)Bytes[1] << 8) | ((uint64_t)Bytes[0] << 0);
116
0
  return Insn;
117
0
}
118
119
/// Reads 6 bytes in the endian order specified in MI->cs->mode.
120
uint64_t readBytes48(MCInst *MI, const uint8_t *Bytes)
121
28.7k
{
122
28.7k
  assert(MI && Bytes);
123
28.7k
  uint64_t Insn;
124
28.7k
  if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
125
28.7k
    Insn = ((uint64_t)Bytes[5] << 0) | ((uint64_t)Bytes[4] << 8) |
126
28.7k
           ((uint64_t)Bytes[3] << 16) | ((uint64_t)Bytes[2] << 24) |
127
28.7k
           ((uint64_t)Bytes[1] << 32) | ((uint64_t)Bytes[0] << 40);
128
0
  else
129
0
    Insn = ((uint64_t)Bytes[5] << 40) | ((uint64_t)Bytes[4] << 32) |
130
0
           ((uint64_t)Bytes[3] << 24) | ((uint64_t)Bytes[2] << 16) |
131
0
           ((uint64_t)Bytes[1] << 8) | ((uint64_t)Bytes[0] << 0);
132
28.7k
  return Insn;
133
28.7k
}
134
135
/// Reads 4 bytes in the endian order specified in MI->cs->mode.
136
uint32_t readBytes32(MCInst *MI, const uint8_t *Bytes)
137
532k
{
138
532k
  assert(MI && Bytes);
139
532k
  uint32_t Insn;
140
532k
  if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
141
241k
    Insn = (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) |
142
241k
           ((uint32_t)Bytes[0] << 24);
143
290k
  else
144
290k
    Insn = ((uint32_t)Bytes[3] << 24) | (Bytes[2] << 16) |
145
290k
           (Bytes[1] << 8) | (Bytes[0] << 0);
146
532k
  return Insn;
147
532k
}
148
149
/// Reads 3 bytes in the endian order specified in MI->cs->mode.
150
uint32_t readBytes24(MCInst *MI, const uint8_t *Bytes)
151
47.4k
{
152
47.4k
  assert(MI && Bytes);
153
47.4k
  uint32_t Insn;
154
47.4k
  if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
155
0
    Insn = (Bytes[2]) | (Bytes[1] << 8) |
156
0
           ((uint32_t)Bytes[0] << 16);
157
47.4k
  else
158
47.4k
    Insn = (Bytes[2] << 16) | (Bytes[1] << 8) |
159
47.4k
           ((uint32_t)Bytes[0]);
160
47.4k
  return Insn;
161
47.4k
}
162
163
/// Reads 2 bytes in the endian order specified in MI->cs->mode.
164
uint16_t readBytes16(MCInst *MI, const uint8_t *Bytes)
165
964k
{
166
964k
  assert(MI && Bytes);
167
964k
  uint16_t Insn;
168
964k
  if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
169
34.0k
    Insn = (Bytes[0] << 8) | Bytes[1];
170
930k
  else
171
930k
    Insn = (Bytes[1] << 8) | Bytes[0];
172
173
964k
  return Insn;
174
964k
}
175
176
/// @brief Appends the string @p src to the string @p str. @p src is put to lower case.
177
/// @param str The string to append to.
178
/// @param str_size The length of @p str
179
/// @param src The string to append.
180
/// Does nothing if any of the given strings is NULL.
181
3.45k
void append_to_str_lower(char *str, size_t str_size, const char *src) {
182
3.45k
  if (!str || !src) {
183
0
    return;
184
0
  }
185
3.45k
  char *dest = strchr(str, '\0');
186
3.45k
  if (dest - str >= str_size) {
187
0
    assert("str_size does not match actual string length." && 0);
188
0
    return;
189
0
  }
190
191
3.45k
  int i = dest - str;
192
20.6k
  for (int j = 0; (i < str_size) && (j < strlen(src)); ++i, ++j) {
193
17.1k
    str[i] = tolower(src[j]);
194
17.1k
  }
195
3.45k
  str[i] = '\0';
196
3.45k
}
197
198
/// @brief Appends the string @p src to the string @p dest.
199
/// @p dest is can be a stack allocated buffer.
200
///
201
/// @param dest The string to append to.
202
/// @param dest_buf_size Size of buffer @p str.
203
/// @param src The string to append.
204
/// Does nothing if any of the given strings is NULL.
205
0
void str_append_no_realloc(char *dest, size_t dest_buf_size, const char *src) {
206
0
  if (!dest || !src) {
207
0
    return;
208
0
  }
209
0
  if (strlen(dest) + strlen(src) + 1 > dest_buf_size) {
210
0
    printf("str_size does not match actual string length.\n");
211
0
    return;
212
0
  }
213
0
  strncat(dest, src, dest_buf_size - strlen(dest));
214
0
}
215
216
217
/// Allocates memory of strlen(str_a) + strlen(str_b) + 1 chars
218
/// and copies all strings into it as str_a + str_b
219
/// str_a is passed to realloc and should not be used afterwards.
220
/// Returns the concatenated string.
221
/// Returns NULL in case of failure.
222
0
char *str_append(char *str_a, const char *str_b) {
223
0
  if (!str_a || !str_b) {
224
0
    return NULL;
225
0
  }
226
0
  size_t asize = strlen(str_a) + strlen(str_b) + 1;
227
0
  str_a = realloc(str_a, asize);
228
0
  strncat(str_a, str_b, asize - strlen(str_a));
229
0
  return str_a;
230
0
}
231
232
/// Returns the given byte sequence @bytes as a string of the
233
/// form: 0xXX,0xXX...
234
/// Returns NULL in case of failure.
235
char *byte_seq_to_str(uint8_t *bytes, size_t len)
236
0
{
237
0
  if (!bytes) {
238
0
    return NULL;
239
0
  }
240
0
  if (len == 0) {
241
0
    return NULL;
242
0
  }
243
0
  char single_byte[8] = { 0 };
244
0
  char *s = calloc(sizeof(char), 32);
245
0
  for (size_t i = 0; i < len; ++i) {
246
0
    cs_snprintf(single_byte, sizeof(single_byte), "0x%02" PRIx8 "%s",
247
0
          bytes[i], i == len - 1 ? "" : ", ");
248
0
    s = str_append(s, single_byte);
249
0
    if (!s) {
250
0
      return NULL;
251
0
    }
252
0
  }
253
0
  return s;
254
0
}