File size: 8,591 Bytes
2e203a0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #!/usr/bin/env python3
"""Bounded finite bounds/radius composition, inline removal and leaf-return gates."""
import gzip
import itertools
import json
from pathlib import Path
import re
from analyze_area_queries import site,run
from analyze_chat_crosshair import bits,number
from analyze_collision_composition import get_word,put_word
from analyze_engine_control import control_flow
from analyze_frame_timing import read_address
from analyze_native import elf
from analyze_qvm import write_json
from analyze_vm_extensions import native_functions,verified
from analyze_world_links import vector
def main():
out={'native':{},'limitations':'Synthetic finite lower-32-bit SSE/integer slices with supplied object '
'fields, server records and native return values. Radius helper is evaluated separately and its '
'result explicitly injected at the caller return boundary; no original process/native call/full '
'link pipeline executes. ABI/allocation/lifecycle, BSP metadata, exceptional floats/MXCSR and '
'original-runtime/all-platform conformance remain open.'}
obj,record,stack=0x10000,0x20000,0x40000
for label in ['linux--Quake3-UrT-Ded.x86_64','linux--Quake3-UrT.x86_64']:
r=json.loads(Path(f'docs/research/native/{label}.json').read_text());data=verified((Path('.cache/UrbanTerror43')/r['source']['path']).read_bytes(),r['source']['sha256'])
a=r['artifacts']['disassembly.txt'];fs=native_functions(verified(gzip.open(a['path'],'rb').read(),a['uncompressed_sha256']).decode())
graphs={n:control_flow(fs[n]) for n in ['SV_LinkEntity','SV_UnlinkEntity','RadiusFromBounds']};g=graphs['SV_LinkEntity'];rows=g['instructions'];metadata,_=elf(data)
constants=[];constant_memory={}
for name,graph in graphs.items():
for x in graph['instructions']:
if x['opcode']=='movss' and '(%rip)' in x['operands']:
address=int(re.search(r'#\s*0x([0-9a-f]+)',x['operands'])[1],16);raw,off=read_address(data,metadata['sections'],address,4)
value=int.from_bytes(raw,'little');put_word(constant_memory,address,value)
constants.append({'function':name,'instruction':x['address'],'address':address,'file_offset':off,'bits':value})
def call_sites(name):return [i for i,x in enumerate(rows) if x['opcode']=='callq' and '<'+name+'>' in x['operands']]
radius_calls=call_sites('RadiusFromBounds');leaf_calls=call_sites('CM_BoxLeafnums')
if len(radius_calls)!=1 or len(leaf_calls)!=1:raise ValueError('bound call count changed')
radius_call=rows[radius_calls[0]]['address'];after_radius=rows[radius_calls[0]+1]['address'];leaf_call=rows[leaf_calls[0]]['address'];after_leaf=rows[leaf_calls[0]+1]['address']
start=site(g,'movl','0x1b0(%rbx), %esi');cleanup=site(g,'addq','$0x228, %rsp')
bounds=[];fixtures=[([-3,-4,0],[3,4,0]),([-1,-2,-2],[2,1,1]),([0,0,0],[0,0,0])]
for (low,high),origin,model,angles in itertools.product(fixtures,[[0,0,0],[10,-20,30]],[0,1,4],[[0,0,0],[-0.0,0,0],[90,0,0],[0,90,0],[0,0,90]]):
m=dict(constant_memory);put_word(m,obj+0x1b0,model)
for base,v in [(0x1b4,low),(0x1c0,high),(0x1e8,origin),(0x1f4,angles)]:
for axis,value in enumerate(v):put_word(m,obj+base+4*axis,bits(value))
t=run(g,start,[radius_call,leaf_call],m,{'%rbx':obj,'%r12':record,'%rsp':stack});trace=list(t['trace']);radius=None;radius_trace=[]
if t['stop']==radius_call:
rg=graphs['RadiusFromBounds'];end=next(x['address'] for x in rg['instructions'] if x['opcode']=='retq')
rt=run(rg,rg['entry'],[end],t['memory'],{'%rdi':t['registers']['rdi'],'%rsi':t['registers']['rsi']})
radius=number(rt['registers']['xmm0']);radius_trace=rt['trace'];regs=t['registers'];regs['xmm0']=rt['registers']['xmm0']
t=run(g,after_radius,[leaf_call],t['memory'],regs);trace+=t['trace']
regs=t['registers'];m=t['memory']
bounds.append({'local_min':low,'local_max':high,'origin':origin,'model_word':model,'angles':angles,
'radius_path':radius is not None,'radius':radius,'radius_trace':radius_trace,'trace':trace,
'absolute_min':vector(m,obj+0x1d0),'absolute_max':vector(m,obj+0x1dc),
'metadata_words':{str(offset):get_word(m,record+offset) for offset in [0xe0,0x124,0x128,0x12c]},
'leaf_request':{'min_pointer':regs['rdi'],'max_pointer':regs['rsi'],'output_pointer':regs['rdx'],
'capacity':regs['rcx'],'extra_pointer':regs['r8']},'writes':t['writes']})
# Leaf count is an isolated supplied callee return, with first leaf/top-node words supplied.
first_area=rows[call_sites('CM_LeafArea')[0]]['address'];leaf_cluster_sites=call_sites('CM_LeafCluster');negative_cluster=rows[leaf_cluster_sites[-1]]['address']
leaf_returns=[]
for count in [-1,0,1,127,128,129]:
m={};put_word(m,stack+0x10,17);put_word(m,stack+0x21c,29)
t=run(g,after_leaf,[cleanup,first_area,negative_cluster],m,{'%rax':count,'%rsp':stack,'%r12':record})
leaf_returns.append({'supplied_count':count,'path':'cleanup' if t['stop']==cleanup else 'first_area' if t['stop']==first_area else 'fallback_cluster',
'saved_count_bits':get_word(t['memory'],stack+12),'requested_leaf':t['registers'].get('rdi'),
'trace':t['trace'],'writes':t['writes']})
# Inline removal begins after first lookup. Owned records request a second lookup;
# stop it and inject the same supplied record before evaluating the removal body.
lookup=call_sites('SV_SvEntityForGentity')
if len(lookup)!=2:raise ValueError('lookup prelude changed')
prelude_start=rows[lookup[0]+1]['address'];second_lookup=rows[lookup[1]]['address'];after_second_lookup=rows[lookup[1]+1]['address']
metadata_start=site(g,'movl','0x1b0(%rbx), %ecx');warning_call=next(x['address'] for x in rows if x['opcode']=='callq' and '<Com_Printf>' in x['operands'])
node=0x60000;records=[0x70000+i*312 for i in range(4)];inline=[]
for name,order,target,owner in [('no_owner',[0,1,2],1,0),('head',[0,1,2],0,node),('middle',[0,1,2],1,node),('tail',[0,1,2],2,node),('only',[0],0,node),('missing',[0,1,2],3,node),('empty',[],3,node)]:
m={};put_word(m,obj+0x1a0,1);put_word(m,node+24,records[order[0]] if order else 0,8)
for i,p in enumerate(records):put_word(m,p,node,8);put_word(m,p+8,records[i+1] if i<3 else 0,8)
if order:put_word(m,records[order[-1]]+8,0,8)
put_word(m,records[target],owner,8)
t=run(g,prelude_start,[second_lookup,metadata_start],m,{'%rbx':obj,'%rax':records[target]});trace=list(t['trace']);requested=t['stop']==second_lookup
if requested:
regs=t['registers'];regs['rax']=records[target]
t=run(g,after_second_lookup,[metadata_start,warning_call],t['memory'],regs);trace+=t['trace']
cursor=get_word(t['memory'],node+24,8);remaining=[]
while cursor:
if cursor in remaining or len(remaining)>4:raise ValueError('inline fixture cycle')
remaining.append(cursor);cursor=get_word(t['memory'],cursor+8,8)
inline.append({'case':name,'target_index':target,'second_lookup_requested':requested,'warning_requested':t['stop']==warning_call,
'remaining_indices':[records.index(p) for p in remaining],'owner_after':get_word(t['memory'],records[target],8),
'next_after':get_word(t['memory'],records[target]+8,8),'linked_word':get_word(t['memory'],obj+0x1a0),'trace':trace})
out['native'][label]={'source':r['source'],'disassembly_sha256':a['uncompressed_sha256'],'graphs':graphs,
'constants':constants,'sites':{'bounds_start':start,'radius_call':radius_call,'after_radius_call':after_radius,'leaf_call':leaf_call,
'after_leaf_call':after_leaf,'first_area_call':first_area,'fallback_cluster_call':negative_cluster,'cleanup':cleanup,
'inline_start':prelude_start,'second_lookup':second_lookup,'metadata_start':metadata_start,'warning_call':warning_call},
'bounds_compositions':bounds,'leaf_return_traces':leaf_returns,'inline_removal_compositions':inline}
write_json(Path('docs/research/link-bounds.json'),out)
print('Recovered 180 finite bound/radius, 12 leaf-return and 14 inline-removal compositions')
if __name__=='__main__':main()
|