1 /***************************************************************************************************
2
3 Zyan Disassembler Library (Zydis)
4
5 Original Author : Florian Bernd, Joel Hoener
6
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24
25 ***************************************************************************************************/
26
27 #include <Zydis/Internal/String.h>
28
29 /* ============================================================================================== */
30 /* Constants */
31 /* ============================================================================================== */
32
33 /* ---------------------------------------------------------------------------------------------- */
34 /* Defines */
35 /* ---------------------------------------------------------------------------------------------- */
36
37 #define ZYDIS_MAXCHARS_DEC_32 10
38 #define ZYDIS_MAXCHARS_DEC_64 20
39 #define ZYDIS_MAXCHARS_HEX_32 8
40 #define ZYDIS_MAXCHARS_HEX_64 16
41
42 /* ---------------------------------------------------------------------------------------------- */
43 /* Lookup Tables */
44 /* ---------------------------------------------------------------------------------------------- */
45
46 static const char* const DECIMAL_LOOKUP =
47 "00010203040506070809"
48 "10111213141516171819"
49 "20212223242526272829"
50 "30313233343536373839"
51 "40414243444546474849"
52 "50515253545556575859"
53 "60616263646566676869"
54 "70717273747576777879"
55 "80818283848586878889"
56 "90919293949596979899";
57
58 /* ---------------------------------------------------------------------------------------------- */
59
60 /* ============================================================================================== */
61 /* Internal Functions */
62 /* ============================================================================================== */
63
64 /* ---------------------------------------------------------------------------------------------- */
65 /* Decimal */
66 /* ---------------------------------------------------------------------------------------------- */
67
68 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
ZydisStringAppendDecU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length)69 static ZyanStatus ZydisStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length)
70 {
71 ZYAN_ASSERT(string);
72 ZYAN_ASSERT(!string->vector.allocator);
73
74 char buffer[ZYDIS_MAXCHARS_DEC_32];
75 char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_32];
76 char *buffer_write_pointer = buffer_end;
77 while (value >= 100)
78 {
79 const ZyanU32 value_old = value;
80 buffer_write_pointer -= 2;
81 value /= 100;
82 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
83 }
84 buffer_write_pointer -= 2;
85 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
86
87 const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
88 const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
89 const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
90 const ZyanUSize length_target = string->vector.size;
91
92 if (string->vector.size + length_total > string->vector.capacity)
93 {
94 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
95 }
96
97 ZyanUSize offset_write = 0;
98 if (padding_length > length_number)
99 {
100 offset_write = padding_length - length_number;
101 ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
102 }
103
104 ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
105 buffer_write_pointer + offset_odd, length_number);
106 string->vector.size = length_target + length_total;
107 ZYDIS_STRING_NULLTERMINATE(string);
108
109 return ZYAN_STATUS_SUCCESS;
110 }
111 #endif
112
ZydisStringAppendDecU64(ZyanString * string,ZyanU64 value,ZyanU8 padding_length)113 static ZyanStatus ZydisStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
114 {
115 ZYAN_ASSERT(string);
116 ZYAN_ASSERT(!string->vector.allocator);
117
118 char buffer[ZYDIS_MAXCHARS_DEC_64];
119 char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_64];
120 char *buffer_write_pointer = buffer_end;
121 while (value >= 100)
122 {
123 const ZyanU64 value_old = value;
124 buffer_write_pointer -= 2;
125 ZYAN_DIV64(value, 100);
126 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
127 }
128 buffer_write_pointer -= 2;
129 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
130
131 const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
132 const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
133 const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
134 const ZyanUSize length_target = string->vector.size;
135
136 if (string->vector.size + length_total > string->vector.capacity)
137 {
138 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
139 }
140
141 ZyanUSize offset_write = 0;
142 if (padding_length > length_number)
143 {
144 offset_write = padding_length - length_number;
145 ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
146 }
147
148 ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
149 buffer_write_pointer + offset_odd, length_number);
150 string->vector.size = length_target + length_total;
151 ZYDIS_STRING_NULLTERMINATE(string);
152
153 return ZYAN_STATUS_SUCCESS;
154 }
155
156 /* ---------------------------------------------------------------------------------------------- */
157 /* Hexadecimal */
158 /* ---------------------------------------------------------------------------------------------- */
159
160 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
ZydisStringAppendHexU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length,ZyanBool force_leading_number,ZyanBool uppercase)161 static ZyanStatus ZydisStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
162 ZyanBool force_leading_number, ZyanBool uppercase)
163 {
164 ZYAN_ASSERT(string);
165 ZYAN_ASSERT(!string->vector.allocator);
166
167 const ZyanUSize len = string->vector.size;
168 const ZyanUSize remaining = string->vector.capacity - string->vector.size;
169
170 if (remaining < (ZyanUSize)padding_length)
171 {
172 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
173 }
174
175 if (!value)
176 {
177 const ZyanU8 n = (padding_length ? padding_length : 1);
178
179 if (remaining < (ZyanUSize)n)
180 {
181 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
182 }
183
184 ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
185 string->vector.size = len + n;
186 ZYDIS_STRING_NULLTERMINATE(string);
187
188 return ZYAN_STATUS_SUCCESS;
189 }
190
191 ZyanU8 n = 0;
192 char* buffer = ZYAN_NULL;
193 for (ZyanI8 i = ZYDIS_MAXCHARS_HEX_32 - 1; i >= 0; --i)
194 {
195 const ZyanU8 v = (value >> i * 4) & 0x0F;
196 if (!n)
197 {
198 if (!v)
199 {
200 continue;
201 }
202 const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0;
203 if (remaining <= (ZyanUSize)i + zero)
204 {
205 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
206 }
207 buffer = (char*)string->vector.data + len - 1;
208 if (zero)
209 {
210 buffer[n++] = '0';
211 }
212 if (padding_length > i)
213 {
214 n = padding_length - i - 1;
215 ZYAN_MEMSET(buffer, '0', n);
216 }
217 }
218 ZYAN_ASSERT(buffer);
219 if (uppercase)
220 {
221 buffer[n++] = "0123456789ABCDEF"[v];
222 } else
223 {
224 buffer[n++] = "0123456789abcdef"[v];
225 }
226 }
227 string->vector.size = len + n;
228 ZYDIS_STRING_NULLTERMINATE(string);
229
230 return ZYAN_STATUS_SUCCESS;
231 }
232 #endif
233
ZydisStringAppendHexU64(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool force_leading_number,ZyanBool uppercase)234 static ZyanStatus ZydisStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
235 ZyanBool force_leading_number, ZyanBool uppercase)
236 {
237 ZYAN_ASSERT(string);
238 ZYAN_ASSERT(!string->vector.allocator);
239
240 const ZyanUSize len = string->vector.size;
241 const ZyanUSize remaining = string->vector.capacity - string->vector.size;
242
243 if (remaining < (ZyanUSize)padding_length)
244 {
245 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
246 }
247
248 if (!value)
249 {
250 const ZyanU8 n = (padding_length ? padding_length : 1);
251
252 if (remaining < (ZyanUSize)n)
253 {
254 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
255 }
256
257 ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
258 string->vector.size = len + n;
259 ZYDIS_STRING_NULLTERMINATE(string);
260
261 return ZYAN_STATUS_SUCCESS;
262 }
263
264 ZyanU8 n = 0;
265 char* buffer = ZYAN_NULL;
266 for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
267 ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32) - 1; i >= 0; --i)
268 {
269 const ZyanU8 v = (value >> i * 4) & 0x0F;
270 if (!n)
271 {
272 if (!v)
273 {
274 continue;
275 }
276 const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0;
277 if (remaining <= (ZyanUSize)i + zero)
278 {
279 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
280 }
281 buffer = (char*)string->vector.data + len - 1;
282 if (zero)
283 {
284 buffer[n++] = '0';
285 }
286 if (padding_length > i)
287 {
288 n = padding_length - i - 1;
289 ZYAN_MEMSET(buffer, '0', n);
290 }
291 }
292 ZYAN_ASSERT(buffer);
293 if (uppercase)
294 {
295 buffer[n++] = "0123456789ABCDEF"[v];
296 } else
297 {
298 buffer[n++] = "0123456789abcdef"[v];
299 }
300 }
301 string->vector.size = len + n;
302 ZYDIS_STRING_NULLTERMINATE(string);
303
304 return ZYAN_STATUS_SUCCESS;
305 }
306
307 /* ---------------------------------------------------------------------------------------------- */
308
309 /* ============================================================================================== */
310 /* Public Functions */
311 /* ============================================================================================== */
312
313 /* ---------------------------------------------------------------------------------------------- */
314 /* Formatting */
315 /* ---------------------------------------------------------------------------------------------- */
316
ZydisStringAppendDecU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,const ZyanStringView * prefix,const ZyanStringView * suffix)317 ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
318 const ZyanStringView* prefix, const ZyanStringView* suffix)
319 {
320 if (prefix)
321 {
322 ZYAN_CHECK(ZydisStringAppend(string, prefix));
323 }
324
325 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
326 ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
327 #else
328 if (value & 0xFFFFFFFF00000000)
329 {
330 ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
331 }
332 ZYAN_CHECK(ZydisStringAppendDecU32(string, (ZyanU32)value, padding_length));
333 #endif
334
335 if (suffix)
336 {
337 return ZydisStringAppend(string, suffix);
338 }
339 return ZYAN_STATUS_SUCCESS;
340 }
341
ZydisStringAppendHexU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool force_leading_number,ZyanBool uppercase,const ZyanStringView * prefix,const ZyanStringView * suffix)342 ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
343 ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix,
344 const ZyanStringView* suffix)
345 {
346 if (prefix)
347 {
348 ZYAN_CHECK(ZydisStringAppend(string, prefix));
349 }
350
351 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
352 ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number,
353 uppercase));
354 #else
355 if (value & 0xFFFFFFFF00000000)
356 {
357 ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number,
358 uppercase));
359 }
360 else
361 {
362 ZYAN_CHECK(ZydisStringAppendHexU32(string, (ZyanU32)value, padding_length,
363 force_leading_number, uppercase));
364 }
365 #endif
366
367 if (suffix)
368 {
369 return ZydisStringAppend(string, suffix);
370 }
371 return ZYAN_STATUS_SUCCESS;
372 }
373
374 /* ---------------------------------------------------------------------------------------------- */
375
376 /* ============================================================================================== */
377