| """ |
| Objective-C runtime wrapper for use by LLDB Python formatters |
| This is an old and deprecated version of the wrapper |
| The new code, to which everyone should convert, is in objc_runtime.py |
| |
| 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.is_64_bit = (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() |
| if isa is None: |
| return None |
| # 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() |
| if isa is None: |
| return None |
| # 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.is_64_bit: |
| 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 |