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:
committed by
Space Team
parent
fd1641ef35
commit
22b2c1a587
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/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");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -32,7 +32,7 @@ import traceback
|
|||||||
|
|
||||||
NULL = 'null'
|
NULL = 'null'
|
||||||
logging=False
|
logging=False
|
||||||
exe_logging=False
|
exe_logging=True if (os.getenv('GLOG_log_dir') != None) else False # Same as in LLDBFrontend
|
||||||
bench_logging=False
|
bench_logging=False
|
||||||
|
|
||||||
def log(msg):
|
def log(msg):
|
||||||
@@ -43,7 +43,7 @@ def log(msg):
|
|||||||
|
|
||||||
def exelog(stmt):
|
def exelog(stmt):
|
||||||
if exe_logging:
|
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(stmt())
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.close()
|
f.close()
|
||||||
@@ -84,6 +84,8 @@ def _symbol_loaded_address(name, debugger = lldb.debugger):
|
|||||||
log(lambda: "_symbol_loaded_address:{} {:#x}".format(name, address))
|
log(lambda: "_symbol_loaded_address:{} {:#x}".format(name, address))
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
def _type_info_by_address(address, debugger = lldb.debugger):
|
def _type_info_by_address(address, debugger = lldb.debugger):
|
||||||
target = debugger.GetSelectedTarget()
|
target = debugger.GetSelectedTarget()
|
||||||
process = target.GetProcess()
|
process = target.GetProcess()
|
||||||
@@ -123,6 +125,7 @@ __FACTORY = {}
|
|||||||
SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
|
SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
|
||||||
TO_STRING_DEPTH = 2
|
TO_STRING_DEPTH = 2
|
||||||
ARRAY_TO_STRING_LIMIT = 10
|
ARRAY_TO_STRING_LIMIT = 10
|
||||||
|
TOTAL_MEMBERS_LIMIT = 50
|
||||||
|
|
||||||
_TYPE_CONVERSION = [
|
_TYPE_CONVERSION = [
|
||||||
lambda obj, value, address, name: value.CreateValueFromExpression(name, "(void *){:#x}".format(address)),
|
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
|
return ret
|
||||||
|
|
||||||
class KonanHelperProvider(lldb.SBSyntheticValueProvider):
|
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._target = lldb.debugger.GetSelectedTarget()
|
||||||
self._process = self._target.GetProcess()
|
self._process = self._target.GetProcess()
|
||||||
self._valobj = valobj
|
self._valobj = valobj
|
||||||
self._internal_dict = internal_dict.copy()
|
self._internal_dict = internal_dict.copy()
|
||||||
|
self._type_name = type_name
|
||||||
if amString:
|
if amString:
|
||||||
return
|
return
|
||||||
if self._children_count == 0:
|
if self._children_count == 0:
|
||||||
@@ -250,7 +254,7 @@ class KonanStringSyntheticProvider(KonanHelperProvider):
|
|||||||
def __init__(self, valobj):
|
def __init__(self, valobj):
|
||||||
log(lambda: "KonanStringSyntheticProvider:{:#x} name:{}".format(valobj.unsigned, valobj.name))
|
log(lambda: "KonanStringSyntheticProvider:{:#x} name:{}".format(valobj.unsigned, valobj.name))
|
||||||
self._children_count = 0
|
self._children_count = 0
|
||||||
super(KonanStringSyntheticProvider, self).__init__(valobj, True)
|
super(KonanStringSyntheticProvider, self).__init__(valobj, True, "StringProvider")
|
||||||
fallback = valobj.GetValue()
|
fallback = valobj.GetValue()
|
||||||
buff_addr = evaluate("(void *)Konan_DebugBuffer()").unsigned
|
buff_addr = evaluate("(void *)Konan_DebugBuffer()").unsigned
|
||||||
buff_len = evaluate(
|
buff_len = evaluate(
|
||||||
@@ -296,7 +300,7 @@ class KonanObjectSyntheticProvider(KonanHelperProvider):
|
|||||||
# Save an extra call into the process
|
# Save an extra call into the process
|
||||||
log(lambda: "KonanObjectSyntheticProvider({:#x})".format(valobj.unsigned))
|
log(lambda: "KonanObjectSyntheticProvider({:#x})".format(valobj.unsigned))
|
||||||
self._children_count = 0
|
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)]
|
self._children = [self._field_name(i) for i in range(self._children_count)]
|
||||||
log(lambda: "KonanObjectSyntheticProvider::__init__({:#x}) _children:{}".format(self._valobj.unsigned,
|
log(lambda: "KonanObjectSyntheticProvider::__init__({:#x}) _children:{}".format(self._valobj.unsigned,
|
||||||
self._children))
|
self._children))
|
||||||
@@ -346,7 +350,7 @@ class KonanObjectSyntheticProvider(KonanHelperProvider):
|
|||||||
class KonanArraySyntheticProvider(KonanHelperProvider):
|
class KonanArraySyntheticProvider(KonanHelperProvider):
|
||||||
def __init__(self, valobj, internal_dict):
|
def __init__(self, valobj, internal_dict):
|
||||||
self._children_count = 0
|
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))
|
log(lambda: "KonanArraySyntheticProvider: valobj:{:#x}".format(valobj.unsigned))
|
||||||
if self._valobj is None:
|
if self._valobj is None:
|
||||||
return
|
return
|
||||||
@@ -452,9 +456,38 @@ class KonanProxyTypeProvider:
|
|||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
return getattr(self._proxy, 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):
|
def get_runtime_type(variable):
|
||||||
result.AppendMessage(evaluate('(char *)Konan_DebugGetTypeName({})'.format(command)).summary)
|
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')
|
__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))
|
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, _):
|
def __lldb_init_module(debugger, _):
|
||||||
log(lambda: "init start")
|
log(lambda: "init start")
|
||||||
__FACTORY['object'] = lambda x, y, z: KonanObjectSyntheticProvider(x, y, z)
|
__FACTORY['object'] = lambda x, y, z: KonanObjectSyntheticProvider(x, y, z)
|
||||||
@@ -556,7 +647,9 @@ def __lldb_init_module(debugger, _):
|
|||||||
--category Kotlin\
|
--category Kotlin\
|
||||||
')
|
')
|
||||||
debugger.HandleCommand('type category enable 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 {}.type_by_address_command type_by_address'.format(__name__))
|
||||||
debugger.HandleCommand('command script add -f {}.symbol_by_name_command symbol_by_name'.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")
|
log(lambda: "init end")
|
||||||
|
|||||||
Reference in New Issue
Block a user