From cba9387c361c3d33dcf1b21ff0e5beb4b0a81ade Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 16 May 2023 22:12:57 +0100 Subject: Do some pedantic spring cleaning - Use const in more places where it makes sense - not absolutely everywhere because it can get a bit annoying - Make all the instruction search loops a bit more readable by casting the function pointer into a temporary variable to loop over - Add a few more doc comments and fix a typo or two - Make that RTTI thing flexibly-sized, finally - Don't include gamedata.h in vcall.h for no reason; consequently include gamedata.h in a bunch of places where it was implictly pulled in before - Fix dbg_toghidra() and ent_getedict() having mismatched return types between their headers and respective source files - Remove that one broken, hacky, secret Portal non-feature that probably nobody even ended up using; it can be implemented properly later if required --- src/abi.h | 43 +++++++++++++++++++++++++------------------ src/ac.c | 13 +++++-------- src/alias.c | 3 ++- src/bind.c | 5 +++-- src/bind.h | 1 + src/con_.c | 1 + src/con_.h | 2 +- src/dbg.c | 12 ++++++------ src/dbg.h | 10 ++++++---- src/democustom.c | 2 +- src/demorec.c | 9 ++++++--- src/ent.c | 4 ++-- src/ent.h | 5 ++++- src/errmsg.c | 4 +--- src/extmalloc.c | 2 +- src/fov.c | 6 +++--- src/gameinfo.c | 1 + src/hook.c | 4 ++-- src/os-win32.h | 8 ++++---- src/sst.c | 23 +---------------------- src/vcall.h | 4 +--- 21 files changed, 77 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/abi.h b/src/abi.h index 81b97e5..f9b5b7c 100644 --- a/src/abi.h +++ b/src/abi.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,8 +20,8 @@ #include "intdefs.h" /* - * This file defines miscellaneous C++ ABI stuff. Looking at it may cause - * brain damage and/or emotional trauma. + * This file defines miscellaneous C++ ABI stuff. Looking at it may cause brain + * damage and/or emotional trauma. */ #ifdef _WIN32 // Windows RTTI stuff, obviously only used on Windows. @@ -37,19 +37,20 @@ // should be a small lookup table is an absolute nutcase. I hope that individual // has gotten some help by now, mostly for the sake of others. -struct msvc_rtti_descriptor { - void *vtab; +struct msvc_rtti_descriptor_head { + void **vtab; void *unknown; // ??? - // XXX: pretty sure this is supposed to be flexible, but too lazy to write - // the stupid union init macros to make that fully portable - char classname[80]; + // descriptor includes this, but constant flexible arrays are annoying, so + // this structure is just the header part and the string is tacked on in the + // DEF_MSVC_BASIC_RTTI macro below + //char classname[]; }; // "pointer to member displacement" struct msvc_pmd { int mdisp, pdisp, vdisp; }; struct msvc_basedesc { - struct msvc_rtti_descriptor *desc; + const struct msvc_rtti_descriptor_head *desc; uint nbases; struct msvc_pmd where; uint attr; @@ -59,7 +60,7 @@ struct msvc_rtti_hierarchy { uint sig; uint attrs; uint nbaseclasses; - struct msvc_basedesc **baseclasses; + const struct msvc_basedesc **baseclasses; }; struct msvc_rtti_locator { @@ -67,20 +68,26 @@ struct msvc_rtti_locator { int baseoff; // ctor offset, or some flags; reactos and rust pelite say different things? int unknown; - struct msvc_rtti_descriptor *desc; - struct msvc_rtti_hierarchy *hier; + const struct msvc_rtti_descriptor_head *desc; + const struct msvc_rtti_hierarchy *hier; }; // I mean seriously look at this crap! #define DEF_MSVC_BASIC_RTTI(mod, name, vtab, typestr) \ -mod struct msvc_rtti_locator name; \ -static struct msvc_rtti_descriptor _desc_##name = {(vtab), 0, typestr}; \ -static struct msvc_basedesc _basedesc_##name = {&_desc_##name, 0, {0, 0, 0}, 0}; \ -mod struct msvc_rtti_locator name = { \ +const mod struct msvc_rtti_locator name; \ +static const struct { \ + struct msvc_rtti_descriptor_head d; \ + char classname[sizeof("" typestr)]; \ +} _desc_##name = {(vtab), 0, .classname = "" typestr}; \ +static const struct msvc_basedesc _basedesc_##name = { \ + &_desc_##name.d, 0, {0, 0, 0}, 0 \ +}; \ +mod const struct msvc_rtti_locator name = { \ 0, 0, 0, \ - &_desc_##name, \ + &_desc_##name.d, \ &(struct msvc_rtti_hierarchy){ \ - 0, 1 /* per engine */, 1, (struct msvc_basedesc *[]){&_basedesc_##name} \ + 0, 1 /* match engine */, 1, \ + (const struct msvc_basedesc *[]){&_basedesc_##name} \ } \ }; diff --git a/src/ac.c b/src/ac.c index 01b969f..c379326 100644 --- a/src/ac.c +++ b/src/ac.c @@ -27,6 +27,7 @@ #include "errmsg.h" #include "event.h" #include "feature.h" +#include "gamedata.h" #include "intdefs.h" #include "mem.h" #include "os.h" @@ -242,10 +243,8 @@ static bool find_DispatchInputEvent(void) { return false; } void *cgame; - GetDesktopResolution_func GetDesktopResolution = - VFUNC(gameuifuncs, GetDesktopResolution); - for (uchar *p = (uchar *)GetDesktopResolution; - p - (uchar *)GetDesktopResolution < 16;) { + const uchar *insns = (const uchar*)VFUNC(gameuifuncs, GetDesktopResolution); + for (const uchar *p = insns; p - insns < 16;) { if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5)) { void **indirect = mem_loadptr(p + 2); cgame = *indirect; @@ -255,10 +254,8 @@ static bool find_DispatchInputEvent(void) { } errmsg_errorx("couldn't find pointer to CGame instance"); return false; -ok: DispatchAllStoredGameMessages_func DispatchAllStoredGameMessages = - VFUNC(cgame, DispatchAllStoredGameMessages); - for (uchar *p = (uchar *)DispatchAllStoredGameMessages; - p - (uchar *)DispatchAllStoredGameMessages < 128;) { +ok: insns = (const uchar *)VFUNC(cgame, DispatchAllStoredGameMessages); + for (const uchar *p = insns; p - insns < 128;) { if (p[0] == X86_CALL) { orig_DispatchInputEvent = (DispatchInputEvent_func)(p + 5 + mem_loadoffset(p + 1)); diff --git a/src/alias.c b/src/alias.c index c281a37..e390cd1 100644 --- a/src/alias.c +++ b/src/alias.c @@ -71,8 +71,9 @@ DEF_CCMD_HERE_UNREG(sst_alias_remove, "Remove a command alias", 0) { } static bool find_alias_head(con_cmdcb alias_cb) { + const uchar *insns = (const uchar *)alias_cb; #ifdef _WIN32 - for (uchar *p = (uchar *)alias_cb; p - (uchar *)alias_cb < 64;) { + for (const uchar *p = insns; p - insns < 64;) { // alias command with no args calls ConMsg() then loads the head pointer // that asm looks like: call ; mov , dword ptr [x] // (we don't care about the exact registers) diff --git a/src/bind.c b/src/bind.c index 41fd437..97864c8 100644 --- a/src/bind.c +++ b/src/bind.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,7 +37,8 @@ const char *bind_get(int keycode) { return keyinfo[keycode].binding; } static bool find_keyinfo(con_cmdcb klbc_cb) { #ifdef _WIN32 - for (uchar *p = (uchar *)klbc_cb; p - (uchar *)klbc_cb < 32;) { + const uchar *insns = (const uchar *)klbc_cb; + for (const uchar *p = insns; p - insns < 32;) { // key_listboundkeys command, in its loop through each possible index, // does a mov from that index into a register, something like: // mov , dword ptr [ * 8 + s_pKeyInfo] diff --git a/src/bind.h b/src/bind.h index daf97da..ec8b009 100644 --- a/src/bind.h +++ b/src/bind.h @@ -17,6 +17,7 @@ #ifndef INC_BIND_H #define INC_BIND_H +/* Returns the command string bound to a given keycode. */ const char *bind_get(int keycode); #endif diff --git a/src/con_.c b/src/con_.c index a80a2d4..eafc242 100644 --- a/src/con_.c +++ b/src/con_.c @@ -23,6 +23,7 @@ #include "con_.h" #include "engineapi.h" // for factories and rgba - XXX: is this a bit circular? #include "extmalloc.h" +#include "gamedata.h" #include "gametype.h" #include "mem.h" #include "os.h" diff --git a/src/con_.h b/src/con_.h index 6d67e51..dcba4d9 100644 --- a/src/con_.h +++ b/src/con_.h @@ -213,7 +213,7 @@ extern void *_con_vtab_cmd[]; // a constant expression we have to use a macro. extern struct _con_vtab_var_wrap { #ifdef _WIN32 - struct msvc_rtti_locator *rtti; + const struct msvc_rtti_locator *rtti; #else // itanium ABI also has the top offset/"whole object" offset in libstdc++ ssize topoffset; diff --git a/src/dbg.c b/src/dbg.c index 2eb88f6..0db23ec 100644 --- a/src/dbg.c +++ b/src/dbg.c @@ -24,7 +24,7 @@ #include "ppmagic.h" #include "udis86.h" -void dbg_hexdump(char *name, const void *p, int len) { +void dbg_hexdump(const char *name, const void *p, int len) { struct rgba nice_colour = {160, 64, 200, 255}; // a nice purple colour con_colourmsg(&nice_colour, "Hex dump \"%s\" (%p):", name, p); for (const uchar *cp = p; cp - (uchar *)p < len; ++cp) { @@ -38,7 +38,7 @@ void dbg_hexdump(char *name, const void *p, int len) { con_msg("\n"); } -void dbg_asmdump(char *name, const void *p, int len) { +void dbg_asmdump(const char *name, const void *p, int len) { struct rgba nice_colour = {40, 160, 140, 255}; // a nice teal colour struct ud udis; ud_init(&udis); @@ -52,15 +52,15 @@ void dbg_asmdump(char *name, const void *p, int len) { } #ifdef _WIN32 -usize dbg_toghidra(void *addr) { - void *mod; +usize dbg_toghidra(const void *addr) { + const void *mod; if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (ushort *)addr, - (HMODULE *)&mod/*please leave me alone*/)) { + (HMODULE *)&mod /* please leave me alone */)) { con_warn("dbg_toghidra: couldn't get base address\n"); return 0; } - return (char *)addr - (char *)mod + 0x10000000; + return (const char *)addr - (const char *)mod + 0x10000000; } #endif diff --git a/src/dbg.h b/src/dbg.h index e3625e0..8e07a22 100644 --- a/src/dbg.h +++ b/src/dbg.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,6 +17,8 @@ #ifndef INC_DBG_H #define INC_DBG_H +#include "intdefs.h" + /* * These functions can all be used for development and debugging but aren't * available to release builds; this header shouldn't even be #included in real @@ -24,14 +26,14 @@ */ /* Prints out a basic hexadecimal listing of a byte range. */ -void dbg_hexdump(char *name, const void *p, int len); +void dbg_hexdump(const char *name, const void *p, int len); /* Prints out a disassembly of some instructions in memory. */ -void dbg_asmdump(char *name, const void *p, int len); +void dbg_asmdump(const char *name, const void *p, int len); #ifdef _WIN32 // at least for now /* Returns a function's Ghidra address, assuming default project offsets. */ -void *dbg_toghidra(void *addr); +usize dbg_toghidra(const void *addr); #endif #endif diff --git a/src/democustom.c b/src/democustom.c index f8c7c9d..c2c6ae1 100644 --- a/src/democustom.c +++ b/src/democustom.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/src/demorec.c b/src/demorec.c index bbcc317..ee57c12 100644 --- a/src/demorec.c +++ b/src/demorec.c @@ -168,9 +168,10 @@ static void hook_stop_cb(const struct con_cmdargs *args) { // instance). static inline bool find_demorecorder(void) { #ifdef _WIN32 + const uchar *insns = (const uchar *)orig_stop_cb; // The "stop" command calls the virtual function demorecorder.IsRecording(), // so just look for the load of the "this" pointer into ECX - for (uchar *p = (uchar *)orig_stop_cb; p - (uchar *)orig_stop_cb < 32;) { + for (const uchar *p = insns; p - insns < 32;) { if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5)) { void **indirect = mem_loadptr(p + 2); demorecorder = *indirect; @@ -188,7 +189,8 @@ static inline bool find_demorecorder(void) { // original "StopRecording" demorecorder function. static inline bool find_recmembers(void *stoprecording) { #ifdef _WIN32 - for (uchar *p = (uchar *)stoprecording; p - (uchar *)stoprecording < 128;) { + const uchar *insns = (uchar *)stoprecording; + for (const uchar *p = insns; p - insns < 128;) { // m_nDemoNumber = 0 -> mov dword ptr [ + off], 0 // XXX: might end up wanting constants for the MRM field masks? if (p[0] == X86_MOVMIW && (p[1] & 0xC0) == 0x80 && @@ -212,7 +214,8 @@ static inline bool find_recmembers(void *stoprecording) { // "StartRecording" demorecorder function. static inline bool find_demoname(void *startrecording) { #ifdef _WIN32 - for (uchar *p = (uchar *)startrecording; p - (uchar *)startrecording < 32;) { + const uchar *insns = (uchar *)startrecording; + for (const uchar *p = insns; p - insns < 32;) { // the function immediately calls Q_strncpy and copies into a buffer // offset from `this` - look for a LEA instruction some time *before* // the first call takes place diff --git a/src/ent.c b/src/ent.c index 4a457af..4ab0379 100644 --- a/src/ent.c +++ b/src/ent.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,7 +28,7 @@ FEATURE() DECL_VFUNC_DYN(void *, PEntityOfEntIndex, int) static struct edict **edicts = 0; -void *ent_getedict(int idx) { +struct edict *ent_getedict(int idx) { if (edicts) { // globalvars->edicts seems to be null when disconnected if (!*edicts) return 0; diff --git a/src/ent.h b/src/ent.h index 049f27f..0273d86 100644 --- a/src/ent.h +++ b/src/ent.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,7 +19,10 @@ #include "engineapi.h" +/* Returns a server-side edict pointer, or null if not found. */ struct edict *ent_getedict(int idx); + +/* Returns an opaque pointer to a server-side entity, or null if not found. */ void *ent_get(int idx); #endif diff --git a/src/errmsg.c b/src/errmsg.c index 63af533..cc7bf12 100644 --- a/src/errmsg.c +++ b/src/errmsg.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,8 +14,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "con_.h" - const char msg_note[] = "note: "; const char msg_warn[] = "warning: "; const char msg_error[] = "error: "; diff --git a/src/extmalloc.c b/src/extmalloc.c index edd1d54..3e14e0d 100644 --- a/src/extmalloc.c +++ b/src/extmalloc.c @@ -17,7 +17,7 @@ #include "intdefs.h" #include "vcall.h" -// FIXME: this is duped from os.h because I don't want to pull in Windows.h, +// XXX: this is duped from os.h because I don't want to pull in Windows.h, // consider splitting out the IMPORT/EXPORT defs to some other thing? #ifdef _WIN32 #define IMPORT __declspec(dllimport) // only needed for variables diff --git a/src/fov.c b/src/fov.c index 1a0874c..236182a 100644 --- a/src/fov.c +++ b/src/fov.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * Copyright © 2022 Willian Henrique * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,9 +50,9 @@ static void VCALLCONV hook_SetDefaultFOV(void *this, int fov) { } static bool find_SetDefaultFOV(struct con_cmd *fov) { - uchar *fovcb = (uchar *)fov->cb; + const uchar *insns = (const uchar *)fov->cb; int callcnt = 0; - for (uchar *p = fovcb; p - fovcb < 96;) { + for (const uchar *p = insns; p - insns < 96;) { // fov command source, and consequent asm, calls 4 functions, one of // them virtual (i.e. via register). of the 3 direct calls, // SetDefaultFOV is the third. diff --git a/src/gameinfo.c b/src/gameinfo.c index 086ab8b..d04ae0f 100644 --- a/src/gameinfo.c +++ b/src/gameinfo.c @@ -21,6 +21,7 @@ #include "con_.h" #include "engineapi.h" #include "errmsg.h" +#include "gamedata.h" #include "gametype.h" #include "intdefs.h" #include "kv.h" diff --git a/src/hook.c b/src/hook.c index eacac4a..ff7ac96 100644 --- a/src/hook.c +++ b/src/hook.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * Copyright © 2022 Willian Henrique * * Permission to use, copy, modify, and/or distribute this software for any @@ -102,7 +102,7 @@ nosp: con_warn("hook_inline: out of trampoline space\n"); } void unhook_inline(void *orig) { - uchar *p = (uchar *)orig; + uchar *p = orig; int len = p[-1]; int off = mem_load32(p + len + 1); uchar *q = p + off + 5; diff --git a/src/os-win32.h b/src/os-win32.h index 12720a9..8f554bd 100644 --- a/src/os-win32.h +++ b/src/os-win32.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -83,9 +83,9 @@ static inline void os_randombytes(void *buf, int sz) { #ifndef PATH_MAX // XXX: win32/crt has this dumb 260 limit even though the actual kernel imposes -// no limit (though apparently NTFS has a limit of 65535). Theoerically we could -// do some memes with UNC paths to extend it to at least have parity with Unix -// PATH_MAX (4096), but for now we just kind of accept that Windows is a +// no limit (though apparently NTFS has a limit of 65535). Theoretically we +// could do some memes with UNC paths to extend it to at least have parity with +// Unix PATH_MAX (4096), but for now we just kind of accept that Windows is a // disaster. #define PATH_MAX MAX_PATH #endif diff --git a/src/sst.c b/src/sst.c index 93c194a..392f540 100644 --- a/src/sst.c +++ b/src/sst.c @@ -26,6 +26,7 @@ #include "errmsg.h" #include "event.h" #include "fixes.h" +#include "gamedata.h" #include "gameinfo.h" #include "gametype.h" #include "hook.h" @@ -411,13 +412,6 @@ static const char *VCALLCONV GetPluginDescription(void *this) { DECL_VFUNC_DYN(void, ServerCommand, const char *) -// XXX: quick hack requested by Portal people for some timeboxed IL grind -// challenge they want to do. I think this is a terribly sad way to do this but -// at the same time it's easy and low-impact so put it in as hidden for now -// until we come up with something better later. -DEF_CVAR(_sst_onload_echo, "EXPERIMENTAL! Don't rely on this existing!", "", - CON_HIDDEN) - DEF_EVENT(ClientActive, struct edict */*player*/) DEF_EVENT(Tick, bool /*simulating*/) @@ -429,21 +423,6 @@ static void VCALLCONV GameFrame(void *this, bool simulating) { static void VCALLCONV ClientActive(void *this, struct edict *player) { EMIT_ClientActive(player); - - // continuing dumb portal hack. didn't even seem worth adding a feature for - if (has_vtidx_ServerCommand && con_getvarstr(_sst_onload_echo)[0]) { - char *s = malloc(8 + _sst_onload_echo->strlen); // dumb lol - if (s) { // if not, game probably exploded already - memcpy(s, "echo \"", 6); - // note: assume there's no quotes in the variable, because there - // should be no way to do this at least via console - memcpy(s + 6, con_getvarstr(_sst_onload_echo), - _sst_onload_echo->strlen); - memcpy(s + 6 + _sst_onload_echo->strlen - 1, "\"\n", 3); - ServerCommand(engserver, s); - free(s); - } - } } #define MAX_VTABLE_FUNCS 21 diff --git a/src/vcall.h b/src/vcall.h index 778ba09..d22fe7e 100644 --- a/src/vcall.h +++ b/src/vcall.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,8 +17,6 @@ #ifndef INC_VCALL_H #define INC_VCALL_H -#include "gamedata.h" - /* * Convenient facilities for calling simple (single-table) virtual functions on * possibly-opaque pointers to C++ objects. -- cgit v1.2.3