2323
2424import lldb
2525import struct
26+ import re
2627
2728NULL = 'null'
2829
2930def log (msg ):
3031 if False :
3132 print (msg ())
3233
34+ def log2 (msg ):
35+ if True :
36+ print (msg ())
37+
3338def exelog (stmt ):
3439 if False :
3540 f = open (os .getenv ('HOME' , '' ) + "/lldbexelog.txt" , "a" )
@@ -49,11 +54,31 @@ def evaluate(expr):
4954 exelog (evallog )
5055 return result
5156
57+ def _symbol_loaded_address (name , debugger = lldb .debugger ):
58+ target = debugger .GetSelectedTarget ()
59+ process = target .GetProcess ()
60+ thread = process .GetSelectedThread ()
61+ frame = thread .GetSelectedFrame ()
62+ candidates = list (filter (lambda x : x .name == name , frame .module .symbols ))
63+ # take first
64+ for candidate in candidates :
65+ address = candidate .GetStartAddress ().GetLoadAddress (target )
66+ log (lambda : "_symbol_loaded_address:{} {:#x}" .format (name , address ))
67+ return address
68+
69+ def _type_info_by_address (address , debugger = lldb .debugger ):
70+ target = debugger .GetSelectedTarget ()
71+ process = target .GetProcess ()
72+ thread = process .GetSelectedThread ()
73+ frame = thread .GetSelectedFrame ()
74+ candidates = list (filter (lambda x : x .GetStartAddress ().GetLoadAddress (target ) == address , frame .module .symbols ))
75+ return candidates
76+
5277def is_instance_of (addr , typeinfo ):
53- return evaluate ("(bool)IsInstance({}, {})" .format (addr , typeinfo )).GetValue () == "true"
78+ return evaluate ("(bool)IsInstance({}, {:#x })" .format (addr , typeinfo )).GetValue () == "true"
5479
5580def is_string_or_array (value ):
56- return evaluate ("(bool )IsInstance({0}, theStringTypeInfo ) ? 1 : ((int)Konan_DebugIsArray({0}) ? 2 : 0)" .format (lldb_val_to_ptr (value ))).unsigned
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
5782
5883def type_info (value ):
5984 """This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
@@ -73,16 +98,14 @@ def type_info(value):
7398TO_STRING_DEPTH = 2
7499ARRAY_TO_STRING_LIMIT = 10
75100
76- def kotlin_object_type_summary (lldb_val , internal_dict = [] ):
101+ def kotlin_object_type_summary (lldb_val , internal_dict = {} ):
77102 """Hook that is run by lldb to display a Kotlin object."""
78103 log (lambda : "kotlin_object_type_summary({:#x})" .format (lldb_val .unsigned ))
79104 fallback = lldb_val .GetValue ()
80105 if str (lldb_val .type ) != "struct ObjHeader *" :
81- return fallback
82-
83- ptr = lldb_val_to_ptr (lldb_val )
84- if ptr is None :
85- return fallback
106+ if lldb_val .GetValue () is None :
107+ return NULL
108+ return lldb_val .GetValueAsSigned ()
86109
87110 tip = internal_dict ["type_info" ] if "type_info" in internal_dict .keys () else type_info (lldb_val )
88111 if not tip :
@@ -93,17 +116,20 @@ def kotlin_object_type_summary(lldb_val, internal_dict = []):
93116
94117def select_provider (lldb_val , tip , internal_dict ):
95118 soa = is_string_or_array (lldb_val )
119+ log (lambda : "select_provider: {} : {}" .format (lldb_val , soa ))
96120 return __FACTORY ['string' ](lldb_val , tip , internal_dict ) if soa == 1 else __FACTORY ['array' ](lldb_val , tip , internal_dict ) if soa == 2 \
97121 else __FACTORY ['object' ](lldb_val , tip , internal_dict )
98122
99123class KonanHelperProvider (lldb .SBSyntheticValueProvider ):
100- def __init__ (self , valobj , amString ):
124+ def __init__ (self , valobj , amString , internal_dict = {} ):
101125 self ._target = lldb .debugger .GetSelectedTarget ()
102126 self ._process = self ._target .GetProcess ()
103127 self ._valobj = valobj
104128 self ._ptr = lldb_val_to_ptr (self ._valobj )
105129 if amString :
106130 return
131+ self ._internal_dict = internal_dict .copy ()
132+ self ._to_string_depth = TO_STRING_DEPTH if "to_string_depth" not in self ._internal_dict .keys () else self ._internal_dict ["to_string_depth" ]
107133 if self ._children_count == 0 :
108134 self ._children_count = evaluate ("(int)Konan_DebugGetFieldCount({})" .format (self ._ptr )).signed
109135 self ._children = []
@@ -142,6 +168,8 @@ def _read_value(self, index):
142168 return self ._type_conversion [int (value_type )](address , str (self ._children [index ].name ()))
143169
144170 def _create_synthetic_child (self , address , name ):
171+ if self ._to_string_depth == 0 :
172+ return None
145173 index = self .get_child_index (name )
146174 value = self ._valobj .CreateChildAtOffset (str (name ),
147175 self ._children [index ].offset (),
@@ -184,17 +212,16 @@ def __init__(self, valobj):
184212 self ._children_count = 0
185213 super (KonanStringSyntheticProvider , self ).__init__ (valobj , True )
186214 fallback = valobj .GetValue ()
215+ buff_addr = evaluate ("(void *)Konan_DebugBuffer()" ).unsigned
187216 buff_len = evaluate (
188- '(int)Konan_DebugObjectToUtf8Array({}, (char *)Konan_DebugBuffer() , (int)Konan_DebugBufferSize());' .format (
189- self ._ptr )
190- ).unsigned
217+ '(int)Konan_DebugObjectToUtf8Array({}, (void *){:#x} , (int)Konan_DebugBufferSize());' .format (
218+ self ._ptr , buff_addr )
219+ ).signed
191220
192221 if not buff_len :
193222 self ._representation = fallback
194223 return
195224
196- buff_addr = evaluate ("(char *)Konan_DebugBuffer()" ).unsigned
197-
198225 error = lldb .SBError ()
199226 s = self ._process .ReadCStringFromMemory (int (buff_addr ), int (buff_len ), error )
200227 if not error .Success ():
@@ -249,7 +276,7 @@ def __init__(self, valobj, tip, internal_dict):
249276 else :
250277 self ._children_count = 0
251278
252- super (KonanObjectSyntheticProvider , self ).__init__ (valobj , False )
279+ super (KonanObjectSyntheticProvider , self ).__init__ (valobj , False , internal_dict )
253280
254281 if not tip in SYNTHETIC_OBJECT_LAYOUT_CACHE :
255282 SYNTHETIC_OBJECT_LAYOUT_CACHE [tip ] = [
@@ -260,13 +287,11 @@ def __init__(self, valobj, tip, internal_dict):
260287 log (lambda : "TIP: {:#x} HIT" .format (tip ))
261288 self ._children = SYNTHETIC_OBJECT_LAYOUT_CACHE [tip ]
262289 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" ]
265290
266291
267292 def _field_name (self , index ):
268293 error = lldb .SBError ()
269- name = self ._read_string ("(const char *)Konan_DebugGetFieldName({}, (int){})" .format (self ._ptr , index ), error )
294+ name = self ._read_string ("(void *)Konan_DebugGetFieldName({}, (int){})" .format (self ._ptr , index ), error )
270295 if not error .Success ():
271296 raise DebuggerException ()
272297 return name
@@ -294,17 +319,18 @@ def get_child_at_index(self, index):
294319
295320 # TODO: fix cyclic structures stringification.
296321 def to_string (self ):
297- if self ._to_string_depth == 0 :
298- return "..."
299- else :
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 )])
322+ return "..."
323+ # if self._to_string_depth == 0:
324+ # return "..."
325+ # else:
326+ # internal_dict = self._internal_dict.copy()
327+ # internal_dict["to_string_depth"] = self._to_string_depth - 1
328+ # return dict([(self._children[i].name(), self._deref_or_obj_summary(i, internal_dict)) for i in range(self._children_count)])
303329
304330class KonanArraySyntheticProvider (KonanHelperProvider ):
305331 def __init__ (self , valobj , internal_dict ):
306332 self ._children_count = 0
307- super (KonanArraySyntheticProvider , self ).__init__ (valobj , False )
333+ super (KonanArraySyntheticProvider , self ).__init__ (valobj , False , internal_dict )
308334 if self ._ptr is None :
309335 return
310336 valobj .SetSyntheticChildrenGenerated (True )
@@ -314,8 +340,7 @@ def __init__(self, valobj, internal_dict):
314340 offset = zerro_address - valobj .unsigned
315341 size = first_address - zerro_address
316342 self ._children = [MemberLayout (str (x ), type , offset + x * size ) for x in range (self .num_children ())]
317- self ._values = [self ._read_value (i ) for i in range (self .cap_children_count ())]
318- self ._internal_dict = internal_dict
343+ self ._values = [self ._read_value (i ) for i in range (min (ARRAY_TO_STRING_LIMIT , self ._children_count ))]
319344
320345
321346 def cap_children_count (self ):
@@ -339,28 +364,106 @@ def get_child_at_index(self, index):
339364 return result
340365
341366 def to_string (self ):
342- return [self ._deref_or_obj_summary (i , self ._internal_dict .copy ()) for i in range (min (ARRAY_TO_STRING_LIMIT , self ._children_count ))]
367+ return '[%x]' % self ._children_count
368+ # return [self._deref_or_obj_summary(i, self._internal_dict.copy()) for i in range(min(ARRAY_TO_STRING_LIMIT, self._children_count))]
343369
344370
345371class KonanProxyTypeProvider :
346372 def __init__ (self , valobj , internal_dict ):
347373 log (lambda : "proxy: {:#x}" .format (valobj .unsigned ))
348374 tip = type_info (valobj )
375+ log (lambda : "KonanProxyTypeProvider: tip: {:#x}" .format (tip ))
349376 if not tip :
350377 return
351378 self ._proxy = select_provider (valobj , tip , internal_dict )
379+ log (lambda : "KonanProxyTypeProvider: _proxy: {}" .format (self ._proxy .__class__ .__name__ ))
352380 self .update ()
353381
354382 def __getattr__ (self , item ):
355383 return getattr (self ._proxy , item )
356384
357- def print_this_command (debugger , command , result , internal_dict ):
358- pthis = lldb .frame .FindVariable ('<this>' )
359- print (pthis )
360-
361385def clear_cache_command (debugger , command , result , internal_dict ):
362386 SYNTHETIC_OBJECT_LAYOUT_CACHE .clear ()
363387
388+
389+ def type_name_command (debugger , command , result , internal_dict ):
390+ result .AppendMessage (evaluate ('(char *)Konan_DebugGetTypeName({})' .format (command )).summary )
391+
392+ __KONAN_VARIABLE = re .compile ('kvar:(.*)#internal' )
393+ __KONAN_VARIABLE_TYPE = re .compile ('^kfun:<get-(.*)>\\ (\\ )(.*)$' )
394+ __TYPES_KONAN_TO_C = {
395+ 'kotlin.Byte' : ('int8_t' , lambda v : v .signed ),
396+ 'kotlin.Short' : ('short' , lambda v : v .signed ),
397+ 'kotlin.Int' : ('int' , lambda v : v .signed ),
398+ 'kotlin.Long' : ('long' , lambda v : v .signed ),
399+ 'kotlin.UByte' : ('int8_t' , lambda v : v .unsigned ),
400+ 'kotlin.UShort' : ('short' , lambda v : v .unsigned ),
401+ 'kotlin.UInt' : ('int' , lambda v : v .unsigned ),
402+ 'kotlin.ULong' : ('long' , lambda v : v .unsigned ),
403+ 'kotlin.Char' : ('short' , lambda v : v .signed ),
404+ 'kotlin.Boolean' : ('bool' , lambda v : v .signed ),
405+ 'kotlin.Float' : ('float' , lambda v : v .value ),
406+ 'kotlin.Double' : ('double' , lambda v : v .value )
407+ }
408+
409+ def type_by_address_command (debugger , command , result , internal_dict ):
410+ result .AppendMessage ("DEBUG: {}" .format (command ))
411+ tokens = command .split ()
412+ target = debugger .GetSelectedTarget ()
413+ process = target .GetProcess ()
414+ thread = process .GetSelectedThread ()
415+ types = _type_info_by_address (tokens [0 ])
416+ result .AppendMessage ("DEBUG: {}" .format (types ))
417+ for t in types :
418+ result .AppendMessage ("{}: {:#x}" .format (t .name , t .GetStartAddress ().GetLoadAddress (target )))
419+
420+ def symbol_by_name_command (debugger , command , result , internal_dict ):
421+ target = debugger .GetSelectedTarget ()
422+ process = target .GetProcess ()
423+ thread = process .GetSelectedThread ()
424+ frame = thread .GetSelectedFrame ()
425+ tokens = command .split ()
426+ mask = re .compile (tokens [0 ])
427+ symbols = list (filter (lambda v : mask .match (v .name ), frame .GetModule ().symbols ))
428+ visited = list ()
429+ for symbol in symbols :
430+ name = symbol .name
431+ if name in visited :
432+ continue
433+ visited .append (name )
434+ result .AppendMessage ("{}: {:#x}" .format (name , symbol .GetStartAddress ().GetLoadAddress (target )))
435+
436+ def konan_globals_command (debugger , command , result , internal_dict ):
437+ target = debugger .GetSelectedTarget ()
438+ process = target .GetProcess ()
439+ thread = process .GetSelectedThread ()
440+ frame = thread .GetSelectedFrame ()
441+
442+ konan_variable_symbols = list (filter (lambda v : __KONAN_VARIABLE .match (v .name ), frame .GetModule ().symbols ))
443+ visited = list ()
444+ for symbol in konan_variable_symbols :
445+ name = __KONAN_VARIABLE .search (symbol .name ).group (1 )
446+
447+ if name in visited :
448+ continue
449+ visited .append (name )
450+
451+ getters = list (filter (lambda v : re .match ('^kfun:<get-{}>\\ (\\ ).*$' .format (name ), v .name ), frame .module .symbols ))
452+ if not getters :
453+ result .AppendMessage ("storage not found for name:{}" .format (name ))
454+ continue
455+
456+ getter_functions = frame .module .FindFunctions (getters [0 ].name )
457+ if not getter_functions :
458+ continue
459+
460+ address = getter_functions [0 ].function .GetStartAddress ().GetLoadAddress (target )
461+ type = __KONAN_VARIABLE_TYPE .search (getters [0 ].name ).group (2 )
462+ (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 ))
464+ str_value = extractor (value )
465+ result .AppendMessage ('{} {}: {}' .format (type , name , str_value ))
466+
364467def __lldb_init_module (debugger , _ ):
365468 __FACTORY ['object' ] = lambda x , y , z : KonanObjectSyntheticProvider (x , y , z )
366469 __FACTORY ['array' ] = lambda x , y , z : KonanArraySyntheticProvider (x , z )
@@ -380,5 +483,7 @@ def __lldb_init_module(debugger, _):
380483 --category Kotlin\
381484 ' )
382485 debugger .HandleCommand ('type category enable Kotlin' )
383- debugger .HandleCommand ('command script add -f {}.print_this_command print_this' .format (__name__ ))
384486 debugger .HandleCommand ('command script add -f {}.clear_cache_command clear_kotlin_cache' .format (__name__ ))
487+ debugger .HandleCommand ('command script add -f {}.type_name_command type_name' .format (__name__ ))
488+ debugger .HandleCommand ('command script add -f {}.type_by_address_command type_by_address' .format (__name__ ))
489+ debugger .HandleCommand ('command script add -f {}.symbol_by_name_command symbol_by_name' .format (__name__ ))
0 commit comments