targets={0x9b2880:'query-opaque-key'}
refs={v:[] for v in targets.values()}
for s in p.sections:
 if not s['flags']&0x20000000: continue
 b=p.data[s['raw']:s['raw']+s['rawSize']]
 i=b.find(b'\xe8')
 while i>=0 and i+5<=len(b):
  rva=s['rva']+i;target=rva+5+struct.unpack_from('<i',b,i+1)[0]
  if target in targets:
   fi=p.containing_function(rva)
   if fi is not None:
    f=p.functions[fi];instructions=list(c.disasm(p.read(f['beginRva'],f['endRva']-f['beginRva']),f['beginRva']))
    if any(x.address==rva and x.mnemonic=='call' for x in instructions):refs[targets[target]].append(dict(callRva=rva,caller=f,instructions=[dict(rva=x.address,mnemonic=x.mnemonic,operands=x.op_str) for x in instructions]))
  i=b.find(b'\xe8',i+1)
Path('src/loader/runtime/profile-tools/devdata/creative-mode-146/current-field-patch-key-callers-20261016.json').write_text(json.dumps(refs,indent=2))
for k,v in refs.items():print(k,[(hex(x['callRva']),hex(x['caller']['primaryBeginRva'])) for x in v])
