24
24
import lldb
25
25
import struct
26
26
import re
27
+ import os
28
+ import sys
27
29
28
30
NULL = 'null'
29
31
@@ -32,12 +34,14 @@ def log(msg):
32
34
print (msg ())
33
35
34
36
def log2 (msg ):
35
- if True :
37
+ if False :
36
38
print (msg ())
37
39
38
- def exelog (stmt ):
40
+ def exelog (source , stmt ):
39
41
if False :
40
42
f = open (os .getenv ('HOME' , '' ) + "/lldbexelog.txt" , "a" )
43
+ f .write (source )
44
+ f .write (" - " )
41
45
f .write (stmt ())
42
46
f .write ("\n " )
43
47
f .close ()
@@ -47,11 +51,11 @@ def lldb_val_to_ptr(lldb_val):
47
51
return '((struct ObjHeader *) {:#x})' .format (addr )
48
52
49
53
50
- def evaluate (expr ):
54
+ def evaluate (source , expr ):
51
55
result = lldb .debugger .GetSelectedTarget ().EvaluateExpression (expr , lldb .SBExpressionOptions ())
52
56
evallog = lambda : "{} => {}" .format (expr , result )
53
57
log (evallog )
54
- exelog (evallog )
58
+ exelog (source , evallog )
55
59
return result
56
60
57
61
def _symbol_loaded_address (name , debugger = lldb .debugger ):
@@ -75,18 +79,18 @@ def _type_info_by_address(address, debugger = lldb.debugger):
75
79
return candidates
76
80
77
81
def 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"
79
83
80
84
def 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
82
86
83
87
def type_info (value ):
84
88
"""This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
85
89
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 *" :
87
91
return False
88
92
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 )
90
94
return result .unsigned if result .IsValid () and result .unsigned != 0 else None
91
95
92
96
@@ -100,23 +104,27 @@ def type_info(value):
100
104
101
105
def kotlin_object_type_summary (lldb_val , internal_dict = {}):
102
106
"""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 ))
104
108
fallback = lldb_val .GetValue ()
105
109
if str (lldb_val .type ) != "struct ObjHeader *" :
106
110
if lldb_val .GetValue () is None :
107
111
return NULL
108
112
return lldb_val .GetValueAsSigned ()
109
113
114
+ if lldb_val .unsigned == 0 :
115
+ return NULL
110
116
tip = internal_dict ["type_info" ] if "type_info" in internal_dict .keys () else type_info (lldb_val )
117
+
111
118
if not tip :
112
119
return fallback
113
120
114
121
return select_provider (lldb_val , tip , internal_dict ).to_string ()
115
122
116
123
117
124
def select_provider (lldb_val , tip , internal_dict ):
125
+ log (lambda : "select_provider: name:{} : {}, {}" .format (lldb_val .name , lldb_val , internal_dict ))
118
126
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 ))
120
128
return __FACTORY ['string' ](lldb_val , tip , internal_dict ) if soa == 1 else __FACTORY ['array' ](lldb_val , tip , internal_dict ) if soa == 2 \
121
129
else __FACTORY ['object' ](lldb_val , tip , internal_dict )
122
130
@@ -131,7 +139,7 @@ def __init__(self, valobj, amString, internal_dict = {}):
131
139
self ._internal_dict = internal_dict .copy ()
132
140
self ._to_string_depth = TO_STRING_DEPTH if "to_string_depth" not in self ._internal_dict .keys () else self ._internal_dict ["to_string_depth" ]
133
141
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 ()
135
143
self ._children = []
136
144
self ._type_conversion = [
137
145
lambda address , name : self ._valobj .CreateValueFromExpression (name , "(void *){:#x}" .format (address )),
@@ -159,8 +167,12 @@ def __init__(self, valobj, amString, internal_dict = {}):
159
167
valobj .GetType ().GetBasicType (lldb .eBasicTypeBool )
160
168
]
161
169
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
+
162
174
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 )
164
176
165
177
def _read_value (self , index ):
166
178
value_type = self ._children [index ].type ()
@@ -202,18 +214,18 @@ def _deref_or_obj_summary(self, index, internal_dict):
202
214
return kotlin_object_type_summary (value .deref , internal_dict )
203
215
204
216
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
206
218
207
219
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
209
221
210
222
class KonanStringSyntheticProvider (KonanHelperProvider ):
211
223
def __init__ (self , valobj ):
212
224
self ._children_count = 0
213
225
super (KonanStringSyntheticProvider , self ).__init__ (valobj , True )
214
226
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" ,
217
229
'(int)Konan_DebugObjectToUtf8Array({}, (void *){:#x}, (int)Konan_DebugBufferSize());' .format (
218
230
self ._ptr , buff_addr )
219
231
).signed
@@ -342,6 +354,9 @@ def __init__(self, valobj, internal_dict):
342
354
self ._children = [MemberLayout (str (x ), type , offset + x * size ) for x in range (self .num_children ())]
343
355
self ._values = [self ._read_value (i ) for i in range (min (ARRAY_TO_STRING_LIMIT , self ._children_count ))]
344
356
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 )
345
360
346
361
def cap_children_count (self ):
347
362
return self ._children_count
@@ -364,17 +379,18 @@ def get_child_at_index(self, index):
364
379
return result
365
380
366
381
def to_string (self ):
367
- return '[%x]' % self ._children_count
382
+ return '[%x]' % self ._real_child_count
368
383
# return [self._deref_or_obj_summary(i, self._internal_dict.copy()) for i in range(min(ARRAY_TO_STRING_LIMIT, self._children_count))]
369
384
370
385
371
386
class KonanProxyTypeProvider :
372
387
def __init__ (self , valobj , internal_dict ):
373
- log (lambda : "proxy : {:#x}" .format (valobj .unsigned ))
388
+ log (lambda : "KonanProxyTypeProvider : {:#x}" .format (valobj .unsigned ))
374
389
tip = type_info (valobj )
375
- log ( lambda : "KonanProxyTypeProvider: tip: {:#x}" . format ( tip ))
390
+
376
391
if not tip :
377
392
return
393
+ log (lambda : "KonanProxyTypeProvider: tip: {:#x}" .format (tip ))
378
394
self ._proxy = select_provider (valobj , tip , internal_dict )
379
395
log (lambda : "KonanProxyTypeProvider: _proxy: {}" .format (self ._proxy .__class__ .__name__ ))
380
396
self .update ()
@@ -387,7 +403,7 @@ def clear_cache_command(debugger, command, result, internal_dict):
387
403
388
404
389
405
def 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 )
391
407
392
408
__KONAN_VARIABLE = re .compile ('kvar:(.*)#internal' )
393
409
__KONAN_VARIABLE_TYPE = re .compile ('^kfun:<get-(.*)>\\ (\\ )(.*)$' )
@@ -460,7 +476,7 @@ def konan_globals_command(debugger, command, result, internal_dict):
460
476
address = getter_functions [0 ].function .GetStartAddress ().GetLoadAddress (target )
461
477
type = __KONAN_VARIABLE_TYPE .search (getters [0 ].name ).group (2 )
462
478
(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 ))
464
480
str_value = extractor (value )
465
481
result .AppendMessage ('{} {}: {}' .format (type , name , str_value ))
466
482
0 commit comments