Move konan_lldb.py with from the KMM plugin

This version of the konan_lldb.py has scripted breakpoints to avoid
stepping into <compiler-generated> routines.

^KT-63598
This commit is contained in:
Timofey Solonin
2023-11-18 18:05:14 +01:00
committed by Space Team
parent fd1641ef35
commit 22b2c1a587
@@ -1,7 +1,7 @@
#!/usr/bin/python
##
# Copyright 2010-2017 JetBrains s.r.o.
# Copyright 2010-2023 JetBrains s.r.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@ import traceback
NULL = 'null'
logging=False
exe_logging=False
exe_logging=True if (os.getenv('GLOG_log_dir') != None) else False # Same as in LLDBFrontend
bench_logging=False
def log(msg):
@@ -43,7 +43,7 @@ def log(msg):
def exelog(stmt):
if exe_logging:
f = open(os.getenv('HOME', '') + "/lldbexelog.txt", "a")
f = open(os.getenv('GLOG_log_dir', '') + "/konan_lldb.log", "a")
f.write(stmt())
f.write("\n")
f.close()
@@ -84,6 +84,8 @@ def _symbol_loaded_address(name, debugger = lldb.debugger):
log(lambda: "_symbol_loaded_address:{} {:#x}".format(name, address))
return address
return 0
def _type_info_by_address(address, debugger = lldb.debugger):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
@@ -123,6 +125,7 @@ __FACTORY = {}
SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
TO_STRING_DEPTH = 2
ARRAY_TO_STRING_LIMIT = 10
TOTAL_MEMBERS_LIMIT = 50
_TYPE_CONVERSION = [
lambda obj, value, address, name: value.CreateValueFromExpression(name, "(void *){:#x}".format(address)),
@@ -192,11 +195,12 @@ def select_provider(lldb_val, tip, internal_dict):
return ret
class KonanHelperProvider(lldb.SBSyntheticValueProvider):
def __init__(self, valobj, amString, internal_dict = {}):
def __init__(self, valobj, amString, type_name, internal_dict = {}):
self._target = lldb.debugger.GetSelectedTarget()
self._process = self._target.GetProcess()
self._valobj = valobj
self._internal_dict = internal_dict.copy()
self._type_name = type_name
if amString:
return
if self._children_count == 0:
@@ -250,7 +254,7 @@ class KonanStringSyntheticProvider(KonanHelperProvider):
def __init__(self, valobj):
log(lambda: "KonanStringSyntheticProvider:{:#x} name:{}".format(valobj.unsigned, valobj.name))
self._children_count = 0
super(KonanStringSyntheticProvider, self).__init__(valobj, True)
super(KonanStringSyntheticProvider, self).__init__(valobj, True, "StringProvider")
fallback = valobj.GetValue()
buff_addr = evaluate("(void *)Konan_DebugBuffer()").unsigned
buff_len = evaluate(
@@ -296,7 +300,7 @@ class KonanObjectSyntheticProvider(KonanHelperProvider):
# Save an extra call into the process
log(lambda: "KonanObjectSyntheticProvider({:#x})".format(valobj.unsigned))
self._children_count = 0
super(KonanObjectSyntheticProvider, self).__init__(valobj, False, internal_dict)
super(KonanObjectSyntheticProvider, self).__init__(valobj, False, "ObjectProvider", internal_dict)
self._children = [self._field_name(i) for i in range(self._children_count)]
log(lambda: "KonanObjectSyntheticProvider::__init__({:#x}) _children:{}".format(self._valobj.unsigned,
self._children))
@@ -346,7 +350,7 @@ class KonanObjectSyntheticProvider(KonanHelperProvider):
class KonanArraySyntheticProvider(KonanHelperProvider):
def __init__(self, valobj, internal_dict):
self._children_count = 0
super(KonanArraySyntheticProvider, self).__init__(valobj, False, internal_dict)
super(KonanArraySyntheticProvider, self).__init__(valobj, False, "ArrayProvider", internal_dict)
log(lambda: "KonanArraySyntheticProvider: valobj:{:#x}".format(valobj.unsigned))
if self._valobj is None:
return
@@ -452,9 +456,38 @@ class KonanProxyTypeProvider:
def __getattr__(self, item):
return getattr(self._proxy, item)
def strip_quotes(name):
return "" if (name == None) else name.strip('"')
def type_name_command(debugger, command, result, internal_dict):
result.AppendMessage(evaluate('(char *)Konan_DebugGetTypeName({})'.format(command)).summary)
def get_runtime_type(variable):
return strip_quotes(evaluate("(char *)Konan_DebugGetTypeName({:#x})".format(variable.unsigned)).summary)
def field_type_command(debugger, field_address, exe_ctx, result, internal_dict):
"""
Returns runtime type of foo.bar.baz field in the form "(foo.bar.baz <TYPE_NAME>)".
If requested field could not be traced, then "<NO_FIELD_FOUND>" plug is used for type name.
"""
fields = field_address.split('.')
variable = exe_ctx.GetFrame().FindVariable(fields[0])
provider = None
for field_name in fields[1:]:
if (variable != None):
provider = KonanProxyTypeProvider(variable, internal_dict)
field_index = provider.get_child_index(field_name)
variable = provider.get_child_at_index(field_index)
else:
break
desc = "<NO_FIELD_FOUND>"
if (variable != None):
rt = get_runtime_type(variable)
if (len(rt) > 0):
desc = rt
result.write("{}".format(desc))
__KONAN_VARIABLE = re.compile('kvar:(.*)#internal')
@@ -536,6 +569,64 @@ def konan_globals_command(debugger, command, result, internal_dict):
result.AppendMessage('{} {}: {}'.format(type, name, str_value))
class KonanStep(object):
def __init__(self, thread_plan):
self.thread_plan = thread_plan
self.step_thread_plan = self.queue_thread_plan()
debugger = thread_plan.GetThread().GetProcess().GetTarget().GetDebugger()
self.avoid_no_debug = debugger.GetInternalVariableValue('target.process.thread.step-in-avoid-nodebug',
debugger.GetInstanceName()).GetStringAtIndex(0)
def explains_stop(self, event):
return True
def should_stop(self, event):
frame = self.thread_plan.GetThread().GetFrameAtIndex(0)
source_file = frame.GetLineEntry().GetFileSpec().GetFilename()
if self.avoid_no_debug == 'true' and source_file in [None, '<compiler-generated>']:
self.step_thread_plan = self.queue_thread_plan()
return False
self.thread_plan.SetPlanComplete(True)
return True
def should_step(self):
return True
def queue_thread_plan(self):
address = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPCAddress()
line_entry = self.thread_plan.GetThread().GetFrameAtIndex(0).GetLineEntry()
begin_address = line_entry.GetStartAddress().GetFileAddress()
end_address = line_entry.GetEndAddress().GetFileAddress()
return self.do_queue_thread_plan(address, end_address - begin_address)
class KonanStepIn(KonanStep):
def __init__(self, thread_plan, dict, *args):
KonanStep.__init__(self, thread_plan)
def do_queue_thread_plan(self, address, offset):
return self.thread_plan.QueueThreadPlanForStepInRange(address, offset)
class KonanStepOver(KonanStep):
def __init__(self, thread_plan, dict, *args):
KonanStep.__init__(self, thread_plan)
def do_queue_thread_plan(self, address, offset):
return self.thread_plan.QueueThreadPlanForStepOverRange(address, offset)
class KonanStepOut(KonanStep):
def __init__(self, thread_plan, dict, *args):
KonanStep.__init__(self, thread_plan)
def do_queue_thread_plan(self, address, offset):
return self.thread_plan.QueueThreadPlanForStepOut(0)
def __lldb_init_module(debugger, _):
log(lambda: "init start")
__FACTORY['object'] = lambda x, y, z: KonanObjectSyntheticProvider(x, y, z)
@@ -556,7 +647,9 @@ def __lldb_init_module(debugger, _):
--category Kotlin\
')
debugger.HandleCommand('type category enable Kotlin')
debugger.HandleCommand('command script add -f {}.type_name_command type_name'.format(__name__))
debugger.HandleCommand('command script add -f {}.field_type_command field_type'.format(__name__))
debugger.HandleCommand('command script add -f {}.type_by_address_command type_by_address'.format(__name__))
debugger.HandleCommand('command script add -f {}.symbol_by_name_command symbol_by_name'.format(__name__))
# Avoid Kotlin/Native runtime
debugger.HandleCommand('settings set target.process.thread.step-avoid-regexp ^::Kotlin_')
log(lambda: "init end")