[debuging][bindings] evaluation/calculation optimizations borrowed from #2372
This commit is contained in:
@@ -52,29 +52,17 @@ def evaluate(expr):
|
|||||||
def is_instance_of(addr, typeinfo):
|
def is_instance_of(addr, typeinfo):
|
||||||
return evaluate("(bool)IsInstance({}, {})".format(addr, typeinfo)).GetValue() == "true"
|
return evaluate("(bool)IsInstance({}, {})".format(addr, typeinfo)).GetValue() == "true"
|
||||||
|
|
||||||
|
def is_string_or_array(value):
|
||||||
|
return evaluate("(bool)IsInstance({0}, theStringTypeInfo) ? 1 : ((int)Konan_DebugIsArray({0}) ? 2 : 0)".format(lldb_val_to_ptr(value))).unsigned
|
||||||
|
|
||||||
def is_string(value):
|
def type_info(value):
|
||||||
return is_instance_of(lldb_val_to_ptr(value), "theStringTypeInfo")
|
|
||||||
|
|
||||||
|
|
||||||
def is_array(value):
|
|
||||||
return evaluate("(int)Konan_DebugIsArray({})".format(lldb_val_to_ptr(value))).unsigned == 1
|
|
||||||
|
|
||||||
|
|
||||||
def check_type_info(value):
|
|
||||||
"""This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
|
"""This method checks self-referencing of pointer of first member of TypeInfo including case when object has an
|
||||||
meta-object pointed by TypeInfo. Two lower bits are reserved for memory management needs see runtime/src/main/cpp/Memory.h."""
|
meta-object pointed by TypeInfo. Two lower bits are reserved for memory management needs see runtime/src/main/cpp/Memory.h."""
|
||||||
if str(value.type) != "struct ObjHeader *":
|
if str(value.type) != "struct ObjHeader *":
|
||||||
return False
|
return False
|
||||||
expr = "*(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3) == **(void***)((uintptr_t)(*(void**){0:#x}) & ~0x3)".format(value.unsigned)
|
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)
|
||||||
result = evaluate(expr)
|
result = evaluate(expr)
|
||||||
return result.IsValid() and result.GetValue() == "true"
|
return result.unsigned if result.IsValid() and result.unsigned != 0 else None
|
||||||
|
|
||||||
def type_info(value):
|
|
||||||
return evaluate("*(void **)((uintptr_t)(*(void**){0:#x}) & ~0x3)".format(value.unsigned)).unsigned
|
|
||||||
|
|
||||||
#
|
|
||||||
# Some kind of forward declaration.
|
|
||||||
|
|
||||||
|
|
||||||
__FACTORY = {}
|
__FACTORY = {}
|
||||||
@@ -83,37 +71,39 @@ __FACTORY = {}
|
|||||||
# Cache type info pointer to [ChildMetaInfo]
|
# Cache type info pointer to [ChildMetaInfo]
|
||||||
SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
|
SYNTHETIC_OBJECT_LAYOUT_CACHE = {}
|
||||||
|
|
||||||
def kotlin_object_type_summary(lldb_val, internal_dict):
|
def kotlin_object_type_summary(lldb_val, internal_dict = []):
|
||||||
"""Hook that is run by lldb to display a Kotlin object."""
|
"""Hook that is run by lldb to display a Kotlin object."""
|
||||||
log(lambda: "kotlin_object_type_summary({:#x})".format(lldb_val.unsigned))
|
log(lambda: "kotlin_object_type_summary({:#x})".format(lldb_val.unsigned))
|
||||||
fallback = lldb_val.GetValue()
|
fallback = lldb_val.GetValue()
|
||||||
if str(lldb_val.type) != "struct ObjHeader *":
|
if str(lldb_val.type) != "struct ObjHeader *":
|
||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
if not check_type_info(lldb_val):
|
|
||||||
return NULL
|
|
||||||
|
|
||||||
ptr = lldb_val_to_ptr(lldb_val)
|
ptr = lldb_val_to_ptr(lldb_val)
|
||||||
if ptr is None:
|
if ptr is None:
|
||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
return select_provider(lldb_val).to_string()
|
tip = internal_dict["type_info"] if "type_info" in internal_dict.keys() else type_info(lldb_val)
|
||||||
|
if not tip:
|
||||||
|
return fallback
|
||||||
|
|
||||||
|
return select_provider(lldb_val, tip, internal_dict).to_string()
|
||||||
|
|
||||||
|
|
||||||
def select_provider(lldb_val):
|
def select_provider(lldb_val, tip, internal_dict):
|
||||||
return __FACTORY['string'](lldb_val) if is_string(lldb_val) else __FACTORY['array'](lldb_val) if is_array(
|
soa = is_string_or_array(lldb_val)
|
||||||
lldb_val) else __FACTORY['object'](lldb_val)
|
return __FACTORY['string'](lldb_val, tip, internal_dict) if soa == 1 else __FACTORY['array'](lldb_val, tip, internal_dict) if soa == 2 \
|
||||||
|
else __FACTORY['object'](lldb_val, tip, internal_dict)
|
||||||
|
|
||||||
class KonanHelperProvider(lldb.SBSyntheticValueProvider):
|
class KonanHelperProvider(lldb.SBSyntheticValueProvider):
|
||||||
def __init__(self, valobj):
|
def __init__(self, valobj, amString):
|
||||||
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._ptr = lldb_val_to_ptr(self._valobj)
|
self._ptr = lldb_val_to_ptr(self._valobj)
|
||||||
if is_string(valobj):
|
if amString:
|
||||||
return
|
return
|
||||||
self._children_count = evaluate("(int)Konan_DebugGetFieldCount({})".format(self._ptr)).signed
|
if self._children_count == 0:
|
||||||
|
self._children_count = evaluate("(int)Konan_DebugGetFieldCount({})".format(self._ptr)).signed
|
||||||
self._children = []
|
self._children = []
|
||||||
self._type_conversion = [
|
self._type_conversion = [
|
||||||
lambda address, name: self._valobj.CreateValueFromExpression(name, "(void *){:#x}".format(address)),
|
lambda address, name: self._valobj.CreateValueFromExpression(name, "(void *){:#x}".format(address)),
|
||||||
@@ -163,15 +153,23 @@ class KonanHelperProvider(lldb.SBSyntheticValueProvider):
|
|||||||
log(lambda: "type:{0} of {1:#x} of {2:#x}".format(type, self._valobj.unsigned, self._valobj.unsigned + self._children[index].offset()))
|
log(lambda: "type:{0} of {1:#x} of {2:#x}".format(type, self._valobj.unsigned, self._valobj.unsigned + self._children[index].offset()))
|
||||||
return type
|
return type
|
||||||
|
|
||||||
def _deref_or_obj_summary(self, index):
|
def _deref_or_obj_summary(self, index, internal_dict):
|
||||||
value = self._values[index]
|
value = self._values[index]
|
||||||
if not value:
|
if not value:
|
||||||
log(lambda : "_deref_or_obj_summary: value none, index:{}, type:{}".format(index, self._children[index].type()))
|
log(lambda : "_deref_or_obj_summary: value none, index:{}, type:{}".format(index, self._children[index].type()))
|
||||||
return None
|
return None
|
||||||
if check_type_info(value):
|
|
||||||
return kotlin_object_type_summary(value, None)
|
tip = type_info(value)
|
||||||
else:
|
if tip:
|
||||||
return kotlin_object_type_summary(value.deref, None)
|
internal_dict["type_info"] = tip
|
||||||
|
return kotlin_object_type_summary(value, internal_dict)
|
||||||
|
tip = type_info(value.deref)
|
||||||
|
|
||||||
|
if tip:
|
||||||
|
internal_dict["type_info"] = tip
|
||||||
|
return kotlin_object_type_summary(value.deref, internal_dict)
|
||||||
|
|
||||||
|
return kotlin_object_type_summary(value.deref, internal_dict)
|
||||||
|
|
||||||
def _field_address(self, index):
|
def _field_address(self, index):
|
||||||
return evaluate("(void *)Konan_DebugGetFieldAddress({}, {})".format(self._ptr, index)).unsigned
|
return evaluate("(void *)Konan_DebugGetFieldAddress({}, {})".format(self._ptr, index)).unsigned
|
||||||
@@ -181,7 +179,8 @@ class KonanHelperProvider(lldb.SBSyntheticValueProvider):
|
|||||||
|
|
||||||
class KonanStringSyntheticProvider(KonanHelperProvider):
|
class KonanStringSyntheticProvider(KonanHelperProvider):
|
||||||
def __init__(self, valobj):
|
def __init__(self, valobj):
|
||||||
super(KonanStringSyntheticProvider, self).__init__(valobj)
|
self._children_count = 0
|
||||||
|
super(KonanStringSyntheticProvider, self).__init__(valobj, True)
|
||||||
fallback = valobj.GetValue()
|
fallback = valobj.GetValue()
|
||||||
buff_len = evaluate(
|
buff_len = evaluate(
|
||||||
'(int)Konan_DebugObjectToUtf8Array({}, (char *)Konan_DebugBuffer(), (int)Konan_DebugBufferSize());'.format(
|
'(int)Konan_DebugObjectToUtf8Array({}, (char *)Konan_DebugBuffer(), (int)Konan_DebugBufferSize());'.format(
|
||||||
@@ -239,8 +238,16 @@ class MemberLayout:
|
|||||||
return self._offset
|
return self._offset
|
||||||
|
|
||||||
class KonanObjectSyntheticProvider(KonanHelperProvider):
|
class KonanObjectSyntheticProvider(KonanHelperProvider):
|
||||||
def __init__(self, valobj, tip):
|
def __init__(self, valobj, tip, internal_dict):
|
||||||
super(KonanObjectSyntheticProvider, self).__init__(valobj)
|
# Save an extra call into the process
|
||||||
|
if tip in SYNTHETIC_OBJECT_LAYOUT_CACHE:
|
||||||
|
log(lambda : "TIP: {:#x} EARLYHIT".format(tip))
|
||||||
|
self._children = SYNTHETIC_OBJECT_LAYOUT_CACHE[tip]
|
||||||
|
self._children_count = len(self._children)
|
||||||
|
else:
|
||||||
|
self._children_count = 0
|
||||||
|
|
||||||
|
super(KonanObjectSyntheticProvider, self).__init__(valobj, False)
|
||||||
|
|
||||||
if not tip in SYNTHETIC_OBJECT_LAYOUT_CACHE:
|
if not tip in SYNTHETIC_OBJECT_LAYOUT_CACHE:
|
||||||
SYNTHETIC_OBJECT_LAYOUT_CACHE[tip] = [
|
SYNTHETIC_OBJECT_LAYOUT_CACHE[tip] = [
|
||||||
@@ -274,16 +281,26 @@ class KonanObjectSyntheticProvider(KonanHelperProvider):
|
|||||||
return next(i for i,v in enumerate(self._children) if v.name() == name)
|
return next(i for i,v in enumerate(self._children) if v.name() == name)
|
||||||
|
|
||||||
def get_child_at_index(self, index):
|
def get_child_at_index(self, index):
|
||||||
return self._values[index]
|
result = self._values[index]
|
||||||
|
if result is None:
|
||||||
|
result = self._read_value(index)
|
||||||
|
self._values[index] = result
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
# TODO: fix cyclic structures stringification.
|
# TODO: fix cyclic structures stringification.
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
return dict([(self._children[i].name(), self._deref_or_obj_summary(i)) for i in range(self._children_count)])
|
if self._to_string_depth == 0:
|
||||||
|
return "..."
|
||||||
|
else:
|
||||||
|
internal_dict = self._internal_dict.copy()
|
||||||
|
internal_dict["to_string_depth"] = self._to_string_depth - 1
|
||||||
|
return dict([(self._children[i].name(), self._deref_or_obj_summary(i, internal_dict)) for i in range(self._children_count)])
|
||||||
|
|
||||||
class KonanArraySyntheticProvider(KonanHelperProvider):
|
class KonanArraySyntheticProvider(KonanHelperProvider):
|
||||||
def __init__(self, valobj):
|
def __init__(self, valobj, internal_dict):
|
||||||
super(KonanArraySyntheticProvider, self).__init__(valobj)
|
self._children_count = 0
|
||||||
|
super(KonanArraySyntheticProvider, self).__init__(valobj, False)
|
||||||
if self._ptr is None:
|
if self._ptr is None:
|
||||||
return
|
return
|
||||||
valobj.SetSyntheticChildrenGenerated(True)
|
valobj.SetSyntheticChildrenGenerated(True)
|
||||||
@@ -293,10 +310,15 @@ class KonanArraySyntheticProvider(KonanHelperProvider):
|
|||||||
offset = zerro_address - valobj.unsigned
|
offset = zerro_address - valobj.unsigned
|
||||||
size = first_address - zerro_address
|
size = first_address - zerro_address
|
||||||
self._children = [MemberLayout(str(x), type, offset + x * size) for x in range(self.num_children())]
|
self._children = [MemberLayout(str(x), type, offset + x * size) for x in range(self.num_children())]
|
||||||
self._values = [self._read_value(i) for i in range(self._children_count)]
|
self._values = [self._read_value(i) for i in range(self.cap_children_count())]
|
||||||
|
self._internal_dict = internal_dict
|
||||||
|
|
||||||
|
|
||||||
|
def cap_children_count(self):
|
||||||
|
return self._children_count
|
||||||
|
|
||||||
def num_children(self):
|
def num_children(self):
|
||||||
return self._children_count
|
return self.cap_children_count()
|
||||||
|
|
||||||
def has_children(self):
|
def has_children(self):
|
||||||
return self._children_count > 0
|
return self._children_count > 0
|
||||||
@@ -306,18 +328,23 @@ class KonanArraySyntheticProvider(KonanHelperProvider):
|
|||||||
return index if (0 <= index < self._children_count) else -1
|
return index if (0 <= index < self._children_count) else -1
|
||||||
|
|
||||||
def get_child_at_index(self, index):
|
def get_child_at_index(self, index):
|
||||||
return self._values[index]
|
result = self._values[index]
|
||||||
|
if result is None:
|
||||||
|
result = self._read_value(index)
|
||||||
|
self._values[index] = result
|
||||||
|
return result
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
return [self._deref_or_obj_summary(i) for i in range(self._children_count)]
|
return [self._deref_or_obj_summary(i) for i in range(self._children_count)]
|
||||||
|
|
||||||
|
|
||||||
class KonanProxyTypeProvider:
|
class KonanProxyTypeProvider:
|
||||||
def __init__(self, valobj, _):
|
def __init__(self, valobj, internal_dict):
|
||||||
log(lambda : "proxy: {:#x}".format(valobj.unsigned))
|
log(lambda : "proxy: {:#x}".format(valobj.unsigned))
|
||||||
if not check_type_info(valobj):
|
tip = type_info(valobj)
|
||||||
|
if not tip:
|
||||||
return
|
return
|
||||||
self._proxy = select_provider(valobj)
|
self._proxy = select_provider(valobj, tip, internal_dict)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
@@ -331,9 +358,9 @@ def clear_cache_command(debugger, command, result, internal_dict):
|
|||||||
SYNTHETIC_OBJECT_LAYOUT_CACHE.clear()
|
SYNTHETIC_OBJECT_LAYOUT_CACHE.clear()
|
||||||
|
|
||||||
def __lldb_init_module(debugger, _):
|
def __lldb_init_module(debugger, _):
|
||||||
__FACTORY['object'] = lambda x: KonanObjectSyntheticProvider(x, type_info(x))
|
__FACTORY['object'] = lambda x, y, z: KonanObjectSyntheticProvider(x, y, z)
|
||||||
__FACTORY['array'] = lambda x: KonanArraySyntheticProvider(x)
|
__FACTORY['array'] = lambda x, y, z: KonanArraySyntheticProvider(x, z)
|
||||||
__FACTORY['string'] = lambda x: KonanStringSyntheticProvider(x)
|
__FACTORY['string'] = lambda x, y, _: KonanStringSyntheticProvider(x)
|
||||||
debugger.HandleCommand('\
|
debugger.HandleCommand('\
|
||||||
type summary add \
|
type summary add \
|
||||||
--no-value \
|
--no-value \
|
||||||
|
|||||||
Reference in New Issue
Block a user