Spaces:
Sleeping
Sleeping
| /* | |
| This file contains definitions used in the Hex-Rays decompiler output. | |
| It has type definitions and convenience macros to make the | |
| output more readable. | |
| Copyright (c) 2007-2024 Hex-Rays | |
| */ | |
| // ejs hack... | |
| typedef long long ll; | |
| typedef unsigned long long ull; | |
| typedef __int64 ll; | |
| typedef unsigned __int64 ull; | |
| typedef __int64 ll; | |
| typedef unsigned __int64 ull; | |
| typedef unsigned int uint; | |
| typedef unsigned char uchar; | |
| typedef unsigned short ushort; | |
| typedef unsigned long ulong; | |
| typedef char int8; | |
| typedef signed char sint8; | |
| typedef unsigned char uint8; | |
| typedef short int16; | |
| typedef signed short sint16; | |
| typedef unsigned short uint16; | |
| typedef int int32; | |
| typedef signed int sint32; | |
| typedef unsigned int uint32; | |
| typedef ll int64; | |
| typedef ll sint64; | |
| typedef ull uint64; | |
| // Partially defined types. They are used when the decompiler does not know | |
| // anything about the type except its size. | |
| // Non-standard boolean types. They are used when the decompiler cannot use | |
| // the standard "bool" type because of the size mistmatch but the possible | |
| // values are only 0 and 1. See also 'BOOL' type below. | |
| typedef int8 _BOOL1; | |
| typedef int16 _BOOL2; | |
| typedef int32 _BOOL4; | |
| typedef int64 _BOOL8; | |
| typedef int8 BYTE; | |
| typedef int16 WORD; | |
| typedef int32 DWORD; | |
| typedef int32 LONG; | |
| typedef int BOOL; // uppercase BOOL is usually 4 bytes | |
| typedef int64 QWORD; | |
| typedef int bool; // we want to use bool in our C programs | |
| // when given the same arguments, always returns the same value | |
| // has no side effects | |
| // Non-returning function | |
| // Some convenience macros to make partial accesses nicer | |
| // first unsigned macros: | |
| // now signed macros (the same but with sign extension) | |
| // Generate a pair of operands. S stands for 'signed' | |
| // Helper functions to represent some assembly instructions. | |
| // compile time assertion | |
| // check that unsigned multiplication does not overflow | |
| template<class T> bool is_mul_ok(T count, T elsize) | |
| { | |
| CASSERT(T(-1) > 0); // make sure T is unsigned | |
| if ( elsize == 0 || count == 0 ) | |
| return true; | |
| return count <= T(-1) / elsize; | |
| } | |
| // multiplication that saturates (yields the biggest value) instead of overflowing | |
| // such a construct is useful in "operator new[]" | |
| template<class T> bool saturated_mul(T count, T elsize) | |
| { | |
| return is_mul_ok(count, elsize) ? count * elsize : T(-1); | |
| } | |
| // memcpy() with determined behavoir: it always copies | |
| // from the start to the end of the buffer | |
| // note: it copies byte by byte, so it is not equivalent to, for example, rep movsd | |
| inline void *qmemcpy(void *dst, const void *src, size_t cnt) | |
| { | |
| char *out = (char *)dst; | |
| const char *in = (const char *)src; | |
| while ( cnt > 0 ) | |
| { | |
| *out++ = *in++; | |
| --cnt; | |
| } | |
| return dst; | |
| } | |
| // rotate left | |
| template<class T> T __ROL__(T value, int count) | |
| { | |
| const uint nbits = sizeof(T) * 8; | |
| if ( count > 0 ) | |
| { | |
| count %= nbits; | |
| T high = value >> (nbits - count); | |
| if ( T(-1) < 0 ) // signed value | |
| high &= ~((T(-1) << count)); | |
| value <<= count; | |
| value |= high; | |
| } | |
| else | |
| { | |
| count = -count % nbits; | |
| T low = value << (nbits - count); | |
| value >>= count; | |
| value |= low; | |
| } | |
| return value; | |
| } | |
| inline uint8 __ROL1__(uint8 value, int count) { return __ROL__((uint8)value, count); } | |
| inline uint16 __ROL2__(uint16 value, int count) { return __ROL__((uint16)value, count); } | |
| inline uint32 __ROL4__(uint32 value, int count) { return __ROL__((uint32)value, count); } | |
| inline uint64 __ROL8__(uint64 value, int count) { return __ROL__((uint64)value, count); } | |
| inline uint8 __ROR1__(uint8 value, int count) { return __ROL__((uint8)value, -count); } | |
| inline uint16 __ROR2__(uint16 value, int count) { return __ROL__((uint16)value, -count); } | |
| inline uint32 __ROR4__(uint32 value, int count) { return __ROL__((uint32)value, -count); } | |
| inline uint64 __ROR8__(uint64 value, int count) { return __ROL__((uint64)value, -count); } | |
| // sign flag | |
| template<class T> int8 __SETS__(T x) | |
| { | |
| if ( sizeof(T) == 1 ) | |
| return int8(x) < 0; | |
| if ( sizeof(T) == 2 ) | |
| return int16(x) < 0; | |
| if ( sizeof(T) == 4 ) | |
| return int32(x) < 0; | |
| return int64(x) < 0; | |
| } | |
| // overflow flag of subtraction (x-y) | |
| template<class T, class U> int8 __OFSUB__(T x, U y) | |
| { | |
| if ( sizeof(T) < sizeof(U) ) | |
| { | |
| U x2 = x; | |
| int8 sx = __SETS__(x2); | |
| return (sx ^ __SETS__(y)) & (sx ^ __SETS__(U(x2-y))); | |
| } | |
| else | |
| { | |
| T y2 = y; | |
| int8 sx = __SETS__(x); | |
| return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(T(x-y2))); | |
| } | |
| } | |
| // overflow flag of addition (x+y) | |
| template<class T, class U> int8 __OFADD__(T x, U y) | |
| { | |
| if ( sizeof(T) < sizeof(U) ) | |
| { | |
| U x2 = x; | |
| int8 sx = __SETS__(x2); | |
| return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(U(x2+y))); | |
| } | |
| else | |
| { | |
| T y2 = y; | |
| int8 sx = __SETS__(x); | |
| return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(T(x+y2))); | |
| } | |
| } | |
| // https://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._borrow_flag | |
| // carry flag of subtraction (x-y) | |
| template<class T, class U> int8 __CFSUB__(T x, U y) | |
| { | |
| int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); | |
| bool res; | |
| if ( size == 1 ) | |
| res = uint8(x) < uint8(y); | |
| else if ( size == 2 ) | |
| res = uint16(x) < uint16(y); | |
| else if ( size == 4 ) | |
| res = uint32(x) < uint32(y); | |
| else | |
| res = uint64(x) < uint64(y); | |
| res = !res; | |
| return res; | |
| } | |
| // carry flag of addition (x+y) | |
| template<class T, class U> int8 __CFADD__(T x, U y) | |
| { | |
| int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); | |
| if ( size == 1 ) | |
| return uint8(x) > uint8(x+y); | |
| if ( size == 2 ) | |
| return uint16(x) > uint16(x+y); | |
| if ( size == 4 ) | |
| return uint32(x) > uint32(x+y); | |
| return uint64(x) > uint64(x+y); | |
| } | |
| // carry flag of subtraction with carry | |
| template<class T, class U> int8 __CFSUB__(T x, U y, int8 cf) | |
| { | |
| cf = !cf; | |
| return __CFADD__(y, cf) ^ __CFSUB(x, y + cf); | |
| } | |
| // overflow flag of subtraction with carry | |
| template<class T, class U> int8 __OFSUB__(T x, U y, int8 cf) | |
| { | |
| cf = !cf; | |
| return __OFADD__(y, cf) ^ __OFSUB(x, y + cf); | |
| } | |
| inline uint8 abs8(int8 x) { return x >= 0 ? x : -x; } | |
| inline uint16 abs16(int16 x) { return x >= 0 ? x : -x; } | |
| inline uint32 abs32(int32 x) { return x >= 0 ? x : -x; } | |
| inline uint64 abs64(int64 x) { return x >= 0 ? x : -x; } | |
| //inline uint128 abs128(int128 x) { return x >= 0 ? x : -x; } | |
| template <typename T, typename F> | |
| inline typename std::enable_if<sizeof(T) <= sizeof(F), T>::type __coerce(F f) | |
| { | |
| T t; | |
| memcpy(&t, &f, sizeof(T)); | |
| return t; | |
| } | |
| // For C, we just provide macros, they are not quite correct. | |
| // traps for MIPS arithmetic operation | |
| void __noreturn __integer_oveflow(void); // SIGFPE/FPE_INTOVF | |
| void __noreturn __divide_by_zero(void); // SIGFPE/FPE_INTDIV | |
| void __noreturn __trap(uint16 trapcode); // SIGTRAP | |
| void __noreturn __break(uint16 code, uint16 subcode); | |
| // In the decompilation listing there are some objects declared as _UNKNOWN | |
| // because we could not determine their types. Since the C compiler does not | |
| // accept void item declarations, we replace them by anything of our choice, | |
| // for example a char: | |
| // The ADJ() macro is used for shifted pointers. | |
| // While compilers do not understand it, it makes the code more readable. | |
| // A shifted pointer is declared like this, for example: | |
| // char *__shifted(mystruct,8) p; | |
| // It means: while 'p' points to 'char', it also points to the middle of 'mystruct'. | |
| // More precisely, it is at the offset of 8 bytes from the beginning of 'mystruct'. | |
| // | |
| // The ADJ() macro performs the necessary adjustment. | |
| // The __parentof() and __deltaof() functions are made up, they do not exist. | |
| // __parentof() returns the parent structure type. | |
| // __deltaof() returns the shift amount. | |