Skip to content
objc_lldb.py 3.72 KiB
Newer Older
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):
Enrico Granata's avatar
Enrico Granata committed
		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
Enrico Granata's avatar
Enrico Granata committed
		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