1
+ from typing import Optional
2
+
3
+ from lldb import SBDebugger , SBExecutionContext , SBCommandReturnObject , SBTarget , SBSymbol , SBInstructionList
4
+ from touchlab_kotlin_lldb .util import evaluate , DebuggerException
5
+
6
+ import re
7
+
8
+
9
+ class GCCollectCommand :
10
+ program = 'force_gc'
11
+
12
+ def __init__ (self , debugger , unused ):
13
+ pass
14
+
15
+ def __call__ (self , debugger : SBDebugger , command , exe_ctx : SBExecutionContext , result : SBCommandReturnObject ):
16
+ try :
17
+ target = debugger .GetSelectedTarget ()
18
+ schedule_gc_function = self ._find_single_function_symbol ('kotlin::gcScheduler::GCScheduler::scheduleAndWaitFinalized()' , target , result )
19
+ deinit_memory_function = self ._find_single_function_symbol ('DeinitMemory' , target , result )
20
+ global_data_symbol = self ._find_single_symbol ("(anonymous namespace)::globalDataInstance" , target , result )
21
+
22
+ gc_scheduler_offset = self ._find_gc_scheduler_offset (deinit_memory_function , schedule_gc_function , target )
23
+
24
+ schedule_gc_function_addr = schedule_gc_function .addr .GetLoadAddress (target )
25
+ global_data_addr = global_data_symbol .addr .GetLoadAddress (target )
26
+ gc_scheduler_addr = global_data_addr + gc_scheduler_offset
27
+
28
+ evaluate (
29
+ '((void (*)(void*)){:#x})((void*){:#x})' ,
30
+ schedule_gc_function_addr ,
31
+ gc_scheduler_addr
32
+ )
33
+ evaluate (
34
+ '((void (*)(void*)){:#x})((void*){:#x})' ,
35
+ schedule_gc_function_addr ,
36
+ gc_scheduler_addr
37
+ )
38
+
39
+ except DebuggerException as e :
40
+ result .SetError ("{} Please report this to the xcode-kotlin GitHub." .format (e .msg ))
41
+ return
42
+
43
+
44
+ @staticmethod
45
+ def _find_single_function_symbol (symbol_name : str , target : SBTarget , result : SBCommandReturnObject ) -> SBSymbol :
46
+ functions = target .FindFunctions (symbol_name )
47
+ if functions .GetSize () >= 1 :
48
+ if not functions .GetSize () == 1 :
49
+ result .AppendWarning ("Multiple ({}) symbols found for function {}" .format (functions .GetSize (), symbol_name ))
50
+ return functions [0 ].GetSymbol ()
51
+ else :
52
+ raise DebuggerException ("Could not find symbol for function {}." .format (symbol_name ))
53
+
54
+ @staticmethod
55
+ def _find_single_symbol (symbol_name : str , target : SBTarget , result : SBCommandReturnObject ) -> SBSymbol :
56
+ symbols = target .FindSymbols (symbol_name )
57
+ if symbols .GetSize () >= 1 :
58
+ if not symbols .GetSize () == 1 :
59
+ result .AppendWarning (
60
+ "Multiple ({}) symbols found for function {}" .format (symbols .GetSize (), symbol_name ))
61
+ return symbols [0 ].GetSymbol ()
62
+ else :
63
+ raise DebuggerException ("Could not find symbol for function {}." .format (symbol_name ))
64
+
65
+ @staticmethod
66
+ def _find_gc_scheduler_offset (deinit_memory : SBSymbol , schedule_gc : SBSymbol , target : SBTarget ) -> int :
67
+ instructions = deinit_memory .GetInstructions (target )
68
+ load_addr = "{:#x}" .format (schedule_gc .addr .GetLoadAddress (target ))
69
+
70
+ previous_branch_instruction_index : int = 0
71
+ schedule_gc_branch_instruction_index : Optional [int ] = None
72
+ for i in range (len (instructions )):
73
+ instruction = instructions [i ]
74
+ if instruction .DoesBranch ():
75
+ if instruction .GetOperands (target ) == load_addr :
76
+ schedule_gc_branch_instruction_index = i
77
+ break
78
+ else :
79
+ previous_branch_instruction_index = i
80
+
81
+ if not schedule_gc_branch_instruction_index :
82
+ raise DebuggerException (
83
+ "Could not find a branch instruction to {} inside {}." .format (
84
+ schedule_gc .GetDisplayName (), deinit_memory .GetDisplayName ()))
85
+
86
+ match_pattern = "\\ (anonymous namespace\\ )::globalDataInstance\\ s+\\ +\\ s+(\\ d+)"
87
+ gc_scheduler_offset : Optional [int ] = None
88
+ for i in range (previous_branch_instruction_index , schedule_gc_branch_instruction_index ):
89
+ instruction = instructions [i ]
90
+ match = re .search (match_pattern , instruction .GetComment (target ))
91
+ if match :
92
+ gc_scheduler_offset = int (match .group (1 ))
93
+ break
94
+
95
+ if not gc_scheduler_offset :
96
+ raise DebuggerException ("Could not find gc_scheduler offset for globalDataInstance." )
97
+
98
+ return gc_scheduler_offset
0 commit comments