Skip to content

Commit effe3c1

Browse files
authored
Merge pull request #1 from touchlab/master
PR
2 parents 560be10 + 8be78fe commit effe3c1

File tree

3 files changed

+72
-72
lines changed

3 files changed

+72
-72
lines changed

Kotlin.ideplugin/Contents/Info.plist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
<string>2FD51EF8-522D-4532-9698-980C4C497FD1</string>
4747
<!-- Xcode 11.1 (11A1027) -->
4848
<string>92CB09D8-3B74-4EF7-849C-99816039F0E7</string>
49+
<!-- Xcode 11.2 (11B52) -->
50+
<string>A74FBA51-FFEA-4409-B976-6FC3225A6F64</string>
51+
<!-- Xcode 11.3 (11C29) -->
52+
<string>BAB79788-ACEE-4291-826B-EC4667A6BEC5</string>
4953
</array>
5054
<key>XCPluginHasUI</key>
5155
<false/>

Kotlin.ideplugin/Contents/Resources/konan_lldb.py

Lines changed: 61 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,17 @@
2323

2424
import lldb
2525
import 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

3427
NULL = 'null'
3528

36-
CLIENT_APPCODE = is_appcode()
37-
CLIENT_XCODE = is_xcode()
38-
VISUAL_DEBUGGER = CLIENT_APPCODE or CLIENT_XCODE
39-
4029
def log(msg):
4130
if False:
42-
print(msg)
31+
print(msg())
4332

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

5645
def 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):
6655
def 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]
8672
SYNTHETIC_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

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

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

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

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

373364
def __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__))

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ not have permissions to do this. You'll need to run the script with sufficient p
4545
sudo ./colorsetup.sh
4646
```
4747

48+
## Kotlin 1.3.6x Issue
49+
50+
Using static frameworks and/or Cocoapods may remove debug info in this version. [More info here](https://github.com/JetBrains/kotlin-native/issues/3446)
51+
4852
### Special Note
4953

5054
All of that magic was sorted out by [Ellen Shapiro](https://github.com/designatednerd), who undrestands all of this
@@ -55,9 +59,10 @@ far better than I ever will.
5559
## Usage
5660

5761
If properly set up, you should be able to add Kotlin source to Xcode, set up breakpoints, and step through code.
58-
Be careful not to have Kotlin source added to the iOS Bundle output.
5962

60-
To help automate adding Kotlin source, check out the [Kotlin Xcode Sync](https://github.com/touchlab/KotlinXcodeSync) Gradle plugin.
63+
We're deprecating the Xcode Sync plugin. Add folder reference instead! [See issue](https://github.com/touchlab/xcode-kotlin/issues/16). Description and video coming soon.
64+
65+
~~To help automate adding Kotlin source, check out the [Kotlin Xcode Sync](https://github.com/touchlab/KotlinXcodeSync) Gradle plugin.~~
6166

6267
### Sample
6368

0 commit comments

Comments
 (0)