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/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)
ZydisStringAppendDecU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length)69 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 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         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)
ZydisStringAppendHexU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length,ZyanBool uppercase)161 ZyanStatus ZydisStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
162     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             if (remaining <= (ZyanU8)i)
203             {
204                 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
205             }
206             buffer = (char*)string->vector.data + len - 1;
207             if (padding_length > i)
208             {
209                 n = padding_length - i - 1;
210                 ZYAN_MEMSET(buffer, '0', n);
211             }
212         }
213         ZYAN_ASSERT(buffer);
214         if (uppercase)
215         {
216             buffer[n++] = "0123456789ABCDEF"[v];
217         } else
218         {
219             buffer[n++] = "0123456789abcdef"[v];
220         }
221     }
222     string->vector.size = len + n;
223     ZYDIS_STRING_NULLTERMINATE(string);
224 
225     return ZYAN_STATUS_SUCCESS;
226 }
227 #endif
228 
ZydisStringAppendHexU64(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool uppercase)229 ZyanStatus ZydisStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
230     ZyanBool uppercase)
231 {
232     ZYAN_ASSERT(string);
233     ZYAN_ASSERT(!string->vector.allocator);
234 
235     const ZyanUSize len = string->vector.size;
236     const ZyanUSize remaining = string->vector.capacity - string->vector.size;
237 
238     if (remaining < (ZyanUSize)padding_length)
239     {
240         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
241     }
242 
243     if (!value)
244     {
245         const ZyanU8 n = (padding_length ? padding_length : 1);
246 
247         if (remaining < (ZyanUSize)n)
248         {
249             return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
250         }
251 
252         ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
253         string->vector.size = len + n;
254         ZYDIS_STRING_NULLTERMINATE(string);
255 
256         return ZYAN_STATUS_SUCCESS;
257     }
258 
259     ZyanU8 n = 0;
260     char* buffer = ZYAN_NULL;
261     for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
262         ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32) - 1; i >= 0; --i)
263     {
264         const ZyanU8 v = (value >> i * 4) & 0x0F;
265         if (!n)
266         {
267             if (!v)
268             {
269                 continue;
270             }
271             if (remaining <= (ZyanU8)i)
272             {
273                 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
274             }
275             buffer = (char*)string->vector.data + len - 1;
276             if (padding_length > i)
277             {
278                 n = padding_length - i - 1;
279                 ZYAN_MEMSET(buffer, '0', n);
280             }
281         }
282         ZYAN_ASSERT(buffer);
283         if (uppercase)
284         {
285             buffer[n++] = "0123456789ABCDEF"[v];
286         } else
287         {
288             buffer[n++] = "0123456789abcdef"[v];
289         }
290     }
291     string->vector.size = len + n;
292     ZYDIS_STRING_NULLTERMINATE(string);
293 
294     return ZYAN_STATUS_SUCCESS;
295 }
296 
297 /* ---------------------------------------------------------------------------------------------- */
298 
299 /* ============================================================================================== */
300 /* Public Functions                                                                               */
301 /* ============================================================================================== */
302 
303 /* ---------------------------------------------------------------------------------------------- */
304 /* Formatting                                                                                     */
305 /* ---------------------------------------------------------------------------------------------- */
306 
ZydisStringAppendDecU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,const ZyanStringView * prefix,const ZyanStringView * suffix)307 ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
308     const ZyanStringView* prefix, const ZyanStringView* suffix)
309 {
310     if (prefix)
311     {
312         ZYAN_CHECK(ZydisStringAppend(string, prefix));
313     }
314 
315 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
316     ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
317 #else
318     if (value & 0xFFFFFFFF00000000)
319     {
320         ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
321     }
322     ZYAN_CHECK(ZydisStringAppendDecU32(string, (ZyanU32)value, padding_length));
323 #endif
324 
325     if (suffix)
326     {
327         return ZydisStringAppend(string, suffix);
328     }
329     return ZYAN_STATUS_SUCCESS;
330 }
331 
ZydisStringAppendHexU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool uppercase,const ZyanStringView * prefix,const ZyanStringView * suffix)332 ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
333     ZyanBool uppercase, const ZyanStringView* prefix, const ZyanStringView* suffix)
334 {
335     if (prefix)
336     {
337         ZYAN_CHECK(ZydisStringAppend(string, prefix));
338     }
339 
340 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
341     ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, uppercase));
342 #else
343     if (value & 0xFFFFFFFF00000000)
344     {
345         ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, uppercase));
346     }
347     else
348     {
349         ZYAN_CHECK(ZydisStringAppendHexU32(string, (ZyanU32)value, padding_length, uppercase));
350     }
351 #endif
352 
353     if (suffix)
354     {
355         return ZydisStringAppend(string, suffix);
356     }
357     return ZYAN_STATUS_SUCCESS;
358 }
359 
360 /* ---------------------------------------------------------------------------------------------- */
361 
362 /* ============================================================================================== */
363