2424import lldb
2525import struct
2626import re
27+ import os
28+ import sys
2729
2830NULL = 'null'
2931
@@ -32,12 +34,14 @@ def log(msg):
3234 print (msg ())
3335
3436def log2 (msg ):
35- if True :
37+ if False :
3638 print (msg ())
3739
38- def exelog (stmt ):
40+ def exelog (source , stmt ):
3941 if False :
4042 f = open (os .getenv ('HOME' , '' ) + "/lldbexelog.txt" , "a" )
43+ f .write (source )
44+ f .write (" - " )
4145 f .write (stmt ())
4246 f .write ("\n " )
4347 f .close ()
@@ -47,11 +51,11 @@ def lldb_val_to_ptr(lldb_val):
4751 return '((struct ObjHeader *) {:#x})' .format (addr )
4852
4953
50- def evaluate (expr ):
54+ def evaluate (source , expr ):
5155 result = lldb .debugger .GetSelectedTarget ().EvaluateExpression (expr , lldb .SBExpressionOptions ())
5256 evallog = lambda : "{} => {}" .format (expr , result )
5357 log (evallog )
54- exelog (evallog )
58+ exelog (source , evallog )
5559 return result
5660
5761def _symbol_loaded_address (name , debugger = lldb .debugger ):
@@ -75,18 +79,18 @@ def _type_info_by_address(address, debugger = lldb.debugger):
7579 return candidates
7680
7781def is_instance_of (addr , typeinfo ):
78- return evaluate ("(bool)IsInstance({}, {:#x})" .format (addr , typeinfo )).GetValue () == "true"
82+ return evaluate ("is_instance_of" , " (bool)IsInstance({}, {:#x})" .format (addr , typeinfo )).GetValue () == "true"
7983
8084def is_string_or_array (value ):
81- return evaluate ("(int)IsInstance({0}, {1}) ? 1 : ((int)Konan_DebugIsArray({0}) ? 2 : 0)" .format (lldb_val_to_ptr (value ), _symbol_loaded_address ('kclass:kotlin.String' ))).unsigned
85+ return evaluate ("is_string_or_array" , " (int)IsInstance({0}, {1}) ? 1 : ((int)Konan_DebugIsArray({0}) ? 2 : 0)" .format (lldb_val_to_ptr (value ), _symbol_loaded_address ('kclass:kotlin.String' ))).unsigned
8286
8387def type_info (value ):
8488 """This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
8589 meta-object pointed by TypeInfo. Two lower bits are reserved for memory management needs see runtime/src/main/cpp/Memory.h."""
86- if str ( value .type ) != "struct ObjHeader *" :
90+ if value .GetTypeName ( ) != "ObjHeader *" :
8791 return False
8892 expr = "*(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3) == **(void***)((uintptr_t)(*(void**){0:#x}) & ~0x3) ? *(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3) : (void *)0" .format (value .unsigned )
89- result = evaluate (expr )
93+ result = evaluate ("type_info" , expr )
9094 return result .unsigned if result .IsValid () and result .unsigned != 0 else None
9195
9296
@@ -100,23 +104,27 @@ def type_info(value):
100104
101105def kotlin_object_type_summary (lldb_val , internal_dict = {}):
102106 """Hook that is run by lldb to display a Kotlin object."""
103- log (lambda : "kotlin_object_type_summary({:#x})" .format (lldb_val .unsigned ))
107+ log (lambda : "kotlin_object_type_summary({:#x}, {} )" .format (lldb_val .unsigned , internal_dict ))
104108 fallback = lldb_val .GetValue ()
105109 if str (lldb_val .type ) != "struct ObjHeader *" :
106110 if lldb_val .GetValue () is None :
107111 return NULL
108112 return lldb_val .GetValueAsSigned ()
109113
114+ if lldb_val .unsigned == 0 :
115+ return NULL
110116 tip = internal_dict ["type_info" ] if "type_info" in internal_dict .keys () else type_info (lldb_val )
117+
111118 if not tip :
112119 return fallback
113120
114121 return select_provider (lldb_val , tip , internal_dict ).to_string ()
115122
116123
117124def select_provider (lldb_val , tip , internal_dict ):
125+ log (lambda : "select_provider: name:{} : {}, {}" .format (lldb_val .name , lldb_val , internal_dict ))
118126 soa = is_string_or_array (lldb_val )
119- log (lambda : "select_provider: {} : {}" .format (lldb_val , soa ))
127+ log (lambda : "select_provider: {} : soa: {}" .format (lldb_val , soa ))
120128 return __FACTORY ['string' ](lldb_val , tip , internal_dict ) if soa == 1 else __FACTORY ['array' ](lldb_val , tip , internal_dict ) if soa == 2 \
121129 else __FACTORY ['object' ](lldb_val , tip , internal_dict )
122130
@@ -131,7 +139,7 @@ def __init__(self, valobj, amString, internal_dict = {}):
131139 self ._internal_dict = internal_dict .copy ()
132140 self ._to_string_depth = TO_STRING_DEPTH if "to_string_depth" not in self ._internal_dict .keys () else self ._internal_dict ["to_string_depth" ]
133141 if self ._children_count == 0 :
134- self ._children_count = evaluate ( "(int)Konan_DebugGetFieldCount({})" . format ( self ._ptr )). signed
142+ self ._children_count = self ._calc_child_count ()
135143 self ._children = []
136144 self ._type_conversion = [
137145 lambda address , name : self ._valobj .CreateValueFromExpression (name , "(void *){:#x}" .format (address )),
@@ -159,8 +167,12 @@ def __init__(self, valobj, amString, internal_dict = {}):
159167 valobj .GetType ().GetBasicType (lldb .eBasicTypeBool )
160168 ]
161169
170+ # This is a little ugly, as we need to have self._ptr set before calling, but this allows arrays to be manageable
171+ def _calc_child_count (self ):
172+ return evaluate ("KonanHelperProvider" , "(int)Konan_DebugGetFieldCount({})" .format (self ._ptr )).signed
173+
162174 def _read_string (self , expr , error ):
163- return self ._process .ReadCStringFromMemory (evaluate (expr ).unsigned , 0x1000 , error )
175+ return self ._process .ReadCStringFromMemory (evaluate ("_read_string" , expr ).unsigned , 0x1000 , error )
164176
165177 def _read_value (self , index ):
166178 value_type = self ._children [index ].type ()
@@ -202,18 +214,18 @@ def _deref_or_obj_summary(self, index, internal_dict):
202214 return kotlin_object_type_summary (value .deref , internal_dict )
203215
204216 def _field_address (self , index ):
205- return evaluate ("(void *)Konan_DebugGetFieldAddress({}, {})" .format (self ._ptr , index )).unsigned
217+ return evaluate ("_field_address" , " (void *)Konan_DebugGetFieldAddress({}, {})" .format (self ._ptr , index )).unsigned
206218
207219 def _field_type (self , index ):
208- return evaluate ("(int)Konan_DebugGetFieldType({}, {})" .format (self ._ptr , index )).unsigned
220+ return evaluate ("_field_type" , " (int)Konan_DebugGetFieldType({}, {})" .format (self ._ptr , index )).unsigned
209221
210222class KonanStringSyntheticProvider (KonanHelperProvider ):
211223 def __init__ (self , valobj ):
212224 self ._children_count = 0
213225 super (KonanStringSyntheticProvider , self ).__init__ (valobj , True )
214226 fallback = valobj .GetValue ()
215- buff_addr = evaluate ("(void *)Konan_DebugBuffer()" ).unsigned
216- buff_len = evaluate (
227+ buff_addr = evaluate ("KonanStringSyntheticProvider" , " (void *)Konan_DebugBuffer()" ).unsigned
228+ buff_len = evaluate ("KonanStringSyntheticProvider" ,
217229 '(int)Konan_DebugObjectToUtf8Array({}, (void *){:#x}, (int)Konan_DebugBufferSize());' .format (
218230 self ._ptr , buff_addr )
219231 ).signed
@@ -342,6 +354,9 @@ def __init__(self, valobj, internal_dict):
342354 self ._children = [MemberLayout (str (x ), type , offset + x * size ) for x in range (self .num_children ())]
343355 self ._values = [self ._read_value (i ) for i in range (min (ARRAY_TO_STRING_LIMIT , self ._children_count ))]
344356
357+ def _calc_child_count (self ):
358+ self ._real_child_count = evaluate ("KonanHelperProvider" , "(int)Konan_DebugGetFieldCount({})" .format (self ._ptr )).signed
359+ return min (ARRAY_TO_STRING_LIMIT , self ._real_child_count )
345360
346361 def cap_children_count (self ):
347362 return self ._children_count
@@ -364,17 +379,18 @@ def get_child_at_index(self, index):
364379 return result
365380
366381 def to_string (self ):
367- return '[%x]' % self ._children_count
382+ return '[%x]' % self ._real_child_count
368383# return [self._deref_or_obj_summary(i, self._internal_dict.copy()) for i in range(min(ARRAY_TO_STRING_LIMIT, self._children_count))]
369384
370385
371386class KonanProxyTypeProvider :
372387 def __init__ (self , valobj , internal_dict ):
373- log (lambda : "proxy : {:#x}" .format (valobj .unsigned ))
388+ log (lambda : "KonanProxyTypeProvider : {:#x}" .format (valobj .unsigned ))
374389 tip = type_info (valobj )
375- log ( lambda : "KonanProxyTypeProvider: tip: {:#x}" . format ( tip ))
390+
376391 if not tip :
377392 return
393+ log (lambda : "KonanProxyTypeProvider: tip: {:#x}" .format (tip ))
378394 self ._proxy = select_provider (valobj , tip , internal_dict )
379395 log (lambda : "KonanProxyTypeProvider: _proxy: {}" .format (self ._proxy .__class__ .__name__ ))
380396 self .update ()
@@ -387,7 +403,7 @@ def clear_cache_command(debugger, command, result, internal_dict):
387403
388404
389405def type_name_command (debugger , command , result , internal_dict ):
390- result .AppendMessage (evaluate ('(char *)Konan_DebugGetTypeName({})' .format (command )).summary )
406+ result .AppendMessage (evaluate ("type_name_command" , '(char *)Konan_DebugGetTypeName({})' .format (command )).summary )
391407
392408__KONAN_VARIABLE = re .compile ('kvar:(.*)#internal' )
393409__KONAN_VARIABLE_TYPE = re .compile ('^kfun:<get-(.*)>\\ (\\ )(.*)$' )
@@ -460,7 +476,7 @@ def konan_globals_command(debugger, command, result, internal_dict):
460476 address = getter_functions [0 ].function .GetStartAddress ().GetLoadAddress (target )
461477 type = __KONAN_VARIABLE_TYPE .search (getters [0 ].name ).group (2 )
462478 (c_type , extractor ) = __TYPES_KONAN_TO_C [type ] if type in __TYPES_KONAN_TO_C .keys () else ('struct ObjHeader *' , lambda v : kotlin_object_type_summary (v ))
463- value = evaluate ('(({0} (*)()){1:#x})()' .format (c_type , address ))
479+ value = evaluate ("konan_globals_command" , '(({0} (*)()){1:#x})()' .format (c_type , address ))
464480 str_value = extractor (value )
465481 result .AppendMessage ('{} {}: {}' .format (type , name , str_value ))
466482
0 commit comments