Skip to content

Commit 934abda

Browse files
authored
Merge pull request #28 from touchlab/kpg/lldb_speed_up
Speeding up debugging
2 parents cb9580c + 7379aa7 commit 934abda

File tree

2 files changed

+78
-21
lines changed

2 files changed

+78
-21
lines changed

Kotlin.ideplugin/Contents/Resources/konan_lldb.py

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import lldb
2525
import struct
2626
import re
27+
import os
28+
import sys
2729

2830
NULL = 'null'
2931

@@ -32,12 +34,14 @@ def log(msg):
3234
print(msg())
3335

3436
def 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

5761
def _symbol_loaded_address(name, debugger = lldb.debugger):
@@ -75,18 +79,18 @@ def _type_info_by_address(address, debugger = lldb.debugger):
7579
return candidates
7680

7781
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"
7983

8084
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
8286

8387
def 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

101105
def 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

117124
def 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

210222
class 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

371386
class 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

389405
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)
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

setup-xcode11-dev.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
# Use this script for Xcode 11.
4+
5+
###################
6+
# This script is specifically for development of the plugin. Currently, the goal is just to move the new formatting scripts
7+
# into place. Much faster round trip than killing Xcode, etc.
8+
# Do *not* use this script if you're not actively developing the plugin.
9+
###################
10+
11+
###################
12+
# DEFINITIONS
13+
###################
14+
15+
service='Xcode'
16+
plugins_dir=~/Library/Developer/Xcode/Plug-ins
17+
18+
###################
19+
# CREATE PLUG-IN
20+
###################
21+
22+
echo "Creating new Kotlin plugin"
23+
mkdir -p $plugins_dir
24+
cp -r Kotlin.ideplugin $plugins_dir
25+
26+
###################
27+
# LLDB DEFINITIONS
28+
###################
29+
30+
lldb_config="command script import ~/Library/Developer/Xcode/Plug-ins/Kotlin.ideplugin/Contents/Resources/konan_lldb_config.py"
31+
lldb_format="command script import ~/Library/Developer/Xcode/Plug-ins/Kotlin.ideplugin/Contents/Resources/konan_lldb.py"
32+
33+
if grep --quiet -s konan_lldb ~/.lldbinit-Xcode
34+
then
35+
# code if found
36+
echo "konan_lldb.py found in ~/.lldbinit-Xcode"
37+
else
38+
# code if not found
39+
echo $lldb_config >> ~/.lldbinit-Xcode
40+
echo $lldb_format >> ~/.lldbinit-Xcode
41+
fi

0 commit comments

Comments
 (0)