2323
2424import lldb
2525import struct
26- import os
27-
28- def is_appcode ():
29- return 'AppCode' in os .getenv ('XPC_SERVICE_NAME' , '' )
30-
31- def is_xcode ():
32- return 'Xcode' in os .getenv ('CLIENT_TYPE' , '' )
3326
3427NULL = 'null'
3528
36- CLIENT_APPCODE = is_appcode ()
37- CLIENT_XCODE = is_xcode ()
38- VISUAL_DEBUGGER = CLIENT_APPCODE or CLIENT_XCODE
39-
4029def log (msg ):
4130 if False :
42- print (msg )
31+ print (msg () )
4332
4433def exelog (stmt ):
4534 if False :
4635 f = open (os .getenv ('HOME' , '' ) + "/lldbexelog.txt" , "a" )
47- f .write (stmt )
36+ f .write (stmt () )
4837 f .write ("\n " )
4938 f .close ()
5039
@@ -55,7 +44,7 @@ def lldb_val_to_ptr(lldb_val):
5544
5645def evaluate (expr ):
5746 result = lldb .debugger .GetSelectedTarget ().EvaluateExpression (expr , lldb .SBExpressionOptions ())
58- evallog = "{} => {}" .format (expr , result )
47+ evallog = lambda : "{} => {}" .format (expr , result )
5948 log (evallog )
6049 exelog (evallog )
6150 return result
@@ -66,46 +55,46 @@ def is_instance_of(addr, typeinfo):
6655def is_string_or_array (value ):
6756 return evaluate ("(bool)IsInstance({0}, theStringTypeInfo) ? 1 : ((int)Konan_DebugIsArray({0}) ? 2 : 0)" .format (lldb_val_to_ptr (value ))).unsigned
6857
69- def check_type_info (value ):
58+ def type_info (value ):
7059 """This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
7160 meta-object pointed by TypeInfo. Two lower bits are reserved for memory management needs see runtime/src/main/cpp/Memory.h."""
7261 if str (value .type ) != "struct ObjHeader *" :
7362 return False
74- expr = "*(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3) == **(void***)((uintptr_t)(*(void**){0:#x}) & ~0x3)" .format (value .unsigned )
63+ 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 )
7564 result = evaluate (expr )
76- return result .IsValid () and result .GetValue () == "true"
77-
78- def type_info (value ):
79- return evaluate ("*(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3)" .format (value .unsigned )).unsigned
65+ return result .unsigned if result .IsValid () and result .unsigned != 0 else None
8066
8167
8268__FACTORY = {}
8369
8470
8571# Cache type info pointer to [ChildMetaInfo]
8672SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
73+ TO_STRING_DEPTH = 2
74+ ARRAY_TO_STRING_LIMIT = 10
8775
88- def kotlin_object_type_summary (lldb_val , internal_dict ):
76+ def kotlin_object_type_summary (lldb_val , internal_dict = [] ):
8977 """Hook that is run by lldb to display a Kotlin object."""
90- log ("kotlin_object_type_summary({:#x})" .format (lldb_val .unsigned ))
78+ log (lambda : "kotlin_object_type_summary({:#x})" .format (lldb_val .unsigned ))
9179 fallback = lldb_val .GetValue ()
9280 if str (lldb_val .type ) != "struct ObjHeader *" :
9381 return fallback
9482
95- if not check_type_info (lldb_val ):
96- return NULL
97-
9883 ptr = lldb_val_to_ptr (lldb_val )
9984 if ptr is None :
10085 return fallback
10186
102- return select_provider (lldb_val ).to_string ()
87+ tip = internal_dict ["type_info" ] if "type_info" in internal_dict .keys () else type_info (lldb_val )
88+ if not tip :
89+ return fallback
10390
91+ return select_provider (lldb_val , tip , internal_dict ).to_string ()
10492
105- def select_provider (lldb_val ):
93+
94+ def select_provider (lldb_val , tip , internal_dict ):
10695 soa = is_string_or_array (lldb_val )
107- return __FACTORY ['string' ](lldb_val ) if soa == 1 else __FACTORY ['array' ](lldb_val ) if soa == 2 \
108- else __FACTORY ['object' ](lldb_val )
96+ return __FACTORY ['string' ](lldb_val , tip , internal_dict ) if soa == 1 else __FACTORY ['array' ](lldb_val , tip , internal_dict ) if soa == 2 \
97+ else __FACTORY ['object' ](lldb_val , tip , internal_dict )
10998
11099class KonanHelperProvider (lldb .SBSyntheticValueProvider ):
111100 def __init__ (self , valobj , amString ):
@@ -163,18 +152,26 @@ def _create_synthetic_child(self, address, name):
163152
164153 def _read_type (self , index ):
165154 type = self ._types [self ._children [index ].type ()]
166- log ("type:{0} of {1:#x} of {2:#x}" .format (type , self ._valobj .unsigned , self ._valobj .unsigned + self ._children [index ].offset ()))
155+ log (lambda : "type:{0} of {1:#x} of {2:#x}" .format (type , self ._valobj .unsigned , self ._valobj .unsigned + self ._children [index ].offset ()))
167156 return type
168157
169- def _deref_or_obj_summary (self , index ):
158+ def _deref_or_obj_summary (self , index , internal_dict ):
170159 value = self ._values [index ]
171160 if not value :
172- log ("_deref_or_obj_summary: value none, index:{}, type:{}" .format (index , self ._children [index ].type ()))
161+ log (lambda : "_deref_or_obj_summary: value none, index:{}, type:{}" .format (index , self ._children [index ].type ()))
173162 return None
174- if check_type_info (value ):
175- return kotlin_object_type_summary (value , None )
176- else :
177- return kotlin_object_type_summary (value .deref , None )
163+
164+ tip = type_info (value )
165+ if tip :
166+ internal_dict ["type_info" ] = tip
167+ return kotlin_object_type_summary (value , internal_dict )
168+ tip = type_info (value .deref )
169+
170+ if tip :
171+ internal_dict ["type_info" ] = tip
172+ return kotlin_object_type_summary (value .deref , internal_dict )
173+
174+ return kotlin_object_type_summary (value .deref , internal_dict )
178175
179176 def _field_address (self , index ):
180177 return evaluate ("(void *)Konan_DebugGetFieldAddress({}, {})" .format (self ._ptr , index )).unsigned
@@ -243,10 +240,10 @@ def offset(self):
243240 return self ._offset
244241
245242class KonanObjectSyntheticProvider (KonanHelperProvider ):
246- def __init__ (self , valobj , tip ):
243+ def __init__ (self , valobj , tip , internal_dict ):
247244 # Save an extra call into the process
248245 if tip in SYNTHETIC_OBJECT_LAYOUT_CACHE :
249- log ("TIP: {:#x} EARLYHIT" .format (tip ))
246+ log (lambda : "TIP: {:#x} EARLYHIT" .format (tip ))
250247 self ._children = SYNTHETIC_OBJECT_LAYOUT_CACHE [tip ]
251248 self ._children_count = len (self ._children )
252249 else :
@@ -258,14 +255,13 @@ def __init__(self, valobj, tip):
258255 SYNTHETIC_OBJECT_LAYOUT_CACHE [tip ] = [
259256 MemberLayout (self ._field_name (i ), self ._field_type (i ), self ._field_address (i ) - self ._valobj .unsigned )
260257 for i in range (self ._children_count )]
261- log ("TIP: {:#x} MISSED" .format (tip ))
258+ log (lambda : "TIP: {:#x} MISSED" .format (tip ))
262259 else :
263- log ("TIP: {:#x} HIT" .format (tip ))
260+ log (lambda : "TIP: {:#x} HIT" .format (tip ))
264261 self ._children = SYNTHETIC_OBJECT_LAYOUT_CACHE [tip ]
265- if VISUAL_DEBUGGER :
266- self ._values = [None for index in range (self ._children_count )]
267- else :
268- self ._values = [self ._read_value (index ) for index in range (self ._children_count )]
262+ self ._values = [self ._read_value (index ) for index in range (self ._children_count )]
263+ self ._internal_dict = internal_dict
264+ self ._to_string_depth = TO_STRING_DEPTH if "to_string_depth" not in self ._internal_dict .keys () else self ._internal_dict ["to_string_depth" ]
269265
270266
271267 def _field_name (self , index ):
@@ -286,7 +282,7 @@ def __none(iterable, f):
286282 return not any (f (x ) for x in iterable )
287283 if __none (self ._children , lambda x : x .name () == name ):
288284 return - 1
289- return next (( i for i ,v in enumerate (self ._children ) if v .name () == name ) )
285+ return next (i for i ,v in enumerate (self ._children ) if v .name () == name )
290286
291287 def get_child_at_index (self , index ):
292288 result = self ._values [index ]
@@ -298,13 +294,15 @@ def get_child_at_index(self, index):
298294
299295 # TODO: fix cyclic structures stringification.
300296 def to_string (self ):
301- if VISUAL_DEBUGGER :
302- return ""
297+ if self . _to_string_depth == 0 :
298+ return "... "
303299 else :
304- return dict ([(self ._children [i ].name (), self ._deref_or_obj_summary (i )) for i in range (self ._children_count )])
300+ internal_dict = self ._internal_dict .copy ()
301+ internal_dict ["to_string_depth" ] = self ._to_string_depth - 1
302+ return dict ([(self ._children [i ].name (), self ._deref_or_obj_summary (i , internal_dict )) for i in range (self ._children_count )])
305303
306304class KonanArraySyntheticProvider (KonanHelperProvider ):
307- def __init__ (self , valobj ):
305+ def __init__ (self , valobj , internal_dict ):
308306 self ._children_count = 0
309307 super (KonanArraySyntheticProvider , self ).__init__ (valobj , False )
310308 if self ._ptr is None :
@@ -316,17 +314,12 @@ def __init__(self, valobj):
316314 offset = zerro_address - valobj .unsigned
317315 size = first_address - zerro_address
318316 self ._children = [MemberLayout (str (x ), type , offset + x * size ) for x in range (self .num_children ())]
319- if VISUAL_DEBUGGER :
320- self ._values = [None for index in range (self .cap_children_count ())]
321- else :
322- self ._values = [self ._read_value (i ) for i in range (self .cap_children_count ())]
317+ self ._values = [self ._read_value (i ) for i in range (self .cap_children_count ())]
318+ self ._internal_dict = internal_dict
319+
323320
324321 def cap_children_count (self ):
325- #AppCode limits array len automatically
326- if CLIENT_XCODE :
327- return min (self ._children_count , 20 )
328- else :
329- return self ._children_count
322+ return self ._children_count
330323
331324 def num_children (self ):
332325 return self .cap_children_count ()
@@ -346,18 +339,16 @@ def get_child_at_index(self, index):
346339 return result
347340
348341 def to_string (self ):
349- if VISUAL_DEBUGGER :
350- return [self ._children_count ]
351- else :
352- return [self ._deref_or_obj_summary (i ) for i in range (self ._children_count )]
342+ return [self ._deref_or_obj_summary (i , self ._internal_dict .copy ()) for i in range (min (ARRAY_TO_STRING_LIMIT , self ._children_count ))]
353343
354344
355345class KonanProxyTypeProvider :
356- def __init__ (self , valobj , _ ):
357- log ("proxy: {:#x}" .format (valobj .unsigned ))
358- if not check_type_info (valobj ):
346+ def __init__ (self , valobj , internal_dict ):
347+ log (lambda : "proxy: {:#x}" .format (valobj .unsigned ))
348+ tip = type_info (valobj )
349+ if not tip :
359350 return
360- self ._proxy = select_provider (valobj )
351+ self ._proxy = select_provider (valobj , tip , internal_dict )
361352 self .update ()
362353
363354 def __getattr__ (self , item ):
@@ -371,9 +362,9 @@ def clear_cache_command(debugger, command, result, internal_dict):
371362 SYNTHETIC_OBJECT_LAYOUT_CACHE .clear ()
372363
373364def __lldb_init_module (debugger , _ ):
374- __FACTORY ['object' ] = lambda x : KonanObjectSyntheticProvider (x , type_info ( x ) )
375- __FACTORY ['array' ] = lambda x : KonanArraySyntheticProvider (x )
376- __FACTORY ['string' ] = lambda x : KonanStringSyntheticProvider (x )
365+ __FACTORY ['object' ] = lambda x , y , z : KonanObjectSyntheticProvider (x , y , z )
366+ __FACTORY ['array' ] = lambda x , y , z : KonanArraySyntheticProvider (x , z )
367+ __FACTORY ['string' ] = lambda x , y , _ : KonanStringSyntheticProvider (x )
377368 debugger .HandleCommand ('\
378369 type summary add \
379370 --no-value \
@@ -390,4 +381,4 @@ def __lldb_init_module(debugger, _):
390381 ' )
391382 debugger .HandleCommand ('type category enable Kotlin' )
392383 debugger .HandleCommand ('command script add -f {}.print_this_command print_this' .format (__name__ ))
393- debugger .HandleCommand ('command script add -f {}.clear_cache_command clear_kotlin_cache' .format (__name__ ))
384+ debugger .HandleCommand ('command script add -f {}.clear_cache_command clear_kotlin_cache' .format (__name__ ))
0 commit comments