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