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) 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 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) 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 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 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 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