Skip to content

Commit 1d14300

Browse files
committed
Fix Swift and ObjC debugging.
1 parent 8dfe289 commit 1d14300

14 files changed

+250
-236
lines changed

LLDBPlugin/lldb/__init__.pyi

+96-102
Large diffs are not rendered by default.

LLDBPlugin/run.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,22 @@
22

33
import os
44
import subprocess
5+
import sys
56

67
import lldb
78

9+
10+
def tracefunc(frame, event, arg, indent=[0]):
11+
if event == "call":
12+
indent[0] += 2
13+
print("-" * indent[0] + "> call function", frame.f_code.co_name)
14+
elif event == "return":
15+
print("<" + "-" * indent[0], "exit function", frame.f_code.co_name)
16+
indent[0] -= 2
17+
return tracefunc
18+
19+
# sys.setprofile(tracefunc)
20+
821
gradle_invoke = subprocess.Popen(['./gradlew', 'compileSwift'], cwd='test_project')
922
gradle_exit_code = gradle_invoke.wait()
1023

@@ -28,6 +41,9 @@
2841
debugger.SetAsync(False)
2942

3043
# debugger.HandleCommand('log enable lldb default')
44+
# debugger.HandleCommand('log enable lldb default')
45+
debugger.HandleCommand('log enable lldb commands')
46+
debugger.HandleCommand('log enable lldb types')
3147

3248
# Import our module
3349
debugger.HandleCommand('command script import touchlab_kotlin_lldb')
@@ -42,16 +58,17 @@
4258

4359
if process:
4460
import time
61+
4562
start = time.perf_counter()
46-
debugger.HandleCommand('fr v --ptr-depth 16 -- string')
63+
debugger.HandleCommand('fr v -T --ptr-depth 16')
4764
print('HandleCommand took {:.6}s'.format(time.perf_counter() - start))
4865
process.Continue()
4966
# debugger.HandleCommand('fr v --ptr-depth 16 -- data')
50-
debugger.HandleCommand('fr v --ptr-depth 16')
67+
# debugger.HandleCommand('fr v --ptr-depth 16')
5168

5269
process.Kill()
5370

5471
# Finally, dispose of the debugger you just made.
5572
lldb.SBDebugger.Destroy(debugger)
5673
# Terminate the debug session
57-
lldb.SBDebugger.Terminate()
74+
lldb.SBDebugger.Terminate()

LLDBPlugin/touchlab_kotlin_lldb/__init__.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
KONAN_INIT_MODULE_NAME = '[0-9a-zA-Z_]+'
2020
KONAN_INIT_SUFFIX = '_kexe'
2121

22-
2322
def __lldb_init_module(debugger: lldb.SBDebugger, _):
2423
log(lambda: "init start")
2524

@@ -28,7 +27,7 @@ def __lldb_init_module(debugger: lldb.SBDebugger, _):
2827
register_commands(debugger)
2928
register_hooks(debugger)
3029

31-
configure_objc_types(debugger)
30+
configure_objc_types_init(debugger)
3231

3332
log(lambda: "init end")
3433

@@ -39,7 +38,7 @@ def reset_cache():
3938
LLDBCache.reset()
4039

4140

42-
def configure_objc_types(debugger: lldb.SBDebugger):
41+
def configure_objc_types_init(debugger: lldb.SBDebugger):
4342
target = debugger.GetDummyTarget()
4443
breakpoint = target.BreakpointCreateByRegex(
4544
"^{}({})({})?$".format(KONAN_INIT_PREFIX, KONAN_INIT_MODULE_NAME, KONAN_INIT_SUFFIX)
@@ -89,8 +88,7 @@ def configure_objc_types_breakpoint(frame: lldb.SBFrame, bp_loc: lldb.SBBreakpoi
8988
)
9089
)
9190

92-
debugger = target.debugger
93-
category = debugger.GetCategory(KOTLIN_CATEGORY)
91+
category = target.debugger.GetCategory(KOTLIN_CATEGORY)
9492

9593
for type_specifier in specifiers_to_register:
9694
category.AddTypeSummary(

LLDBPlugin/touchlab_kotlin_lldb/cache/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ def instance(cls):
1919
def __init__(self):
2020
self._debug_buffer_addr: Optional[int] = None
2121
self._debug_buffer_size: Optional[int] = None
22-
self._string_symbol_addr: Optional[int] = None
23-
self._list_symbol_addr: Optional[int] = None
24-
self._map_symbol_addr: Optional[int] = None
22+
self._string_symbol_value: Optional[lldb.value] = None
23+
self._list_symbol_value: Optional[lldb.value] = None
24+
self._map_symbol_value: Optional[lldb.value] = None
2525
self._helper_types_declared: bool = False
2626
self._type_info_type: Optional[lldb.SBType] = None
2727
self._obj_header_type: Optional[lldb.SBType] = None

LLDBPlugin/touchlab_kotlin_lldb/types/KonanArraySyntheticProvider.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def num_children(self):
2020
return self._children_count
2121

2222
def has_children(self):
23-
return self._children_count > 0
23+
return True
2424

2525
def get_child_index(self, name):
2626
log(lambda: "KonanArraySyntheticProvider::get_child_index({})".format(name))

LLDBPlugin/touchlab_kotlin_lldb/types/KonanBaseSyntheticProvider.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,21 @@
55

66
class KonanBaseSyntheticProvider(object):
77
def __init__(self, valobj: lldb.SBValue, type_info: lldb.value):
8+
super().__init__()
9+
810
self._valobj: lldb.SBValue = valobj
911
self._val: lldb.value = lldb.value(valobj.GetNonSyntheticValue())
1012
self._type_info: lldb.value = type_info
1113
self._process: lldb.SBProcess = lldb.debugger.GetSelectedTarget().process
1214

13-
super().__init__()
14-
15-
# We need to call it ourselves, because Xcode doesn't seem to call it in some cases
16-
self.update()
17-
1815
def update(self) -> bool:
1916
return False
2017

18+
def get_type_name(self) -> str:
19+
package_name = kotlin_object_to_string(self._process, self._type_info.packageName_.sbvalue.unsigned)
20+
relative_name = kotlin_object_to_string(self._process, self._type_info.relativeName_.sbvalue.unsigned)
21+
return '{}.{}'.format(package_name, relative_name)
22+
2123
def read_cstring(self, address: int) -> str:
2224
error = lldb.SBError()
2325
result = self._process.ReadCStringFromMemory(
@@ -35,4 +37,4 @@ def read_cstring(self, address: int) -> str:
3537
return result
3638

3739
def to_string(self):
38-
return kotlin_object_to_string(self._process, self._valobj.unsigned)
40+
return kotlin_object_to_string(self._process, self._valobj.unsigned)

LLDBPlugin/touchlab_kotlin_lldb/types/KonanListSyntheticProvider.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ def update(self):
3333
)
3434

3535
self._backing = backing
36-
else:
37-
self._backing.update()
36+
37+
self._backing.update()
3838
return False
3939

4040
def num_children(self):
4141
return self._backing.num_children()
4242

4343
def has_children(self):
44-
return self._backing.has_children()
44+
return True
4545

4646
def get_child_index(self, name):
4747
return self._backing.get_child_index(name)

LLDBPlugin/touchlab_kotlin_lldb/types/KonanMapSyntheticProvider.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ def update(self):
3333
raise DebuggerException(
3434
"Couldn't find backing for map {:#x}, name: {}".format(self._valobj.unsigned, self._valobj.name)
3535
)
36+
else:
37+
self._keys = keys
38+
self._values = values
3639

37-
self._keys = keys
38-
self._values = values
39-
else:
40-
self._keys.update()
41-
self._values.update()
40+
self._keys.update()
41+
self._values.update()
4242

4343
return False
4444

4545
def num_children(self):
4646
return self._keys.num_children()
4747

4848
def has_children(self):
49-
return self._keys.has_children()
49+
return True
5050

5151
def get_child_index(self, name):
5252
# TODO: Not correct, we need to look at the values which this doesn't do

LLDBPlugin/touchlab_kotlin_lldb/types/KonanObjectSyntheticProvider.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import lldb
22

33

4-
from .base import _TYPE_CONVERSION
4+
from .base import _TYPE_CONVERSION, type_info_type
55
from .KonanBaseSyntheticProvider import KonanBaseSyntheticProvider
66

77

88
class KonanObjectSyntheticProvider(KonanBaseSyntheticProvider):
99
def __init__(self, valobj: lldb.SBValue, type_info: lldb.value):
1010
self._children_count = 0
1111
self._children_names = []
12+
self._was_updated = False
1213

1314
super().__init__(valobj, type_info)
1415

1516
def update(self) -> bool:
17+
self._was_updated = True
1618
self._children_count = int(self._type_info.extendedInfo_.fieldsCount_)
1719
if self._children_count < 0:
1820
self._children_count = 0
@@ -27,7 +29,7 @@ def num_children(self):
2729
return self._children_count
2830

2931
def has_children(self):
30-
return self._children_count > 0
32+
return True
3133

3234
def get_child_index(self, name):
3335
# if self._children is None:
@@ -40,4 +42,3 @@ def get_child_at_index(self, index):
4042

4143
def get_child_address_at_index(self, index):
4244
return self._valobj.unsigned + int(self._type_info.extendedInfo_.fieldOffsets_[index])
43-

LLDBPlugin/touchlab_kotlin_lldb/types/base.py

+51-19
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
from ..util import strip_quotes, log, evaluate
66
from ..cache import LLDBCache
77

8-
KOTLIN_OBJ_HEADER_TYPE = lldb.SBTypeNameSpecifier('ObjHeader *', lldb.eMatchTypeNormal)
9-
KOTLIN_ARRAY_HEADER_TYPE = lldb.SBTypeNameSpecifier('ArrayHeader *', lldb.eMatchTypeNormal)
8+
KOTLIN_OBJ_HEADER_TYPE = lldb.SBTypeNameSpecifier('ObjHeader', lldb.eMatchTypeNormal)
9+
KOTLIN_ARRAY_HEADER_TYPE = lldb.SBTypeNameSpecifier('ArrayHeader', lldb.eMatchTypeNormal)
1010
KOTLIN_CATEGORY = 'Kotlin'
1111

1212
_TYPE_CONVERSION = [
@@ -55,28 +55,49 @@
5555
]
5656

5757

58+
def single_pointer(valobj: lldb.SBValue) -> lldb.SBValue:
59+
non_synthetic_value = valobj.GetNonSyntheticValue()
60+
61+
# TODO: Test how this behaves when stopped in C++
62+
# In case we've stopped in Swift, this will be true.
63+
if non_synthetic_value.type.IsReferenceType():
64+
return non_synthetic_value
65+
66+
while non_synthetic_value.type.GetPointeeType().IsPointerType():
67+
non_synthetic_value = non_synthetic_value.Dereference()
68+
69+
if not non_synthetic_value.type.IsPointerType():
70+
non_synthetic_value = non_synthetic_value.AddressOf()
71+
72+
return non_synthetic_value
73+
74+
75+
def obj_header_pointer(valobj: lldb.SBValue) -> lldb.SBValue:
76+
return single_pointer(valobj).Cast(obj_header_type())
77+
78+
5879
def get_runtime_type(variable):
5980
return strip_quotes(evaluate("(char *)Konan_DebugGetTypeName({:#x})", variable.unsigned).summary)
6081

6182

6283
def type_info_type() -> lldb.SBType:
6384
self = LLDBCache.instance()
6485
if self._type_info_type is None:
65-
self._type_info_type = evaluate('(TypeInfo*)0x0').type
86+
self._type_info_type = evaluate('(TypeInfo*)0x0').GetNonSyntheticValue().type
6687
return self._type_info_type
6788

6889

6990
def obj_header_type() -> lldb.SBType:
7091
self = LLDBCache.instance()
7192
if self._obj_header_type is None:
72-
self._obj_header_type = evaluate('(ObjHeader*)0x0').type
93+
self._obj_header_type = evaluate('(ObjHeader*)0x0').GetNonSyntheticValue().type
7394
return self._obj_header_type
7495

7596

7697
def array_header_type() -> lldb.SBType:
7798
self = LLDBCache.instance()
7899
if self._array_header_type is None:
79-
self._array_header_type = evaluate('(ArrayHeader*)0x0').type
100+
self._array_header_type = evaluate('(ArrayHeader*)0x0').GetNonSyntheticValue().type
80101
return self._array_header_type
81102

82103

@@ -96,8 +117,7 @@ def runtime_type_alignment() -> lldb.value:
96117
return self._runtime_type_alignment
97118

98119

99-
def _symbol_loaded_address(name: str, debugger: lldb.SBDebugger) -> int:
100-
target: lldb.SBTarget = debugger.GetSelectedTarget()
120+
def _symbol_loaded_address(name: str, target: lldb.SBTarget) -> int:
101121
candidates = target.FindSymbols(name)
102122
# take first
103123
for candidate in candidates:
@@ -108,25 +128,37 @@ def _symbol_loaded_address(name: str, debugger: lldb.SBDebugger) -> int:
108128
return 0
109129

110130

111-
def get_string_symbol_address() -> int:
131+
def _get_konan_class_symbol_value(cls_name: str) -> lldb.value:
132+
target = lldb.debugger.GetSelectedTarget()
133+
address = _symbol_loaded_address(f'kclass:{cls_name}', target)
134+
return lldb.value(
135+
target.CreateValueFromAddress(
136+
cls_name,
137+
lldb.SBAddress(address, target),
138+
type_info_type(),
139+
)
140+
)
141+
142+
143+
def get_string_symbol() -> lldb.value:
112144
self = LLDBCache.instance()
113-
if self._string_symbol_addr is None:
114-
self._string_symbol_addr = _symbol_loaded_address('kclass:kotlin.String', lldb.debugger)
115-
return self._string_symbol_addr
145+
if self._string_symbol_value is None:
146+
self._string_symbol_value = _get_konan_class_symbol_value('kotlin.String')
147+
return self._string_symbol_value
116148

117149

118-
def get_list_symbol_address() -> int:
150+
def get_list_symbol() -> lldb.value:
119151
self = LLDBCache.instance()
120-
if self._list_symbol_addr is None:
121-
self._list_symbol_addr = _symbol_loaded_address('kclass:kotlin.collections.List', lldb.debugger)
122-
return self._list_symbol_addr
152+
if self._list_symbol_value is None:
153+
self._list_symbol_value = _get_konan_class_symbol_value('kotlin.collections.List')
154+
return self._list_symbol_value
123155

124156

125-
def get_map_symbol_address() -> int:
157+
def get_map_symbol() -> lldb.value:
126158
self = LLDBCache.instance()
127-
if self._map_symbol_addr is None:
128-
self._map_symbol_addr = _symbol_loaded_address('kclass:kotlin.collections.Map', lldb.debugger)
129-
return self._map_symbol_addr
159+
if self._map_symbol_value is None:
160+
self._map_symbol_value = _get_konan_class_symbol_value('kotlin.collections.Map')
161+
return self._map_symbol_value
130162

131163

132164
class KnownValueType:

0 commit comments

Comments
 (0)