33import zlib
44import json
55import sys
6+ import re
67
78from typing import TYPE_CHECKING
89from functools import lru_cache
@@ -124,6 +125,10 @@ def links_count(self) -> int:
124125 count += 1
125126
126127 return count
128+
129+ @staticmethod
130+ def remove_bad_mermaid_chars (text : str ):
131+ return re .sub (r'`' ,'' ,text )
127132
128133 def gen_mermaid_flow_graph (self , direction = None , shaded_nodes : list = None , shade_color = '#339933' , max_display_depth = None , endpoint_only = False , wrap_mermaid = False ) -> str :
129134 """
@@ -200,7 +205,7 @@ def gen_mermaid_flow_graph(self, direction=None, shaded_nodes: list = None, shad
200205 depth = node [1 ]
201206 fname = node [0 ]
202207
203- if max_display_depth and depth > max_display_depth :
208+ if max_display_depth is not None and depth > max_display_depth :
204209 continue
205210
206211 if shaded_nodes and fname in shaded_nodes :
@@ -238,6 +243,8 @@ def gen_mermaid_flow_graph(self, direction=None, shaded_nodes: list = None, shad
238243
239244 mermaid_chart = mermaid_flow .format (links = '\n ' .join (links .keys ()), direction = direction , style = style )
240245
246+ mermaid_chart = self .remove_bad_mermaid_chars (mermaid_chart )
247+
241248 if wrap_mermaid :
242249 mermaid_chart = _wrap_mermaid (mermaid_chart )
243250
@@ -266,7 +273,7 @@ def gen_mermaid_mind_map(self, max_display_depth=None, wrap_mermaid=False) -> st
266273 depth = row [1 ]
267274
268275 # skip root row
269- if depth < 2 or max_display_depth and depth > max_display_depth :
276+ if depth < 2 or max_display_depth is not None and depth > max_display_depth :
270277 continue
271278
272279 if depth < last_depth :
@@ -281,6 +288,8 @@ def gen_mermaid_mind_map(self, max_display_depth=None, wrap_mermaid=False) -> st
281288
282289 mermaid_chart = mermaid_mind .format (rows = '\n ' .join (rows ), root = self .root )
283290
291+ mermaid_chart = self .remove_bad_mermaid_chars (mermaid_chart )
292+
284293 if wrap_mermaid :
285294 mermaid_chart = _wrap_mermaid (mermaid_chart )
286295
@@ -298,7 +307,7 @@ def get_called_funcs_memo(f: "ghidra.program.model.listing.Function"):
298307
299308
300309# Recursively calling to build calling graph
301- def get_calling (f : "ghidra.program.model.listing.Function" , cgraph : CallGraph = CallGraph (), depth : int = 0 , visited : tuple = None , verbose = False , include_ns = True , start_time = None , max_run_time = None ):
310+ def get_calling (f : "ghidra.program.model.listing.Function" , cgraph : CallGraph = CallGraph (), depth : int = 0 , visited : tuple = None , verbose = False , include_ns = True , start_time = None , max_run_time = None , max_depth = MAX_DEPTH ):
302311 """
303312 Build a call graph of all calling functions
304313 Traverses depth first
@@ -314,12 +323,15 @@ def get_calling(f: "ghidra.program.model.listing.Function", cgraph: CallGraph =
314323 visited = tuple ()
315324 start_time = time .time ()
316325
317- if depth > MAX_DEPTH :
326+ if depth == MAX_DEPTH :
318327 cgraph .add_edge (f .getName (include_ns ), f'MAX_DEPTH_HIT - { depth } ' , depth )
319328 return cgraph
320329
321330 if (time .time () - start_time ) > float (max_run_time ):
322- raise TimeoutError (f'time expired for { f .getName (include_ns )} ' )
331+ #raise TimeoutError(f'time expired for {clean_func(f,include_ns)}')
332+ cgraph .add_edge (f .getName (include_ns ), f'MAX_TIME_HIT - time: { max_run_time } depth: { depth } ' , depth )
333+ print (f'\n Warn: cg : { cgraph .root } edges: { cgraph .links_count ()} depth: { depth } name: { f .name } did not complete. max_run_time: { max_run_time } Increase timeout with --max-time-cg-gen MAX_TIME_CG_GEN' )
334+ return cgraph
323335
324336 space = (depth + 2 )* ' '
325337
@@ -349,7 +361,7 @@ def get_calling(f: "ghidra.program.model.listing.Function", cgraph: CallGraph =
349361 cgraph .add_edge (c .getName (include_ns ), f .getName (include_ns ), depth )
350362
351363 # Parse further functions
352- cgraph = get_calling (c , cgraph , depth , visited = visited , start_time = start_time , max_run_time = max_run_time )
364+ cgraph = get_calling (c , cgraph , depth , visited = visited , start_time = start_time , max_run_time = max_run_time , max_depth = max_depth )
353365 else :
354366 if verbose :
355367 print (f'{ space } - END for { f .name } ' )
@@ -380,13 +392,15 @@ def get_called(f: "ghidra.program.model.listing.Function", cgraph: CallGraph = C
380392 visited = tuple ()
381393 start_time = time .time ()
382394
383- if depth > max_depth :
395+ if depth == max_depth :
384396 cgraph .add_edge (f .getName (include_ns ), f'MAX_DEPTH_HIT - { depth } ' , depth )
385397 return cgraph
386398
387399 if (time .time () - start_time ) > float (max_run_time ):
388- raise TimeoutError (f'time expired for { f .getName (include_ns )} ' )
389-
400+ cgraph .add_edge (f .getName (include_ns ), f'MAX_TIME_HIT - time: { max_run_time } depth: { depth } ' , depth )
401+ print (f'\n Warn: cg : { cgraph .root } edges: { cgraph .links_count ()} depth: { depth } name: { f .name } did not complete. max_run_time: { max_run_time } Increase timeout with --max-time-cg-gen MAX_TIME_CG_GEN' )
402+ return cgraph
403+
390404 space = (depth + 2 )* ' '
391405
392406 # loop check
@@ -427,7 +441,7 @@ def get_called(f: "ghidra.program.model.listing.Function", cgraph: CallGraph = C
427441
428442 # Parse further functions
429443 cgraph = get_called (c , cgraph , depth , visited = visited ,
430- start_time = start_time , max_run_time = max_run_time )
444+ start_time = start_time , max_run_time = max_run_time , max_depth = max_depth )
431445
432446 else :
433447 if verbose :
0 commit comments