Spaces:
Running
Running
/* | |
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. | |