// vi: set ts=4 sw=4 : // vim: set tw=75 : // engineinfo.h - info about HL engine, like file used and // text segment range // #ifndef MM_ENGINEINFO_H #define MM_ENGINEINFO_H #ifdef _WIN32 typedef void* MemAddr; #else # include // ElfW(Addr/Phdr) macros typedef void* MemAddr; #endif /* _WIN32 */ #include "extdll.h" // eiface.h: enginefuncs_t #include "comp_dep.h" #include "osdep.h" //unlikely, OPEN_ARGS #include "new_baseclass.h" // What we return in is_valid_code_pointer() when the EngineInfo object is // in an INVALID state, i.e. no code address range could be determined. static const bool c_DefaultReturnOnInvalidState = true; static const int c_EngineInfo__typeLen = 10; class EngineInfo : public class_metamod_new { private: // data : MemAddr m_codeStart; MemAddr m_codeEnd; // State is either NULL when not yet initialised, // VALID if a code range could be determined // or INVALID when no valid range for code addresses // could be determined. char m_state; // Type of engine dso/dll used. // For Linux this specifies the architecture, i.e. 'i486', 'i686', // 'amd', 'amd64' etc. // For Windows this is either 'sw' or 'hw' or 'swds' depending on // the server type. char m_type[c_EngineInfo__typeLen]; // functions : // Check if string is valid name of engine dso/dll. bool DLLINTERNAL check_for_engine_module( const char* pName ); #ifdef _WIN32 // Set info using the PE header found by module name. // Returns 0 on success, error code on failure. int DLLINTERNAL nthdr_module_name( void ); int DLLINTERNAL vac_pe_approx( enginefuncs_t* pFuncs ); // Set code segment start and end from PEheader. The base // address, that relative addresses are based on, is passed in // pBase. void DLLINTERNAL set_code_range( unsigned char* pBase, PIMAGE_NT_HEADERS pNThdr ); #else // Set info using the Programheader found via r_debug struct. // Returns 0 on success, error code on failure. int DLLINTERNAL phdr_r_debug( void ); // Set info using the Programheader found with reference address // via dladdr(). Returns 0 on success, error code on failure. int DLLINTERNAL phdr_dladdr( void* pMem ); // Set info using the Programheader found via ELF header passed as // pElfHdr. Return 0 on success, error code on failure. int DLLINTERNAL phdr_elfhdr( void* pElfHdr ); // Set code segment start and end from Programheader. The base // address, that relative addresses are based on, is passed in // pBase. void DLLINTERNAL set_code_range( void* pBase, ElfW(Phdr)* pPhdr ); #endif /* _WIN32 */ public: // codes : enum { STATE_NULL = 0, STATE_VALID, STATE_INVALID, MODULE_NAME_NOTFOUND = 5, INVALID_DOS_SIGN, INVALID_NT_SIGN, INVALID_ARG, HEADER_NOTFOUND, NOTFOUND }; // functions : EngineInfo() DLLINTERNAL; EngineInfo& operator=( const EngineInfo& ) DLLINTERNAL; EngineInfo( const EngineInfo& ) DLLINTERNAL; const char* DLLINTERNAL type( void ); // Initilaise object, determining the bounds of the code segment of // the HL engine shared object. int DLLINTERNAL initialise( enginefuncs_t* pFuncs = NULL ); // Test if pMem is within bounds of the code segment. bool DLLINTERNAL is_valid_code_pointer( void* pMem ); // Overloaded versions of above test to keep the ugly pointer // conversion stuff in here. bool DLLINTERNAL is_valid_code_pointer( const char* (*fp) (edict_t*) ); bool DLLINTERNAL is_valid_code_pointer( sequenceEntry_s* (*fp) (const char*, const char*) ); bool DLLINTERNAL is_valid_code_pointer( sentenceEntry_s* (*fp) (const char*, int, int*) ); bool DLLINTERNAL is_valid_code_pointer( int (*fp) (char*) ); bool DLLINTERNAL is_valid_code_pointer( unsigned int (*fp) (const char*) ); bool DLLINTERNAL is_valid_code_pointer( int (*fp) (void) ); bool DLLINTERNAL is_valid_code_pointer( int (*fp) (const char*) ); bool DLLINTERNAL is_valid_code_pointer( void (*fp) (int) ); bool DLLINTERNAL is_valid_code_pointer( int (*fp) (int) ); bool DLLINTERNAL is_valid_code_pointer( void (*fp) (int*, int) ); bool DLLINTERNAL is_valid_code_pointer( void (*fp) (void) ); bool DLLINTERNAL is_valid_code_pointer( void (*fp) (const edict_t*, const char*) ); bool DLLINTERNAL is_valid_code_pointer( void (*fp) (const edict_t*, const char*, int) ); }; // We probably should run an initialisation here without a reference // pointer so that the object has valid info in any case. inline EngineInfo::EngineInfo() : m_codeStart(NULL), m_codeEnd(NULL), m_state(STATE_NULL) { m_type[0] = '\0'; } inline EngineInfo::EngineInfo( const EngineInfo& _rhs) : m_codeStart(_rhs.m_codeStart), m_codeEnd(_rhs.m_codeEnd), m_state(STATE_NULL) { memcpy( m_type, _rhs.m_type, c_EngineInfo__typeLen ); } inline EngineInfo& EngineInfo::operator=( const EngineInfo& _rhs) { m_state = _rhs.m_state; m_codeStart = _rhs.m_codeStart; m_codeEnd = _rhs.m_codeEnd; memcpy( m_type, _rhs.m_type, c_EngineInfo__typeLen ); return *this; } inline const char* EngineInfo::type( void ) { return m_type; } inline bool EngineInfo::is_valid_code_pointer( void* _pMem ) { if ( STATE_INVALID == m_state ) { return c_DefaultReturnOnInvalidState; } if ( NULL != _pMem && m_codeStart <= _pMem && _pMem <= m_codeEnd ) { return true; } return false; } inline bool EngineInfo::is_valid_code_pointer( const char* (*_fp) (edict_t*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( sequenceEntry_s* (*_fp) (const char*, const char*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( sentenceEntry_s* (*_fp) (const char*, int, int*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (char*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( unsigned int (*_fp) (const char*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (void) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (const char*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (int) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (int) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (int*, int) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (void) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (const edict_t*, const char*) ) { return is_valid_code_pointer( (void*)_fp ); } inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (const edict_t*, const char*, int) ) { return is_valid_code_pointer( (void*)_fp ); } #endif /* MM_ENGINEINFO_H */