3
3
import zlib
4
4
import json
5
5
import sys
6
+ import re
6
7
7
8
from typing import TYPE_CHECKING
8
9
from functools import lru_cache
@@ -124,6 +125,10 @@ def links_count(self) -> int:
124
125
count += 1
125
126
126
127
return count
128
+
129
+ @staticmethod
130
+ def remove_bad_mermaid_chars (text : str ):
131
+ return re .sub (r'`' ,'' ,text )
127
132
128
133
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 :
129
134
"""
@@ -200,7 +205,7 @@ def gen_mermaid_flow_graph(self, direction=None, shaded_nodes: list = None, shad
200
205
depth = node [1 ]
201
206
fname = node [0 ]
202
207
203
- if max_display_depth and depth > max_display_depth :
208
+ if max_display_depth is not None and depth > max_display_depth :
204
209
continue
205
210
206
211
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
238
243
239
244
mermaid_chart = mermaid_flow .format (links = '\n ' .join (links .keys ()), direction = direction , style = style )
240
245
246
+ mermaid_chart = self .remove_bad_mermaid_chars (mermaid_chart )
247
+
241
248
if wrap_mermaid :
242
249
mermaid_chart = _wrap_mermaid (mermaid_chart )
243
250
@@ -266,7 +273,7 @@ def gen_mermaid_mind_map(self, max_display_depth=None, wrap_mermaid=False) -> st
266
273
depth = row [1 ]
267
274
268
275
# 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 :
270
277
continue
271
278
272
279
if depth < last_depth :
@@ -281,6 +288,8 @@ def gen_mermaid_mind_map(self, max_display_depth=None, wrap_mermaid=False) -> st
281
288
282
289
mermaid_chart = mermaid_mind .format (rows = '\n ' .join (rows ), root = self .root )
283
290
291
+ mermaid_chart = self .remove_bad_mermaid_chars (mermaid_chart )
292
+
284
293
if wrap_mermaid :
285
294
mermaid_chart = _wrap_mermaid (mermaid_chart )
286
295
@@ -298,7 +307,7 @@ def get_called_funcs_memo(f: "ghidra.program.model.listing.Function"):
298
307
299
308
300
309
# 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 ):
302
311
"""
303
312
Build a call graph of all calling functions
304
313
Traverses depth first
@@ -314,12 +323,15 @@ def get_calling(f: "ghidra.program.model.listing.Function", cgraph: CallGraph =
314
323
visited = tuple ()
315
324
start_time = time .time ()
316
325
317
- if depth > MAX_DEPTH :
326
+ if depth == MAX_DEPTH :
318
327
cgraph .add_edge (f .getName (include_ns ), f'MAX_DEPTH_HIT - { depth } ' , depth )
319
328
return cgraph
320
329
321
330
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
323
335
324
336
space = (depth + 2 )* ' '
325
337
@@ -349,7 +361,7 @@ def get_calling(f: "ghidra.program.model.listing.Function", cgraph: CallGraph =
349
361
cgraph .add_edge (c .getName (include_ns ), f .getName (include_ns ), depth )
350
362
351
363
# 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 )
353
365
else :
354
366
if verbose :
355
367
print (f'{ space } - END for { f .name } ' )
@@ -380,13 +392,15 @@ def get_called(f: "ghidra.program.model.listing.Function", cgraph: CallGraph = C
380
392
visited = tuple ()
381
393
start_time = time .time ()
382
394
383
- if depth > max_depth :
395
+ if depth == max_depth :
384
396
cgraph .add_edge (f .getName (include_ns ), f'MAX_DEPTH_HIT - { depth } ' , depth )
385
397
return cgraph
386
398
387
399
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
+
390
404
space = (depth + 2 )* ' '
391
405
392
406
# loop check
@@ -427,7 +441,7 @@ def get_called(f: "ghidra.program.model.listing.Function", cgraph: CallGraph = C
427
441
428
442
# Parse further functions
429
443
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 )
431
445
432
446
else :
433
447
if verbose :
0 commit comments