22from typing import List , Mapping , Tuple , Iterator
33
44from binaryninja import DisassemblyTextLine , LinearDisassemblyLineType , Function , \
5- LowLevelILInstruction , TypeClass , DisassemblyTextRenderer , MediumLevelILFunction , \
5+ LowLevelILInstruction , LowLevelILOperation , TypeClass , DisassemblyTextRenderer , MediumLevelILFunction , \
66 MediumLevelILCallSsa , MediumLevelILVarSsa , MediumLevelILConstBase , \
77 MediumLevelILInstruction , MediumLevelILTailcallSsa , MediumLevelILOperation , \
8- MediumLevelILVarPhi , log_debug
9- from binaryninja import RenderLayer , BasicBlock , InstructionTextTokenType , FlowGraph , \
8+ MediumLevelILVarPhi , log_debug , RenderLayer , BasicBlock , InstructionTextTokenType , FlowGraph , \
109 LinearViewObject , LinearDisassemblyLine
1110
1211"""
@@ -133,7 +132,13 @@ def apply_to_disassembly_block(
133132 lines : List ['DisassemblyTextLine' ]
134133 ):
135134 renderer = DisassemblyTextRenderer (block .function )
135+
136+ # So we don't process lines twice since we're iterating over a list as we modify it
136137 skip_lines = []
138+
139+ # Tailcalls that don't return incorrectly mark the { Does not return } line as a call
140+ ignore_calls = set ()
141+
137142 for i , line in enumerate (lines ):
138143 if len (line .tokens ) == 0 :
139144 continue
@@ -153,6 +158,27 @@ def apply_to_disassembly_block(
153158 line .tokens = line .tokens [:j ]
154159 break
155160
161+ if llil_instr .address == line .address and llil_instr .address not in ignore_calls :
162+ if llil_instr .operation in [
163+ LowLevelILOperation .LLIL_CALL ,
164+ LowLevelILOperation .LLIL_CALL_SSA ,
165+ LowLevelILOperation .LLIL_TAILCALL ,
166+ LowLevelILOperation .LLIL_TAILCALL_SSA
167+ ]:
168+ ignore_calls .add (llil_instr .address )
169+ if llil_instr .operation in [
170+ LowLevelILOperation .LLIL_TAILCALL ,
171+ LowLevelILOperation .LLIL_TAILCALL_SSA
172+ ]:
173+ comment = f"Tailcall at { llil_instr .address :#x} "
174+ else :
175+ comment = f"Call at { llil_instr .address :#x} "
176+ renderer .wrap_comment (new_lines , line , comment , False , " " , "" )
177+ for j , token in enumerate (line .tokens ):
178+ if token .type == InstructionTextTokenType .AddressSeparatorToken :
179+ line .tokens = line .tokens [:j ]
180+ break
181+
156182 if len (new_lines ) > 0 :
157183 lines .pop (i )
158184 for j , new_line in enumerate (new_lines ):
@@ -165,7 +191,13 @@ def apply_to_low_level_il_block(
165191 lines : List ['DisassemblyTextLine' ]
166192 ):
167193 renderer = DisassemblyTextRenderer (block .function )
194+
195+ # So we don't process lines twice since we're iterating over a list as we modify it
168196 skip_lines = []
197+
198+ # Tailcalls that don't return incorrectly mark the { Does not return } line as a call
199+ ignore_calls = set ()
200+
169201 for i , line in enumerate (lines ):
170202 if len (line .tokens ) == 0 :
171203 continue
@@ -184,6 +216,27 @@ def apply_to_low_level_il_block(
184216 line .tokens = line .tokens [:j ]
185217 break
186218
219+ if line .il_instruction .address == line .address and line .il_instruction .address not in ignore_calls :
220+ if line .il_instruction .operation in [
221+ LowLevelILOperation .LLIL_CALL ,
222+ LowLevelILOperation .LLIL_CALL_SSA ,
223+ LowLevelILOperation .LLIL_TAILCALL ,
224+ LowLevelILOperation .LLIL_TAILCALL_SSA
225+ ]:
226+ ignore_calls .add (line .il_instruction .address )
227+ if line .il_instruction .operation in [
228+ LowLevelILOperation .LLIL_TAILCALL ,
229+ LowLevelILOperation .LLIL_TAILCALL_SSA
230+ ]:
231+ comment = f"Tailcall at { line .il_instruction .address :#x} "
232+ else :
233+ comment = f"Call at { line .il_instruction .address :#x} "
234+ renderer .wrap_comment (new_lines , line , comment , False , " " , "" )
235+ for j , token in enumerate (line .tokens ):
236+ if token .type == InstructionTextTokenType .AddressSeparatorToken :
237+ line .tokens = line .tokens [:j ]
238+ break
239+
187240 if len (new_lines ) > 0 :
188241 lines .pop (i )
189242 for j , new_line in enumerate (new_lines ):
0 commit comments