yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
368ddbb7b
master
1# InstTrace Debugging Utility 2# 3# This script is used to trace the callstack at the creation of a specific IR instruction in the Slang compiler. 4# This is useful for debugging purposes, especially if you encounter a compiler bug related to an instruction 5# that appears to be incorrect, and you want to find out where it was created in the codebase. 6# 7# Usage: python3 ./extras/insttrace.py <inst UID> <commandline_to_slangc_or_slang-test> 8# 9# The script will print the callstack at the point where the specified instruction was created. 10# <inst UID> is the unique identifier of the instruction you want to trace, which can be found by inspecting 11# the _debugUID field of an IRInst object in the Slang compiler source code. 12# If the instruction is a clone of another instruction, it will also trace the creation of the original instruction 13# recursively. 14 15import sys 16import subprocess 17import re 18import os 19 20def traceInst (inst_uid ,command ): 21# Run the command with the provided arguments 22# Set the environment variable SLANG_IR_ALLOC_BREAK to the instruction UID 23env = dict (os .environ ,SLANG_DEBUG_IR_BREAK = inst_uid ) 24process = subprocess .Popen (command ,stdout = subprocess .PIPE ,stderr = subprocess .PIPE ,env = env ) 25stdout ,stderr = process .communicate () 26 27# Parse the output to find the string between "BEGIN IR Trace" and "END IR Trace" 28ir_trace = re .search (r"BEGIN IR Trace(.*?)END IR Trace" ,stdout .decode (encoding = 'utf-8' ,errors = 'ignore' ),re .DOTALL ) 29if not ir_trace : 30"No IR Trace found in the output." ) 31return 32 33traceOutput = ir_trace .group (1 ) 34regex = r"(\S+)\(\+(0x[0-9a-f]+)\) \[0x[0-9a-f]+\]" 35 36lines = traceOutput .splitlines () 37 38# First, collect all addresses grouped by library file for batching 39lib_addresses = {}# libFile -> list of addresses 40line_info = []# (line, libFile, address) for each line 41 42for line in lines : 43match = re .search (regex ,line ) 44if match : 45libFile = match .group (1 ) 46address = match .group (2 ) 47line_info .append ((line ,libFile ,address )) 48 49if libFile not in lib_addresses : 50lib_addresses [libFile ]= [] 51lib_addresses [libFile ].append (address ) 52else : 53line_info .append ((line ,None ,None )) 54 55# Batch call addr2line for each library file 56address_to_symbol = {}# (libFile, address) -> symbol info 57 58for libFile ,addresses in lib_addresses .items (): 59if not addresses : 60continue 61 62# Call addr2line once with all addresses for this library 63addr2line_command = ["addr2line" ,"-e" ,libFile ,"-f" ,"-C" ]+ addresses 64try : 65addr2line_process = subprocess .Popen (addr2line_command ,stdout = subprocess .PIPE ,stderr = subprocess .PIPE ) 66stdout ,stderr = addr2line_process .communicate () 67 68# Parse the output - addr2line returns function name and location for each address 69output_lines = stdout .decode (encoding = 'utf-8' ,errors = 'ignore' ).strip ().split ('\n' ) 70 71# Each address produces 2 lines: function name, then file:line 72for i ,address in enumerate (addresses ): 73if i * 2 + 1 < len (output_lines ): 74function_name = output_lines [i * 2 ].strip () 75location = output_lines [i * 2 + 1 ].strip () 76symbol_info = f" { function_name } { location } " 77address_to_symbol [(libFile ,address )]= symbol_info 78else : 79address_to_symbol [(libFile ,address )]= f"<unknown> { address } " 80except Exception as e : 81# Fallback if addr2line fails 82for address in addresses : 83address_to_symbol [(libFile ,address )]= f"<addr2line failed> { address } " 84 85# Now print the results using the cached symbol information 86for line ,libFile ,address in line_info : 87if libFile and address : 88symbol_info = address_to_symbol .get ((libFile ,address ),f"<not found> { address } " ) 89symbol_info ) 90else : 91# print the line as is if it doesn't match the address format 92line ) 93 94"(end of stacktrace)" ) 95 96# Find "Inst #%u is a clone of Inst #%u" in the trace output, and trace the original instruction 97# if it exists. 98clone_match = re .search (r"Inst #(\d+) is a clone of Inst #(\d+)" ,traceOutput ) 99if clone_match : 100clone_inst_uid = clone_match .group (1 ) 101original_inst_uid = clone_match .group (2 ) 102traceInst (original_inst_uid ,command ) 103 104def main (): 105if len (sys .argv )< 3 : 106"InstTrace Debugging Utility" ) 107"Usage: python insttrace.py <inst UID> <commandline_to_slangc_or_slang-test>" ) 108sys .exit (1 ) 109 110inst_uid = sys .argv [1 ] 111command = sys .argv [2 :] 112traceInst (inst_uid ,command ) 113 114if __name__ == "__main__" : 115main ()