You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
6.9 KiB
209 lines
6.9 KiB
"""
|
|
LLDB AppKit formatters
|
|
|
|
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
See https://llvm.org/LICENSE.txt for license information.
|
|
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
"""
|
|
from __future__ import print_function
|
|
|
|
# summary provider for CF(Mutable)BitVector
|
|
import lldb
|
|
import ctypes
|
|
import lldb.runtime.objc.objc_runtime
|
|
import lldb.formatters.metrics
|
|
import lldb.formatters.Logger
|
|
|
|
# first define some utility functions
|
|
|
|
|
|
def byte_index(abs_pos):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
return abs_pos / 8
|
|
|
|
|
|
def bit_index(abs_pos):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
return abs_pos & 7
|
|
|
|
|
|
def get_bit(byte, index):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
if index < 0 or index > 7:
|
|
return None
|
|
return (byte >> (7 - index)) & 1
|
|
|
|
|
|
def grab_array_item_data(pointer, index):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
return pointer.GetPointeeData(index, 1)
|
|
|
|
statistics = lldb.formatters.metrics.Metrics()
|
|
statistics.add_metric('invalid_isa')
|
|
statistics.add_metric('invalid_pointer')
|
|
statistics.add_metric('unknown_class')
|
|
statistics.add_metric('code_notrun')
|
|
|
|
# despite the similary to synthetic children providers, these classes are not
|
|
# trying to provide anything but a summary for a CF*BitVector, so they need not
|
|
# obey the interface specification for synthetic children providers
|
|
|
|
|
|
class CFBitVectorKnown_SummaryProvider:
|
|
|
|
def adjust_for_architecture(self):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize()
|
|
pass
|
|
|
|
def __init__(self, valobj, params):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
self.valobj = valobj
|
|
self.sys_params = params
|
|
if not(self.sys_params.types_cache.NSUInteger):
|
|
if self.sys_params.is_64_bit:
|
|
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
|
|
).GetBasicType(lldb.eBasicTypeUnsignedLong)
|
|
else:
|
|
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
|
|
).GetBasicType(lldb.eBasicTypeUnsignedInt)
|
|
if not(self.sys_params.types_cache.charptr):
|
|
self.sys_params.types_cache.charptr = self.valobj.GetType(
|
|
).GetBasicType(lldb.eBasicTypeChar).GetPointerType()
|
|
self.update()
|
|
|
|
def update(self):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
self.adjust_for_architecture()
|
|
|
|
# we skip the CFRuntimeBase
|
|
# then the next CFIndex is the count
|
|
# then we skip another CFIndex and then we get at a byte array
|
|
# that wraps the individual bits
|
|
|
|
def contents(self):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
count_vo = self.valobj.CreateChildAtOffset(
|
|
"count",
|
|
self.sys_params.cfruntime_size,
|
|
self.sys_params.types_cache.NSUInteger)
|
|
count = count_vo.GetValueAsUnsigned(0)
|
|
if count == 0:
|
|
return '(empty)'
|
|
|
|
array_vo = self.valobj.CreateChildAtOffset(
|
|
"data",
|
|
self.sys_params.cfruntime_size +
|
|
2 *
|
|
self.uiint_size,
|
|
self.sys_params.types_cache.charptr)
|
|
|
|
data_list = []
|
|
cur_byte_pos = None
|
|
for i in range(0, count):
|
|
if cur_byte_pos is None:
|
|
cur_byte_pos = byte_index(i)
|
|
cur_byte = grab_array_item_data(array_vo, cur_byte_pos)
|
|
cur_byte_val = cur_byte.uint8[0]
|
|
else:
|
|
byte_pos = byte_index(i)
|
|
# do not fetch the pointee data every single time through
|
|
if byte_pos != cur_byte_pos:
|
|
cur_byte_pos = byte_pos
|
|
cur_byte = grab_array_item_data(array_vo, cur_byte_pos)
|
|
cur_byte_val = cur_byte.uint8[0]
|
|
bit = get_bit(cur_byte_val, bit_index(i))
|
|
if (i % 4) == 0:
|
|
data_list.append(' ')
|
|
if bit == 1:
|
|
data_list.append('1')
|
|
else:
|
|
data_list.append('0')
|
|
return ''.join(data_list)
|
|
|
|
|
|
class CFBitVectorUnknown_SummaryProvider:
|
|
|
|
def adjust_for_architecture(self):
|
|
pass
|
|
|
|
def __init__(self, valobj, params):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
self.valobj = valobj
|
|
self.sys_params = params
|
|
self.update()
|
|
|
|
def update(self):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
self.adjust_for_architecture()
|
|
|
|
def contents(self):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
return '<unable to summarize this CFBitVector>'
|
|
|
|
|
|
def GetSummary_Impl(valobj):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
global statistics
|
|
class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
|
|
valobj, statistics)
|
|
if wrapper:
|
|
return wrapper
|
|
|
|
name_string = class_data.class_name()
|
|
actual_name = name_string
|
|
|
|
logger >> "name string got was " + \
|
|
str(name_string) + " but actual name is " + str(actual_name)
|
|
|
|
if class_data.is_cftype():
|
|
# CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
|
|
# an NSCFType and then check we are a pointer-to CFBitVectorRef
|
|
valobj_type = valobj.GetType()
|
|
if valobj_type.IsValid() and valobj_type.IsPointerType():
|
|
valobj_type = valobj_type.GetPointeeType()
|
|
if valobj_type.IsValid():
|
|
actual_name = valobj_type.GetName()
|
|
if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector':
|
|
wrapper = CFBitVectorKnown_SummaryProvider(
|
|
valobj, class_data.sys_params)
|
|
statistics.metric_hit('code_notrun', valobj)
|
|
else:
|
|
wrapper = CFBitVectorUnknown_SummaryProvider(
|
|
valobj, class_data.sys_params)
|
|
print(actual_name)
|
|
else:
|
|
wrapper = CFBitVectorUnknown_SummaryProvider(
|
|
valobj, class_data.sys_params)
|
|
print(name_string)
|
|
statistics.metric_hit(
|
|
'unknown_class',
|
|
valobj.GetName() +
|
|
" seen as " +
|
|
name_string)
|
|
return wrapper
|
|
|
|
|
|
def CFBitVector_SummaryProvider(valobj, dict):
|
|
logger = lldb.formatters.Logger.Logger()
|
|
provider = GetSummary_Impl(valobj)
|
|
if provider is not None:
|
|
if isinstance(
|
|
provider,
|
|
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
|
|
return provider.message()
|
|
try:
|
|
summary = provider.contents()
|
|
except:
|
|
summary = None
|
|
logger >> "summary got from provider: " + str(summary)
|
|
if summary is None or summary == '':
|
|
summary = '<variable is not CFBitVector>'
|
|
return summary
|
|
return 'Summary Unavailable'
|
|
|
|
|
|
def __lldb_init_module(debugger, dict):
|
|
debugger.HandleCommand(
|
|
"type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef")
|