forked from OSchip/llvm-project
129 lines
3.6 KiB
Python
129 lines
3.6 KiB
Python
"""
|
|
Objective-C runtime wrapper - Replicates the behavior of AppleObjCRuntimeV2.cpp in Python code
|
|
for the benefit of synthetic children providers and Python summaries
|
|
|
|
part of The LLVM Compiler Infrastructure
|
|
This file is distributed under the University of Illinois Open Source
|
|
License. See LICENSE.TXT for details.
|
|
"""
|
|
import lldb
|
|
|
|
class ObjCRuntime:
|
|
|
|
def __init__(self,valobj = None):
|
|
self.valobj = valobj;
|
|
self.adjust_for_architecture()
|
|
|
|
def adjust_for_architecture(self):
|
|
self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
|
|
self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
|
|
self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
|
|
self.addr_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
|
|
self.addr_ptr_type = self.addr_type.GetPointerType()
|
|
|
|
def is_tagged(self):
|
|
if valobj is None:
|
|
return None
|
|
ptr_value = self.valobj.GetPointerValue()
|
|
if (ptr_value % 2) == 1:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def read_ascii(self, pointer):
|
|
process = self.valobj.GetTarget().GetProcess()
|
|
error = lldb.SBError()
|
|
pystr = ''
|
|
# cannot do the read at once because there is no length byte
|
|
while True:
|
|
content = process.ReadMemory(pointer, 1, error)
|
|
new_bytes = bytearray(content)
|
|
b0 = new_bytes[0]
|
|
pointer = pointer + 1
|
|
if b0 == 0:
|
|
break
|
|
pystr = pystr + chr(b0)
|
|
return pystr
|
|
|
|
def read_isa(self):
|
|
# read ISA pointer
|
|
isa_pointer = self.valobj.CreateChildAtOffset("cfisa",
|
|
0,
|
|
self.addr_ptr_type)
|
|
if isa_pointer == None or isa_pointer.IsValid() == False:
|
|
return None;
|
|
if isa_pointer.GetValue() == None:
|
|
return None;
|
|
isa = int(isa_pointer.GetValue(), 0)
|
|
if isa == 0 or isa == None:
|
|
return None;
|
|
return isa
|
|
|
|
|
|
def get_parent_class(self, isa = None):
|
|
if isa is None:
|
|
isa = self.read_isa()
|
|
# read superclass pointer
|
|
rw_pointer = isa + self.pointer_size
|
|
rw_object = self.valobj.CreateValueFromAddress("parent_isa",
|
|
rw_pointer,
|
|
self.addr_type)
|
|
if rw_object == None or rw_object.IsValid() == False:
|
|
return None;
|
|
if rw_object.GetValue() == None:
|
|
return None;
|
|
rw = int(rw_object.GetValue(), 0)
|
|
if rw == 0 or rw == None:
|
|
return None;
|
|
return rw
|
|
|
|
def get_class_name(self, isa = None):
|
|
if isa is None:
|
|
isa = self.read_isa()
|
|
# read rw pointer
|
|
rw_pointer = isa + 4 * self.pointer_size
|
|
rw_object = self.valobj.CreateValueFromAddress("rw",
|
|
rw_pointer,
|
|
self.addr_type)
|
|
if rw_object == None or rw_object.IsValid() == False:
|
|
return None;
|
|
if rw_object.GetValue() == None:
|
|
return None;
|
|
rw = int(rw_object.GetValue(), 0)
|
|
if rw == 0 or rw == None:
|
|
return None;
|
|
|
|
# read data pointer
|
|
data_pointer = rw + 8
|
|
data_object = self.valobj.CreateValueFromAddress("data",
|
|
data_pointer,
|
|
self.addr_type)
|
|
if data_object == None or data_object.IsValid() == False:
|
|
return None;
|
|
if data_object.GetValue() == None:
|
|
return None;
|
|
data = int(data_object.GetValue(), 0)
|
|
if data == 0 or data == None:
|
|
return None;
|
|
|
|
# read ro pointer
|
|
ro_pointer = data + 12 + self.pointer_size
|
|
if self.lp64:
|
|
ro_pointer += 4
|
|
ro_object = self.valobj.CreateValueFromAddress("ro",
|
|
ro_pointer,
|
|
self.addr_type)
|
|
if ro_object == None or ro_object.IsValid() == False:
|
|
return None;
|
|
if ro_object.GetValue() == None:
|
|
return None;
|
|
name_pointer = int(ro_object.GetValue(), 0)
|
|
if name_pointer == 0 or name_pointer == None:
|
|
return None;
|
|
|
|
# now read the actual name and compare it to known stuff
|
|
name_string = self.read_ascii(name_pointer)
|
|
if (name_string.startswith("NSKVONotify")):
|
|
return self.get_class_name(self.get_parent_class())
|
|
return name_string
|