docs(research): #9 sweep acclient_function_map.md against PDB symbols
Pure-docs sweep. Cross-checked 63 hand-curated entries in
acclient_function_map.md against docs/research/named-retail/symbols.json
(the PDB-derived authoritative name table) using the new helper at
tools/pdb-extract/check_function_map.py.
Findings:
- Zero entries matched address-and-name exactly. Confirms the
PDB build is from a different revision than the binary that
produced our Ghidra chunks (~0x800-0xC10 byte delta varies by
function cluster). Match by NAME, not by raw address.
- 38 entries corrected by PDB name lookup. The "Was" column
preserves the old address for traceability against existing
code comments. Old entries pointed mid-body of the actual
function; new column heads point to function starts.
- 25 entries have no PDB match. Either inlined / non-public
(no S_PUB32 record) or our hand-derived names were synthesized
from call-site analysis and don't match the MSVC mangled form
in the PDB. Several had wrong class assignments (e.g. 0x5387C0
claimed as CTransition::find_collisions, actually
CPolygon::polygon_hits_sphere). Flagged for re-derivation in
acclient_2013_pseudo_c.txt.
Pattern: kept the table format with two address columns (PDB +
legacy) so existing code references using the old addresses can
still be looked up. Added a sweep-summary section at the bottom of
the file documenting the methodology + findings.
Helper script at tools/pdb-extract/check_function_map.py is reusable
for future re-runs (re-run after every PDB regeneration / function
map edit).
Closes #9.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
567078803f
commit
83b020499b
3 changed files with 296 additions and 96 deletions
149
tools/pdb-extract/check_function_map.py
Normal file
149
tools/pdb-extract/check_function_map.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
"""Cross-check acclient_function_map.md addresses against symbols.json.
|
||||
|
||||
For each row, looks up the function name in the PDB symbols table and
|
||||
flags mismatches (mid-body addresses, wrong addresses, missing names).
|
||||
|
||||
Run with:
|
||||
py tools/pdb-extract/check_function_map.py
|
||||
|
||||
Used to close ISSUES.md #9 (address-correction sweep).
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent.parent
|
||||
SYMBOLS = REPO / "docs" / "research" / "named-retail" / "symbols.json"
|
||||
|
||||
# (claimed_address, qualified_name) tuples from acclient_function_map.md.
|
||||
# Format: lowercase hex no leading 0, then the demangled Class::Method.
|
||||
ENTRIES = [
|
||||
# CPhysicsObj
|
||||
("515020", "CPhysicsObj::update_object"),
|
||||
("5111d0", "CPhysicsObj::UpdatePhysicsInternal"),
|
||||
("511420", "CPhysicsObj::calc_acceleration"),
|
||||
("511ec0", "CPhysicsObj::set_velocity"),
|
||||
("511fa0", "CPhysicsObj::set_local_velocity"),
|
||||
("511de0", "CPhysicsObj::set_on_walkable"),
|
||||
("511560", "CPhysicsObj::report_collision_start"),
|
||||
("513ac0", "CPhysicsObj::report_collision_end"),
|
||||
("513b60", "CPhysicsObj::handle_obj_collision"),
|
||||
("515280", "CPhysicsObj::handle_collision"),
|
||||
("513730", "CPhysicsObj::UpdatePositionInternal"),
|
||||
("50f940", "CPhysicsObj::calc_friction"),
|
||||
("510080", "CPhysicsObj::check_contact_velocity"),
|
||||
# CMotionInterp
|
||||
("5286b0", "CMotionInterp::get_jump_v_z"),
|
||||
("528660", "CMotionInterp::jump_charge_is_allowed"),
|
||||
("5285e0", "CMotionInterp::motion_allows_jump"),
|
||||
("528ec0", "CMotionInterp::jump_is_allowed"),
|
||||
("528cd0", "CMotionInterp::get_leave_ground_velocity"),
|
||||
("529390", "CMotionInterp::jump"),
|
||||
("529710", "CMotionInterp::LeaveGround"),
|
||||
("5296d0", "CMotionInterp::HitGround"),
|
||||
("528960", "CMotionInterp::get_state_velocity"),
|
||||
("528a50", "CMotionInterp::StopCompletely"),
|
||||
("5287f0", "CMotionInterp::adjust_motion"),
|
||||
("5293f0", "CMotionInterp::apply_raw_movement"),
|
||||
("529210", "CMotionInterp::apply_current_movement"),
|
||||
("528dd0", "CMotionInterp::contact_allows_move"),
|
||||
("528f70", "CMotionInterp::DoInterpretedMotion"),
|
||||
("529080", "CMotionInterp::StopInterpretedMotion"),
|
||||
("529140", "CMotionInterp::StopMotion"),
|
||||
("529930", "CMotionInterp::DoMotion"),
|
||||
("529a90", "CMotionInterp::PerformMovement"),
|
||||
# CLandBlockStruct
|
||||
("531d10", "CLandBlockStruct::IsSWtoNECut"),
|
||||
("532a50", "CLandBlockStruct::ConstructPolygons"),
|
||||
("532eb0", "CLandBlockStruct::ConstructUVs"),
|
||||
("532d10", "CLandBlockStruct::unpack"),
|
||||
("531f10", "CLandBlockStruct::get_packed_size"),
|
||||
("532440", "CLandBlockStruct::AdjustPlanes"),
|
||||
("532290", "CLandBlockStruct::CalcCellWater"),
|
||||
# CLandBlock
|
||||
("530690", "CLandBlock::Init"),
|
||||
("5307e0", "CLandBlock::release_all"),
|
||||
("531780", "CLandBlock::init_static_objs"),
|
||||
("531000", "CLandBlock::release_visible_cells"),
|
||||
("5301e0", "CLandBlock::grab_visible_cells"),
|
||||
("530650", "CLandBlock::add_server_object"),
|
||||
# LandDefs
|
||||
("5aaa30", "CLandDefs::get_vars"),
|
||||
("5aabb0", "CLandDefs::get_outside_lcoord"),
|
||||
("5aac70", "CLandDefs::AdjustToOutside"),
|
||||
("5aab50", "CLandDefs::get_block_dir"),
|
||||
# Collision / Transition (some entries are CCylSphere / CSphere / CTransition / CPolygon)
|
||||
("5384e0", "CSphere::SphereIntersectsRay"),
|
||||
("539500", "CPolygon::sphere_intersects_poly"),
|
||||
("539750", "CPolygon::sphere_intersects_solid"),
|
||||
("539ba0", "CPolygon::find_time_of_collision"),
|
||||
("539df0", "CPolygon::find_time_of_collision"),
|
||||
("53a040", "CPolygon::find_walkable_collision"),
|
||||
("539110", "CPolygon::calc_normal"),
|
||||
("539060", "CPlane::ray_plane_intersect"),
|
||||
("538eb0", "CSphere::slide_sphere"),
|
||||
("538f50", "CSphere::land_on_sphere"),
|
||||
("538180", "CTransition::collide_with_point"),
|
||||
("5387c0", "CTransition::find_collisions"),
|
||||
("53a230", "CPolygon::hits_walkable"),
|
||||
# PhysicsEngine
|
||||
("452a10", "PhysicsEngine::update"),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
with open(SYMBOLS, "r", encoding="utf-8") as f:
|
||||
symbols = json.load(f)
|
||||
|
||||
# Build name -> [addresses] (some names appear multiple times: overloads)
|
||||
by_name = {}
|
||||
for s in symbols:
|
||||
by_name.setdefault(s["name"], []).append(s["address"])
|
||||
|
||||
# Build address -> name (lowercase hex without 0x prefix)
|
||||
by_addr = {}
|
||||
for s in symbols:
|
||||
addr = s["address"][2:].lower().lstrip("0") or "0"
|
||||
by_addr[addr] = s["name"]
|
||||
|
||||
confirmed = 0
|
||||
addr_corrections = []
|
||||
name_misses = []
|
||||
for claimed_addr, claimed_name in ENTRIES:
|
||||
# Look up by name
|
||||
if claimed_name in by_name:
|
||||
pdb_addrs = by_name[claimed_name]
|
||||
normalized_claimed = claimed_addr.lower().lstrip("0") or "0"
|
||||
match = any(
|
||||
(a[2:].lower().lstrip("0") or "0") == normalized_claimed
|
||||
for a in pdb_addrs
|
||||
)
|
||||
if match:
|
||||
confirmed += 1
|
||||
else:
|
||||
addr_corrections.append((claimed_addr, claimed_name, pdb_addrs))
|
||||
else:
|
||||
# Name not found exactly. Try the claimed address as fallback.
|
||||
normalized_claimed = claimed_addr.lower().lstrip("0") or "0"
|
||||
actual_name = by_addr.get(normalized_claimed)
|
||||
name_misses.append((claimed_addr, claimed_name, actual_name))
|
||||
|
||||
print(f"Confirmed (address + name match): {confirmed}/{len(ENTRIES)}")
|
||||
print()
|
||||
if addr_corrections:
|
||||
print("ADDRESS CORRECTIONS (name correct, address wrong — likely mid-body):")
|
||||
for claimed_addr, name, pdb_addrs in addr_corrections:
|
||||
print(f" 0x{claimed_addr.upper()} {name}")
|
||||
print(f" actual: {', '.join(pdb_addrs)}")
|
||||
print()
|
||||
if name_misses:
|
||||
print("NAME MISMATCHES (name not found by exact match in PDB):")
|
||||
for claimed_addr, name, actual_name in name_misses:
|
||||
print(f" 0x{claimed_addr.upper()} {name}")
|
||||
if actual_name:
|
||||
print(f" PDB at 0x{claimed_addr.upper()}: {actual_name}")
|
||||
else:
|
||||
print(f" PDB has no symbol at 0x{claimed_addr.upper()}")
|
||||
print()
|
||||
|
||||
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue