"""Hardware-only origin trace for the exact SetTeam team context. Matches the typed integer context pointer selected by SetTeam to the constructor invocation that produced it. No client memory writes. """ from __future__ import annotations from collections import deque import json import os import struct import time import traceback import gdb CONTEXT_REUSE = 0x1477C17FC CONTEXT_ALLOCATED = 0x1477C18C1 SET_TEAM_STUB = 0x147060A80 LOCKED_SETTER_RETURN = 0x1477C2415 CONTEXT_STACK_COUNT = 0x144BCEDA0 CONTEXT_STACK_ARRAY = 0x144BCEDA8 INTERESTING = {73, 130000, 130001} _STATE = None def _reg(name): return int(gdb.parse_and_eval(f"${name}")) def _read(address, size): if not address or address < 0: return None try: return bytes(gdb.selected_inferior().read_memory(address, size)) except gdb.error: return None def _u64(address): data = _read(address, 8) return struct.unpack("= 2 else None ) side_context = ( _u64(array + (count - 1) * 8) if array and count is not None and count >= 1 else None ) rsp = _reg("rsp") self.state.log( "set_team_stub_entry", context_stack_count=count, team_context=team_context, team_context_hex=(_read(team_context, 0x40) or b"").hex(), team_value=_i32(team_context + 0x10) if team_context else None, side_context=side_context, side_value=_i32(side_context + 0x10) if side_context else None, matched_origin=self.state.find_origin(team_context), caller_return_address=_u64(rsp), entry_registers={ name: _reg(name) for name in ("rcx", "rdx", "r8", "r9") }, backtrace=gdb.execute("bt 32", to_string=True), total_constructor_hits=self.state.total_constructor_hits, interesting_constructor_hits=self.state.interesting_constructor_hits, ) except Exception as exc: self.state.log( "trace_error", where="set_team_stub", error=str(exc), traceback=traceback.format_exc(), ) return False def _on_exit(event): if _STATE is not None: _STATE.log( "inferior_exited", detail=str(event), total_constructor_hits=_STATE.total_constructor_hits, interesting_constructor_hits=_STATE.interesting_constructor_hits, ) def start_trace(log_path, _cards_base): global _STATE open(log_path, "w", encoding="utf-8").close() _STATE = State(log_path) points = { "context_reuse": ContextReuseBreakpoint(_STATE, CONTEXT_REUSE), "context_allocated": ContextAllocatedBreakpoint(_STATE, CONTEXT_ALLOCATED), "set_team_stub": SetTeamStubBreakpoint(_STATE, SET_TEAM_STUB), } gdb.events.exited.connect(_on_exit) _STATE.log( "trace_armed", breakpoints={ name: {"number": point.number, "va": point.address} for name, point in points.items() }, hardware_only=True, client_memory_writes=False, matching="exact_context_pointer", )