brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · cd554bf Raw
295 lines · python
1"""2LLDB AppKit formatters3 4Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5See https://llvm.org/LICENSE.txt for license information.6SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""8# summary provider for NSSet9import lldb10import ctypes11import lldb.runtime.objc.objc_runtime12import lldb.formatters.metrics13import CFBag14import lldb.formatters.Logger15 16statistics = lldb.formatters.metrics.Metrics()17statistics.add_metric("invalid_isa")18statistics.add_metric("invalid_pointer")19statistics.add_metric("unknown_class")20statistics.add_metric("code_notrun")21 22# despite the similary to synthetic children providers, these classes are not23# trying to provide anything but the port number of an NSMachPort, so they need not24# obey the interface specification for synthetic children providers25 26 27class NSCFSet_SummaryProvider:28    def adjust_for_architecture(self):29        pass30 31    def __init__(self, valobj, params):32        logger = lldb.formatters.Logger.Logger()33        self.valobj = valobj34        self.sys_params = params35        if not (self.sys_params.types_cache.NSUInteger):36            if self.sys_params.is_64_bit:37                self.sys_params.types_cache.NSUInteger = (38                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)39                )40            else:41                self.sys_params.types_cache.NSUInteger = (42                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)43                )44        self.update()45 46    def update(self):47        logger = lldb.formatters.Logger.Logger()48        self.adjust_for_architecture()49 50    # one pointer is the ISA51    # then we have one other internal pointer, plus52    # 4 bytes worth of flags. hence, these values53    def offset(self):54        logger = lldb.formatters.Logger.Logger()55        if self.sys_params.is_64_bit:56            return 2057        else:58            return 1259 60    def count(self):61        logger = lldb.formatters.Logger.Logger()62        vcount = self.valobj.CreateChildAtOffset(63            "count", self.offset(), self.sys_params.types_cache.NSUInteger64        )65        return vcount.GetValueAsUnsigned(0)66 67 68class NSSetUnknown_SummaryProvider:69    def adjust_for_architecture(self):70        pass71 72    def __init__(self, valobj, params):73        logger = lldb.formatters.Logger.Logger()74        self.valobj = valobj75        self.sys_params = params76        self.update()77 78    def update(self):79        logger = lldb.formatters.Logger.Logger()80        self.adjust_for_architecture()81 82    def count(self):83        logger = lldb.formatters.Logger.Logger()84        stream = lldb.SBStream()85        self.valobj.GetExpressionPath(stream)86        expr = "(int)[" + stream.GetData() + " count]"87        num_children_vo = self.valobj.CreateValueFromExpression("count", expr)88        if num_children_vo.IsValid():89            return num_children_vo.GetValueAsUnsigned(0)90        return "<variable is not NSSet>"91 92 93class NSSetI_SummaryProvider:94    def adjust_for_architecture(self):95        pass96 97    def __init__(self, valobj, params):98        logger = lldb.formatters.Logger.Logger()99        self.valobj = valobj100        self.sys_params = params101        if not (self.sys_params.types_cache.NSUInteger):102            if self.sys_params.is_64_bit:103                self.sys_params.types_cache.NSUInteger = (104                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)105                )106            else:107                self.sys_params.types_cache.NSUInteger = (108                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)109                )110        self.update()111 112    def update(self):113        logger = lldb.formatters.Logger.Logger()114        self.adjust_for_architecture()115 116    # we just need to skip the ISA and the count immediately follows117    def offset(self):118        logger = lldb.formatters.Logger.Logger()119        return self.sys_params.pointer_size120 121    def count(self):122        logger = lldb.formatters.Logger.Logger()123        num_children_vo = self.valobj.CreateChildAtOffset(124            "count", self.offset(), self.sys_params.types_cache.NSUInteger125        )126        value = num_children_vo.GetValueAsUnsigned(0)127        if value is not None:128            # the MSB on immutable sets seems to be taken by some other data129            # not sure if it is a bug or some weird sort of feature, but masking it out130            # gets the count right (unless, of course, someone's dictionaries grow131            #                       too large - but I have not tested this)132            if self.sys_params.is_64_bit:133                value = value & ~0xFF00000000000000134            else:135                value = value & ~0xFF000000136        return value137 138 139class NSSetM_SummaryProvider:140    def adjust_for_architecture(self):141        pass142 143    def __init__(self, valobj, params):144        logger = lldb.formatters.Logger.Logger()145        self.valobj = valobj146        self.sys_params = params147        if not (self.sys_params.types_cache.NSUInteger):148            if self.sys_params.is_64_bit:149                self.sys_params.types_cache.NSUInteger = (150                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)151                )152            else:153                self.sys_params.types_cache.NSUInteger = (154                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)155                )156        self.update()157 158    def update(self):159        logger = lldb.formatters.Logger.Logger()160        self.adjust_for_architecture()161 162    # we just need to skip the ISA and the count immediately follows163    def offset(self):164        logger = lldb.formatters.Logger.Logger()165        return self.sys_params.pointer_size166 167    def count(self):168        logger = lldb.formatters.Logger.Logger()169        num_children_vo = self.valobj.CreateChildAtOffset(170            "count", self.offset(), self.sys_params.types_cache.NSUInteger171        )172        return num_children_vo.GetValueAsUnsigned(0)173 174 175class NSCountedSet_SummaryProvider:176    def adjust_for_architecture(self):177        pass178 179    def __init__(self, valobj, params):180        logger = lldb.formatters.Logger.Logger()181        self.valobj = valobj182        self.sys_params = params183        if not (self.sys_params.types_cache.voidptr):184            self.sys_params.types_cache.voidptr = (185                self.valobj.GetType().GetBasicType(lldb.eBasicTypeVoid).GetPointerType()186            )187        self.update()188 189    def update(self):190        logger = lldb.formatters.Logger.Logger()191        self.adjust_for_architecture()192 193    # an NSCountedSet is implemented using a CFBag whose pointer just follows194    # the ISA195    def offset(self):196        logger = lldb.formatters.Logger.Logger()197        return self.sys_params.pointer_size198 199    def count(self):200        logger = lldb.formatters.Logger.Logger()201        cfbag_vo = self.valobj.CreateChildAtOffset(202            "bag_impl", self.offset(), self.sys_params.types_cache.voidptr203        )204        return CFBag.CFBagRef_SummaryProvider(cfbag_vo, self.sys_params).length()205 206 207def GetSummary_Impl(valobj):208    logger = lldb.formatters.Logger.Logger()209    global statistics210    (211        class_data,212        wrapper,213    ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(214        valobj, statistics215    )216    if wrapper:217        return wrapper218 219    name_string = class_data.class_name()220    logger >> "class name is: " + str(name_string)221 222    if name_string == "__NSCFSet":223        wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params)224        statistics.metric_hit("code_notrun", valobj)225    elif name_string == "__NSSetI":226        wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params)227        statistics.metric_hit("code_notrun", valobj)228    elif name_string == "__NSSetM":229        wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params)230        statistics.metric_hit("code_notrun", valobj)231    elif name_string == "NSCountedSet":232        wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params)233        statistics.metric_hit("code_notrun", valobj)234    else:235        wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params)236        statistics.metric_hit(237            "unknown_class", valobj.GetName() + " seen as " + name_string238        )239    return wrapper240 241 242def NSSet_SummaryProvider(valobj, dict):243    logger = lldb.formatters.Logger.Logger()244    provider = GetSummary_Impl(valobj)245    if provider is not None:246        try:247            summary = provider.count()248        except:249            summary = None250        if summary is None:251            summary = "<variable is not NSSet>"252        if isinstance(summary, str):253            return summary254        else:255            summary = str(summary) + (" objects" if summary != 1 else " object")256        return summary257    return "Summary Unavailable"258 259 260def NSSet_SummaryProvider2(valobj, dict):261    logger = lldb.formatters.Logger.Logger()262    provider = GetSummary_Impl(valobj)263    if provider is not None:264        if isinstance(265            provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description266        ):267            return provider.message()268        try:269            summary = provider.count()270        except:271            summary = None272        logger >> "got summary " + str(summary)273        # for some reason, one needs to clear some bits for the count returned274        # to be correct when using directly CF*SetRef as compared to NS*Set275        # this only happens on 64bit, and the bit mask was derived through276        # experimentation (if counts start looking weird, then most probably277        #                  the mask needs to be changed)278        if summary is None:279            summary = "<variable is not CFSet>"280        if isinstance(summary, str):281            return summary282        else:283            if provider.sys_params.is_64_bit:284                summary = summary & ~0x1FFF000000000000285            summary = '@"' + str(summary) + (' values"' if summary != 1 else ' value"')286        return summary287    return "Summary Unavailable"288 289 290def __lldb_init_module(debugger, dict):291    debugger.HandleCommand("type summary add -F NSSet.NSSet_SummaryProvider NSSet")292    debugger.HandleCommand(293        "type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef"294    )295