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