# used to debug in pycharm DEBUG = 1 def connect_debug_server(): import sys sys.path.append("F:/Software/JetBrains/PyCharm 2022.1.2/debug-eggs/pydevd-pycharm.egg") import pydevd_pycharm pydevd_pycharm.settrace('localhost', port=12345, stdoutToServer=True, stderrToServer=True) if DEBUG: connect_debug_server() import ida_funcs import ida_typeinf import ida_hexrays import ida_lines import idc import struct from collections import OrderedDict def u64(data, start=0): return struct.unpack(" max_code: max_code = opcode if opcode not in code_dic: code_dic[opcode] = 1 else: code_dic[opcode] += 1 count = code_dic[opcode] if count > max_sub_code: max_sub_code = count return max_code, max_sub_code def get_proxy_func_name(gnm_name): name = 'GnmCommandProxy::{}'.format(gnm_name) return name def get_code_name(opcode): op_dic = { 0x00000010: 'IT_NOP', 0x00000011: 'IT_SET_BASE', 0x00000012: 'IT_CLEAR_STATE', 0x00000013: 'IT_INDEX_BUFFER_SIZE', 0x00000015: 'IT_DISPATCH_DIRECT', 0x00000016: 'IT_DISPATCH_INDIRECT', 0x00000017: 'IT_INDIRECT_BUFFER_END', 0x00000019: 'IT_INDIRECT_BUFFER_CNST_END', 0x0000001d: 'IT_ATOMIC_GDS', 0x0000001e: 'IT_ATOMIC_MEM', 0x0000001f: 'IT_OCCLUSION_QUERY', 0x00000020: 'IT_SET_PREDICATION', 0x00000021: 'IT_REG_RMW', 0x00000022: 'IT_COND_EXEC', 0x00000023: 'IT_PRED_EXEC', 0x00000024: 'IT_DRAW_INDIRECT', 0x00000025: 'IT_DRAW_INDEX_INDIRECT', 0x00000026: 'IT_INDEX_BASE', 0x00000027: 'IT_DRAW_INDEX_2', 0x00000028: 'IT_CONTEXT_CONTROL', 0x0000002a: 'IT_INDEX_TYPE', 0x0000002c: 'IT_DRAW_INDIRECT_MULTI', 0x0000002d: 'IT_DRAW_INDEX_AUTO', 0x0000002f: 'IT_NUM_INSTANCES', 0x00000030: 'IT_DRAW_INDEX_MULTI_AUTO', 0x00000032: 'IT_INDIRECT_BUFFER_PRIV', 0x00000033: 'IT_INDIRECT_BUFFER_CNST', # 0x00000033: 'IT_COND_INDIRECT_BUFFER_CNST', 0x00000034: 'IT_STRMOUT_BUFFER_UPDATE', 0x00000035: 'IT_DRAW_INDEX_OFFSET_2', 0x00000036: 'IT_DRAW_PREAMBLE', 0x00000037: 'IT_WRITE_DATA', 0x00000038: 'IT_DRAW_INDEX_INDIRECT_MULTI', 0x00000039: 'IT_MEM_SEMAPHORE', 0x0000003a: 'IT_DRAW_INDEX_MULTI_INST', 0x0000003b: 'IT_COPY_DW', 0x0000003c: 'IT_WAIT_REG_MEM', 0x0000003f: 'IT_INDIRECT_BUFFER', # 0x0000003f: 'IT_COND_INDIRECT_BUFFER', 0x00000040: 'IT_COPY_DATA', 0x00000041: 'IT_CP_DMA', 0x00000042: 'IT_PFP_SYNC_ME', 0x00000043: 'IT_SURFACE_SYNC', 0x00000044: 'IT_ME_INITIALIZE', 0x00000045: 'IT_COND_WRITE', 0x00000046: 'IT_EVENT_WRITE', 0x00000047: 'IT_EVENT_WRITE_EOP', 0x00000048: 'IT_EVENT_WRITE_EOS', 0x00000049: 'IT_RELEASE_MEM', 0x0000004a: 'IT_PREAMBLE_CNTL', 0x0000004c: 'IT_DRAW_RESERVED0', 0x0000004d: 'IT_DRAW_RESERVED1', 0x0000004e: 'IT_DRAW_RESERVED2', 0x0000004f: 'IT_DRAW_RESERVED3', 0x00000050: 'IT_DMA_DATA', 0x00000051: 'IT_CONTEXT_REG_RMW', 0x00000052: 'IT_GFX_CNTX_UPDATE', 0x00000053: 'IT_BLK_CNTX_UPDATE', 0x00000055: 'IT_INCR_UPDT_STATE', 0x00000058: 'IT_ACQUIRE_MEM', 0x00000059: 'IT_REWIND', 0x0000005a: 'IT_INTERRUPT', 0x0000005b: 'IT_GEN_PDEPTE', 0x0000005c: 'IT_INDIRECT_BUFFER_PASID', 0x0000005d: 'IT_PRIME_UTCL2', 0x0000005e: 'IT_LOAD_UCONFIG_REG', 0x0000005f: 'IT_LOAD_SH_REG', 0x00000060: 'IT_LOAD_CONFIG_REG', 0x00000061: 'IT_LOAD_CONTEXT_REG', 0x00000062: 'IT_LOAD_COMPUTE_STATE', 0x00000063: 'IT_LOAD_SH_REG_INDEX', 0x00000068: 'IT_SET_CONFIG_REG', 0x00000069: 'IT_SET_CONTEXT_REG', 0x0000006a: 'IT_SET_CONTEXT_REG_INDEX', 0x00000071: 'IT_SET_VGPR_REG_DI_MULTI', 0x00000072: 'IT_SET_SH_REG_DI', 0x00000073: 'IT_SET_CONTEXT_REG_INDIRECT', 0x00000074: 'IT_SET_SH_REG_DI_MULTI', 0x00000075: 'IT_GFX_PIPE_LOCK', 0x00000076: 'IT_SET_SH_REG', 0x00000077: 'IT_SET_SH_REG_OFFSET', 0x00000078: 'IT_SET_QUEUE_REG', 0x00000079: 'IT_SET_UCONFIG_REG', 0x0000007a: 'IT_SET_UCONFIG_REG_INDEX', 0x0000007c: 'IT_FORWARD_HEADER', 0x0000007d: 'IT_SCRATCH_RAM_WRITE', 0x0000007e: 'IT_SCRATCH_RAM_READ', 0x00000080: 'IT_LOAD_CONST_RAM', 0x00000081: 'IT_WRITE_CONST_RAM', 0x00000083: 'IT_DUMP_CONST_RAM', 0x00000084: 'IT_INCREMENT_CE_COUNTER', 0x00000085: 'IT_INCREMENT_DE_COUNTER', 0x00000086: 'IT_WAIT_ON_CE_COUNTER', 0x00000088: 'IT_WAIT_ON_DE_COUNTER_DIFF', 0x0000008b: 'IT_SWITCH_BUFFER', 0x00000090: 'IT_FRAME_CONTROL', 0x00000091: 'IT_INDEX_ATTRIBUTES_INDIRECT', 0x00000093: 'IT_WAIT_REG_MEM64', 0x00000094: 'IT_COND_PREEMPT', 0x00000095: 'IT_HDP_FLUSH', 0x00000098: 'IT_INVALIDATE_TLBS', 0x0000009a: 'IT_DMA_DATA_FILL_MULTI', 0x0000009b: 'IT_SET_SH_REG_INDEX', 0x0000009c: 'IT_DRAW_INDIRECT_COUNT_MULTI', 0x0000009d: 'IT_DRAW_INDEX_INDIRECT_COUNT_MULTI', 0x0000009e: 'IT_DUMP_CONST_RAM_OFFSET', 0x0000009f: 'IT_LOAD_CONTEXT_REG_INDEX', 0x000000a0: 'IT_SET_RESOURCES', 0x000000a1: 'IT_MAP_PROCESS', 0x000000a2: 'IT_MAP_QUEUES', 0x000000a3: 'IT_UNMAP_QUEUES', 0x000000a4: 'IT_QUERY_STATUS', 0x000000a5: 'IT_RUN_LIST', 0x000000a6: 'IT_MAP_PROCESS_VM', 0x0000008c: 'IT_DISPATCH_DRAW_PREAMBLE__GFX09', # 0x0000008c: 'IT_DISPATCH_DRAW_PREAMBLE_ACE__GFX09', # 0x0000008d: 'IT_DISPATCH_DRAW__GFX09', # 0x0000008d: 'IT_DISPATCH_DRAW_ACE__GFX09', 0x0000008e: 'IT_GET_LOD_STATS__GFX09', 0x0000008f: 'IT_DRAW_MULTI_PREAMBLE__GFX09', # 0x00000099: 'IT_AQL_PACKET__GFX09', # 0x0000008c: 'IT_DISPATCH_DRAW_PREAMBLE__GFX101', # 0x0000008c: 'IT_DISPATCH_DRAW_PREAMBLE_ACE__GFX101', # 0x0000008d: 'IT_DISPATCH_DRAW__GFX101', # 0x0000008d: 'IT_DISPATCH_DRAW_ACE__GFX101', # 0x0000008f: 'IT_DRAW_MULTI_PREAMBLE__GFX101', # 0x00000099: 'IT_AQL_PACKET__GFX101', } name = '' if opcode not in op_dic: name = 'IT_UNKNOWN_{:X}'.format(opcode) else: name = op_dic[opcode] return name def write_function_array(table): op_dic = {} for (gnm_name, packet_count, pm4type, opcode, handler, code_lines) in table: if opcode not in op_dic: op_dic[opcode] = [] proxy_name = get_proxy_func_name(gnm_name) op_dic[opcode].append(proxy_name) ordered_table = OrderedDict(sorted(op_dic.items(), key=lambda obj: obj[0])) fout = open('PacketArray.cpp', 'w') max_code, max_sub_code = get_max_code(table) head = 'const std::array, {}> m_proxyTable = {{ {{\n'.format(max_sub_code + 1, max_code + 1) fout.write(head) last_opcode = -1 for opcode, proxy_list in ordered_table.items(): for i in range(last_opcode + 1, opcode): fout.write('\t// {}\n'.format(get_code_name(i))) fout.write('\t{ nullptr },\n') last_opcode = opcode fout.write('\t// {}\n'.format(get_code_name(opcode))) fout.write('\t{\n') for proxy_func in proxy_list: fout.write('\t\t&{},\n'.format(proxy_func)) fout.write('\t\tnullptr,\n') fout.write('\t},\n') fout.write('\n') fout.write('} };\n') fout.close() def get_comment_func_body(code_lines): # get function body body = code_lines[2:-1] comment = ['// ' + line + '\n' for line in body] return comment def recover_gnm_name(name): if name[-1].isdigit(): name = name[:-1] return name def define_proxy_function(name, code): lines = [] lines.append('uint32_t {}(PPM4_TYPE_3_HEADER pm4Hdr)\n'.format(get_proxy_func_name(name))) lines.append('{\n') comments = get_comment_func_body(code) for comment in comments: lines.append('\t' + comment) lines.append('\n') lines.append('\t' + 'uint32_t count = 0;\n') lines.append('\t' + 'if (false)\n') lines.append('\t' + '{\n') lines.append('\t\t' + 'LOG_SCE_TRACE("Gnm: {}");\n'.format(recover_gnm_name(name))) lines.append('\t\t' + '// m_cb->{}();\n'.format(recover_gnm_name(name))) lines.append('\t\t' + 'count = {};\n'.format(get_enum_name(name))) lines.append('\t' + '}\n') lines.append('\n') lines.append('\t' + 'return count;\n') lines.append('}\n') return lines def write_proxy_function_list(table): fout = open('PacketProxy.cpp', 'w') for (gnm_name, packet_count, pm4type, opcode, handler, code_lines) in table: proxy_func = define_proxy_function(gnm_name, code_lines) fout.write(''.join(proxy_func)) fout.write('\n') fout.close() def process_table(func_table): table = filter_table(func_table) write_packet_count_enum(table) write_proxy_function_list(table) write_function_array(table) def run(): # PS4RazorGPUDLL.dll # Version: 8.0.0.2 # MD5: EBB9C82A6F451F0BA240BE17B0DC78A8 # Offset: 2C6BC0 (base 0) init_handler_table print('pm4 handler parse begin.') # handler_table = [0x7FFC806E1120,0x7FFC806E1128,0x7FFC806E1130,0x7FFC806E1138,0x7FFC806E1140,0x7FFC806E1148] handler_table = [0x7FFC806E1120, 0x7FFC806E1128, 0x7FFC806E1130] func_table = [] for table in handler_table: print('parse table:{:08X}'.format(table)) print('================') func_table += parse_table(table) process_table(func_table) print('pm4 handler parse end.') run()