/*************************************************************************************************** Zyan Disassembler Library (Zydis) Original Author : Florian Bernd, Joel Höner * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ***************************************************************************************************/ #include /* ============================================================================================== */ /* Constants */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ /* Defines */ /* ---------------------------------------------------------------------------------------------- */ #define ZYDIS_MAXCHARS_DEC_32 10 #define ZYDIS_MAXCHARS_DEC_64 20 #define ZYDIS_MAXCHARS_HEX_32 8 #define ZYDIS_MAXCHARS_HEX_64 16 /* ---------------------------------------------------------------------------------------------- */ /* Lookup Tables */ /* ---------------------------------------------------------------------------------------------- */ static const char* decimalLookup = "00010203040506070809" "10111213141516171819" "20212223242526272829" "30313233343536373839" "40414243444546474849" "50515253545556575859" "60616263646566676869" "70717273747576777879" "80818283848586878889" "90919293949596979899"; /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */ /* Internal Functions */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ /* Formatting */ /* ---------------------------------------------------------------------------------------------- */ #if defined(ZYDIS_X86) || defined(ZYDIS_ARM) ZydisStatus ZydisPrintDecU32(ZydisString* string, ZydisU32 value, ZydisU8 paddingLength) { ZYDIS_ASSERT(string); ZYDIS_ASSERT(string->buffer); char temp[ZYDIS_MAXCHARS_DEC_32 + 1]; char *p = &temp[ZYDIS_MAXCHARS_DEC_32]; while (value >= 100) { ZydisU32 const old = value; p -= 2; value /= 100; ZydisMemoryCopy(p, &decimalLookup[(old - (value * 100)) * 2], sizeof(ZydisU16)); } p -= 2; ZydisMemoryCopy(p, &decimalLookup[value * 2], sizeof(ZydisU16)); const ZydisUSize n = &temp[ZYDIS_MAXCHARS_DEC_32] - p; if ((string->capacity - string->length < (ZydisUSize)(n + 1)) || (string->capacity - string->length < (ZydisUSize)(paddingLength + 1))) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } ZydisUSize offset = 0; if (n <= paddingLength) { offset = paddingLength - n + 1; ZydisMemorySet(string->buffer + string->length, '0', offset); } ZydisMemoryCopy(string->buffer + string->length + offset, &p[value < 10], n + 1); string->length += n + offset - (ZydisU8)(value < 10); return ZYDIS_STATUS_SUCCESS; } ZydisStatus ZydisPrintHexU32(ZydisString* string, ZydisU32 value, ZydisU8 paddingLength, ZydisBool uppercase, const ZydisString* prefix, const ZydisString* suffix) { ZYDIS_ASSERT(string); ZYDIS_ASSERT(string->buffer); if (prefix) { ZYDIS_CHECK(ZydisStringAppend(string, prefix)); } char* buffer = string->buffer + string->length; const ZydisUSize remaining = string->capacity - string->length; if (remaining < (ZydisUSize)paddingLength) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } if (!value) { const ZydisU8 n = (paddingLength ? paddingLength : 1); if (remaining < (ZydisUSize)n) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } ZydisMemorySet(buffer, '0', n); string->length += n; return ZYDIS_STATUS_SUCCESS; } ZydisU8 n = 0; for (ZydisI8 i = ZYDIS_MAXCHARS_HEX_32 - 1; i >= 0; --i) { const ZydisU8 v = (value >> i * 4) & 0x0F; if (!n) { if (!v) { continue; } if (remaining <= (ZydisU8)(i + 1)) // TODO: +1? { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } if (paddingLength > i) { n = paddingLength - i - 1; ZydisMemorySet(buffer, '0', n); } } if (uppercase) { buffer[n++] = "0123456789ABCDEF"[v]; } else { buffer[n++] = "0123456789abcdef"[v]; } } string->length += n; if (suffix) { ZYDIS_CHECK(ZydisStringAppend(string, suffix)); } return ZYDIS_STATUS_SUCCESS; } #endif ZydisStatus ZydisPrintDecU64(ZydisString* string, ZydisU64 value, ZydisU8 paddingLength) { ZYDIS_ASSERT(string); ZYDIS_ASSERT(string->buffer); char temp[ZYDIS_MAXCHARS_DEC_64 + 1]; char *p = &temp[ZYDIS_MAXCHARS_DEC_64]; while (value >= 100) { ZydisU64 const old = value; p -= 2; value /= 100; ZydisMemoryCopy(p, &decimalLookup[(old - (value * 100)) * 2], 2); } p -= 2; ZydisMemoryCopy(p, &decimalLookup[value * 2], sizeof(ZydisU16)); const ZydisUSize n = &temp[ZYDIS_MAXCHARS_DEC_64] - p; if ((string->capacity - string->length < (ZydisUSize)(n + 1)) || (string->capacity - string->length < (ZydisUSize)(paddingLength + 1))) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } ZydisUSize offset = 0; if (n <= paddingLength) { offset = paddingLength - n + 1; ZydisMemorySet(string->buffer + string->length, '0', offset); } ZydisMemoryCopy(string->buffer + string->length + offset, &p[value < 10], n + 1); string->length += n + offset - (ZydisU8)(value < 10); return ZYDIS_STATUS_SUCCESS; } ZydisStatus ZydisPrintHexU64(ZydisString* string, ZydisU64 value, ZydisU8 paddingLength, ZydisBool uppercase, const ZydisString* prefix, const ZydisString* suffix) { ZYDIS_ASSERT(string); ZYDIS_ASSERT(string->buffer); if (prefix) { ZYDIS_CHECK(ZydisStringAppend(string, prefix)); } char* buffer = string->buffer + string->length; const ZydisUSize remaining = string->capacity - string->length; if (remaining < (ZydisUSize)paddingLength) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } if (!value) { const ZydisU8 n = (paddingLength ? paddingLength : 1); if (remaining < (ZydisUSize)n) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } ZydisMemorySet(buffer, '0', n); string->length += n; return ZYDIS_STATUS_SUCCESS; } ZydisU8 n = 0; const ZydisU8 c = ((value & 0xFFFFFFFF00000000) ? ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32); for (ZydisI8 i = c - 1; i >= 0; --i) { const ZydisU8 v = (value >> i * 4) & 0x0F; if (!n) { if (!v) { continue; } if (remaining <= (ZydisU8)(i + 1)) // TODO: +1? { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } if (paddingLength > i) { n = paddingLength - i - 1; ZydisMemorySet(buffer, '0', n); } } if (uppercase) { buffer[n++] = "0123456789ABCDEF"[v]; } else { buffer[n++] = "0123456789abcdef"[v]; } } string->length += n; if (suffix) { ZYDIS_CHECK(ZydisStringAppend(string, suffix)); } return ZYDIS_STATUS_SUCCESS; } /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */ /* Public Functions */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ /* Basic Operations */ /* ---------------------------------------------------------------------------------------------- */ ZydisStatus ZydisStringAppendEx(ZydisString* string, const ZydisString* text, ZydisLetterCase letterCase) { if (!string || !text) { return ZYDIS_STATUS_INVALID_PARAMETER; } if (string->length + text->length >= string->capacity) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } ZydisMemoryCopy(string->buffer + string->length, text->buffer, text->length); switch (letterCase) { case ZYDIS_LETTER_CASE_DEFAULT: break; case ZYDIS_LETTER_CASE_LOWER: { const signed char rebase = 'a' - 'A'; char* c = string->buffer + string->length; for (ZydisUSize i = 0; i < text->length; ++i) { if ((*c >= 'A') && (*c <= 'Z')) { *c += rebase; } ++c; } break; } case ZYDIS_LETTER_CASE_UPPER: { const signed char rebase = 'A' - 'a'; char* c = string->buffer + string->length; for (ZydisUSize i = 0; i < text->length; ++i) { if ((*c >= 'a') && (*c <= 'z')) { *c += rebase; } ++c; } break; } default: return ZYDIS_STATUS_INVALID_PARAMETER; } string->length += text->length; return ZYDIS_STATUS_SUCCESS; } /* ---------------------------------------------------------------------------------------------- */ /* Formatting */ /* ---------------------------------------------------------------------------------------------- */ ZydisStatus ZydisPrintDecU(ZydisString* string, ZydisU64 value, ZydisU8 paddingLength) { #if defined(ZYDIS_X64) || defined(ZYDIS_AARCH64) return ZydisPrintDecU64(string, value, paddingLength); #else if (value & 0xFFFFFFFF00000000) { return ZydisPrintDecU64(string, value, paddingLength); } else { return ZydisPrintDecU32(string, (ZydisU32)value, paddingLength); } #endif } ZydisStatus ZydisPrintDecS(ZydisString* string, ZydisI64 value, ZydisU8 paddingLength) { if (value < 0) { ZYDIS_CHECK(ZydisStringAppendC(string, "-")); return ZydisPrintDecU(string, -value, paddingLength); } return ZydisPrintDecU(string, value, paddingLength); } ZydisStatus ZydisPrintHexU(ZydisString* string, ZydisU64 value, ZydisU8 paddingLength, ZydisBool uppercase, const ZydisString* prefix, const ZydisString* suffix) { #if defined(ZYDIS_X64) || defined(ZYDIS_AARCH64) return ZydisPrintHexU64(string, value, paddingLength, uppercase, prefix, suffix); #else if (value & 0xFFFFFFFF00000000) { return ZydisPrintHexU64(string, value, paddingLength, uppercase, prefix, suffix); } else { return ZydisPrintHexU32(string, (ZydisU32)value, paddingLength, uppercase, prefix, suffix); } #endif } ZydisStatus ZydisPrintHexS(ZydisString* string, ZydisI64 value, ZydisU8 paddingLength, ZydisBool uppercase, const ZydisString* prefix, const ZydisString* suffix) { if (value < 0) { ZYDIS_CHECK(ZydisStringAppendC(string, "-")); if (prefix) { ZYDIS_CHECK(ZydisStringAppend(string, prefix)); } return ZydisPrintHexU(string, -value, paddingLength, uppercase, ZYDIS_NULL, suffix); } return ZydisPrintHexU(string, value, paddingLength, uppercase, prefix, suffix); } /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */