blob: 300c3cb7124d017f1aa6c4b076e51d38c224efad [file] [log] [blame]
"""
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