SourceMod gamedata checker.

nosoop 48fa8ed5e7 Strongly enforce type annotations 10 months ago
src 48fa8ed5e7 Strongly enforce type annotations 3 months ago
tests 094d53033e Support testing multiple versions of the game binary 3 months ago
.gitignore 2ca53b9168 Add TF2 server binary vtable test 10 months ago
.justfile f6e4a2cd4b Add mypy checking to test dir and prioritize over pytest 10 months ago
README.md f88017cf40 Change vfn constraint system to use a solver 3 months ago
pyproject.toml 48fa8ed5e7 Strongly enforce type annotations 3 months ago

README.md

smgdc

SourceMod gamedata checker.

Rewrite of a previous internal project. Faster. Stronger. More maintainable.

Usage

smgdc <specfile> --add-binary <binary> --add-binary <binary> ...

  • specfile is a specification file or directory (tree) containing specification files.
  • --add-binary specifies one or more binaries to add for checking.
    • This may be a os.pathsep-separated pair of values that map a physical file to one present in the specification file.

Specification file

A specification file is an INI configuration file used to check aspects of one or more binary (code) files.

Example:

; reports presence of a byte sequence in the Windows server binary, yielding signature
[CWeaponMedigun::SecondaryAttack()]
target = bin/tf/server.dll
type = bytesig
contents = 55 8B EC 56 8B 75 08 85 F6 0F 84 ?? ?? ?? ?? 53

; reports that a given immediate value in code is at a given location, yielding offsets, etc.
[CTFProjectile_Flare::Explode_Air()::SelfDamageRadius LINUX]
target = bin/tf/server_srv.so
type = value
symbol = _ZN19CTFProjectile_Flare11Explode_AirEP10CGameTraceib
offset = 0x468
struct = <f
assert = value == 100.0

; reports the presence of a symbol in a given vtable, yielding offset for Windows / Linux
[CBaseEntity::GetEnemy()]
target = bin/tf/server_srv.so
type = vfn
vtable = 11CBaseEntity
symbol = _ZN11CBaseEntity8GetEnemyEv

The entries specify a section name (must be unique within the file), a target binary's subpath to match against, a type of specification to check for, and additional information for a particular specification type.

This allows the validation process to be more flexible than a gameconf file is on its own, as that tells you nothing about the context (is the offset for a virtual file? a property?).

Types of specifications include:

  • value: reads out a value from a binary
  • bytesig: confirms the presence of a byte sequence
  • vfn: takes a virtual method symbol and gets the vtable index for it on Linux and Windows (guesstimate on the latter)

Constraint file

[!IMPORTANT] The constraint file specification is not finalized. Please ensure that you are reading the documentation for the version of smgdc that you are working with.

Linux binaries are sometimes compiled with flags that cause a many-to-one mapping of symbols to function addresses (in other words: link time optimization). While the application does attempt to uniquely identify symbols using other markers, there's sometimes insufficient information to do so.

A constraint file is used as a last resort for end users to manually identify which symbols map to which positions for a given virtual table and its subclasses. This is done by specifying relative ordering constraints for each symbol, allowing for reuse between binary revisions (with the assumption that vtables aren't reordered across them).

Example:

[[_ZTV17CBaseCombatWeapon]]
constraint = "soft"
symbols = [
	"_ZN17CBaseCombatWeapon6DeleteEv",
	"_ZN17CBaseCombatWeapon4KillEv",
]

[[_ZTV17CBaseCombatWeapon]]
constraint = "consecutive"
symbols = [
	"_ZN17CBaseCombatWeapon27WeaponRangeAttack1ConditionEff",
	"_ZN17CBaseCombatWeapon27WeaponRangeAttack2ConditionEff",
	"_ZN17CBaseCombatWeapon27WeaponMeleeAttack1ConditionEff",
	"_ZN17CBaseCombatWeapon27WeaponMeleeAttack2ConditionEff",
]

In this CBaseCombatWeapon vtable, a soft order constraint is applied such that the offset of CBaseCombatWeapon::Delete is lower than CBaseCombatWeapon::Kill — both symbols point to the same address, and both are present at two offsets, so this ensures that once solved, each symbol will be assigned the correct offset.

A consecutive order constraint is also applied such that CBaseCombatWeapon::WeaponRangeAttack1Condition and subsequent symbols have monotonically increasing offsets.