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()