brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · 8812ba4 Raw
299 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# example summary provider for NSNumber9# the real summary is now C++ code built into LLDB10 11import lldb12import ctypes13import lldb.runtime.objc.objc_runtime14import lldb.formatters.metrics15import struct16import lldb.formatters.Logger17 18statistics = lldb.formatters.metrics.Metrics()19statistics.add_metric("invalid_isa")20statistics.add_metric("invalid_pointer")21statistics.add_metric("unknown_class")22statistics.add_metric("code_notrun")23 24# despite the similary to synthetic children providers, these classes are not25# trying to provide anything but the port number of an NSNumber, so they need not26# obey the interface specification for synthetic children providers27 28 29class NSTaggedNumber_SummaryProvider:30    def adjust_for_architecture(self):31        pass32 33    def __init__(self, valobj, info_bits, data, params):34        logger = lldb.formatters.Logger.Logger()35        self.valobj = valobj36        self.sys_params = params37        self.info_bits = info_bits38        self.data = data39        self.update()40 41    def update(self):42        logger = lldb.formatters.Logger.Logger()43        self.adjust_for_architecture()44 45    def value(self):46        logger = lldb.formatters.Logger.Logger()47        # in spite of the plenty of types made available by the public NSNumber API48        # only a bunch of these are actually used in the internal implementation49        # unfortunately, the original type information appears to be lost50        # so we try to at least recover the proper magnitude of the data51        if self.info_bits == 0:52            return "(char)" + str(ord(ctypes.c_char(chr(self.data % 256)).value))53        if self.info_bits == 4:54            return "(short)" + str(ctypes.c_short(self.data % (256 * 256)).value)55        if self.info_bits == 8:56            return "(int)" + str(57                ctypes.c_int(self.data % (256 * 256 * 256 * 256)).value58            )59        if self.info_bits == 12:60            return "(long)" + str(ctypes.c_long(self.data).value)61        else:62            return (63                "unexpected value:(info="64                + str(self.info_bits)65                + ", value = "66                + str(self.data)67                + ")"68            )69 70 71class NSUntaggedNumber_SummaryProvider:72    def adjust_for_architecture(self):73        pass74 75    def __init__(self, valobj, params):76        logger = lldb.formatters.Logger.Logger()77        self.valobj = valobj78        self.sys_params = params79        if not (self.sys_params.types_cache.char):80            self.sys_params.types_cache.char = self.valobj.GetType().GetBasicType(81                lldb.eBasicTypeChar82            )83        if not (self.sys_params.types_cache.short):84            self.sys_params.types_cache.short = self.valobj.GetType().GetBasicType(85                lldb.eBasicTypeShort86            )87        if not (self.sys_params.types_cache.ushort):88            self.sys_params.types_cache.ushort = self.valobj.GetType().GetBasicType(89                lldb.eBasicTypeUnsignedShort90            )91        if not (self.sys_params.types_cache.int):92            self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(93                lldb.eBasicTypeInt94            )95        if not (self.sys_params.types_cache.long):96            self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(97                lldb.eBasicTypeLong98            )99        if not (self.sys_params.types_cache.ulong):100            self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(101                lldb.eBasicTypeUnsignedLong102            )103        if not (self.sys_params.types_cache.longlong):104            self.sys_params.types_cache.longlong = self.valobj.GetType().GetBasicType(105                lldb.eBasicTypeLongLong106            )107        if not (self.sys_params.types_cache.ulonglong):108            self.sys_params.types_cache.ulonglong = self.valobj.GetType().GetBasicType(109                lldb.eBasicTypeUnsignedLongLong110            )111        if not (self.sys_params.types_cache.float):112            self.sys_params.types_cache.float = self.valobj.GetType().GetBasicType(113                lldb.eBasicTypeFloat114            )115        if not (self.sys_params.types_cache.double):116            self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(117                lldb.eBasicTypeDouble118            )119        self.update()120 121    def update(self):122        logger = lldb.formatters.Logger.Logger()123        self.adjust_for_architecture()124 125    def value(self):126        logger = lldb.formatters.Logger.Logger()127        global statistics128        # we need to skip the ISA, then the next byte tells us what to read129        # we then skip one other full pointer worth of data and then fetch the contents130        # if we are fetching an int64 value, one more pointer must be skipped131        # to get at our data132        data_type_vo = self.valobj.CreateChildAtOffset(133            "dt", self.sys_params.pointer_size, self.sys_params.types_cache.char134        )135        data_type = (data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F136        data_offset = 2 * self.sys_params.pointer_size137        if data_type == 0b00001:138            data_vo = self.valobj.CreateChildAtOffset(139                "data", data_offset, self.sys_params.types_cache.char140            )141            statistics.metric_hit("code_notrun", self.valobj)142            return "(char)" + str(143                ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value)144            )145        elif data_type == 0b0010:146            data_vo = self.valobj.CreateChildAtOffset(147                "data", data_offset, self.sys_params.types_cache.short148            )149            statistics.metric_hit("code_notrun", self.valobj)150            return "(short)" + str(151                ctypes.c_short(data_vo.GetValueAsUnsigned(0) % (256 * 256)).value152            )153        # IF tagged pointers are possible on 32bit+v2 runtime154        # (of which the only existing instance should be iOS)155        # then values of this type might be tagged156        elif data_type == 0b0011:157            data_vo = self.valobj.CreateChildAtOffset(158                "data", data_offset, self.sys_params.types_cache.int159            )160            statistics.metric_hit("code_notrun", self.valobj)161            return "(int)" + str(162                ctypes.c_int(163                    data_vo.GetValueAsUnsigned(0) % (256 * 256 * 256 * 256)164                ).value165            )166        # apparently, on is_64_bit architectures, these are the only values that will ever167        # be represented by a non tagged pointers168        elif data_type == 0b10001:169            data_offset = data_offset + 8  # 8 is needed even if we are on 32bit170            data_vo = self.valobj.CreateChildAtOffset(171                "data", data_offset, self.sys_params.types_cache.longlong172            )173            statistics.metric_hit("code_notrun", self.valobj)174            return "(long)" + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)175        elif data_type == 0b0100:176            if self.sys_params.is_64_bit:177                data_offset = data_offset + self.sys_params.pointer_size178            data_vo = self.valobj.CreateChildAtOffset(179                "data", data_offset, self.sys_params.types_cache.longlong180            )181            statistics.metric_hit("code_notrun", self.valobj)182            return "(long)" + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)183        elif data_type == 0b0101:184            data_vo = self.valobj.CreateChildAtOffset(185                "data", data_offset, self.sys_params.types_cache.longlong186            )187            data_plain = int(str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF))188            packed = struct.pack("I", data_plain)189            data_float = struct.unpack("f", packed)[0]190            statistics.metric_hit("code_notrun", self.valobj)191            return "(float)" + str(data_float)192        elif data_type == 0b0110:193            data_vo = self.valobj.CreateChildAtOffset(194                "data", data_offset, self.sys_params.types_cache.longlong195            )196            data_plain = data_vo.GetValueAsUnsigned(0)197            data_double = struct.unpack("d", struct.pack("Q", data_plain))[0]198            statistics.metric_hit("code_notrun", self.valobj)199            return "(double)" + str(data_double)200        statistics.metric_hit(201            "unknown_class",202            str(valobj.GetName()) + " had unknown data_type " + str(data_type),203        )204        return "unexpected: dt = " + str(data_type)205 206 207class NSUnknownNumber_SummaryProvider:208    def adjust_for_architecture(self):209        pass210 211    def __init__(self, valobj, params):212        logger = lldb.formatters.Logger.Logger()213        self.valobj = valobj214        self.sys_params = params215        self.update()216 217    def update(self):218        logger = lldb.formatters.Logger.Logger()219        self.adjust_for_architecture()220 221    def value(self):222        logger = lldb.formatters.Logger.Logger()223        stream = lldb.SBStream()224        self.valobj.GetExpressionPath(stream)225        expr = "(NSString*)[" + stream.GetData() + " stringValue]"226        num_children_vo = self.valobj.CreateValueFromExpression("str", expr)227        if num_children_vo.IsValid():228            return num_children_vo.GetSummary()229        return "<variable is not NSNumber>"230 231 232def GetSummary_Impl(valobj):233    logger = lldb.formatters.Logger.Logger()234    global statistics235    (236        class_data,237        wrapper,238    ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(239        valobj, statistics240    )241    if wrapper:242        return wrapper243 244    name_string = class_data.class_name()245    logger >> "class name is: " + str(name_string)246 247    if name_string == "NSNumber" or name_string == "__NSCFNumber":248        if class_data.is_tagged():249            wrapper = NSTaggedNumber_SummaryProvider(250                valobj,251                class_data.info_bits(),252                class_data.value(),253                class_data.sys_params,254            )255            statistics.metric_hit("code_notrun", valobj)256        else:257            # the wrapper might be unable to decipher what is into the NSNumber258            # and then have to run code on it259            wrapper = NSUntaggedNumber_SummaryProvider(valobj, class_data.sys_params)260    else:261        wrapper = NSUnknownNumber_SummaryProvider(valobj, class_data.sys_params)262        statistics.metric_hit(263            "unknown_class", valobj.GetName() + " seen as " + name_string264        )265    return wrapper266 267 268def NSNumber_SummaryProvider(valobj, dict):269    logger = lldb.formatters.Logger.Logger()270    provider = GetSummary_Impl(valobj)271    if provider is not None:272        if isinstance(273            provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description274        ):275            return provider.message()276        try:277            summary = provider.value()278        except Exception as foo:279            print(foo)280            # 		except:281            summary = None282        logger >> "got summary " + str(summary)283        if summary is None:284            summary = "<variable is not NSNumber>"285        return str(summary)286    return "Summary Unavailable"287 288 289def __lldb_init_module(debugger, dict):290    debugger.HandleCommand(291        "type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber"292    )293    debugger.HandleCommand(294        "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean"295    )296    debugger.HandleCommand(297        "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber"298    )299