diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -351,7 +351,7 @@ } static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream, - uint64_t value, lldb::LanguageType lang) { + int64_t value, lldb::LanguageType lang) { static ConstString g_TypeHint("NSNumber:long"); std::string prefix, suffix; @@ -456,16 +456,23 @@ return NSDecimalNumberSummaryProvider(valobj, stream, options); if (class_name == "NSNumber" || class_name == "__NSCFNumber") { - uint64_t value = 0; + int64_t value = 0; uint64_t i_bits = 0; - if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) { + if (descriptor->GetTaggedPointerInfoSigned(&i_bits, &value)) { + // Check for "preserved" numbers. We still don't support them yet. + if (i_bits & 0x8) { + lldbassert(!static_cast("We should handle preserved numbers!")); + return false; + } + switch (i_bits) { case 0: - NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); + NSNumber_FormatChar(valobj, stream, (char) value, + options.GetLanguage()); break; case 1: case 4: - NSNumber_FormatShort(valobj, stream, (short)value, + NSNumber_FormatShort(valobj, stream, (short) value, options.GetLanguage()); break; case 2: diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -41,6 +41,12 @@ return false; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; + } + uint64_t GetInstanceSize() override; ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; } @@ -253,7 +259,7 @@ ClassDescriptorV2Tagged( ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, - uint64_t payload) { + uint64_t u_payload, int64_t s_payload) { if (!actual_class_sp) { m_valid = false; return; @@ -264,9 +270,10 @@ return; } m_valid = true; - m_payload = payload; + m_payload = u_payload; m_info_bits = (m_payload & 0x0FULL); m_value_bits = (m_payload & ~0x0FULL) >> 4; + m_value_bits_signed = (s_payload & ~0x0FLL) >> 4; } ~ClassDescriptorV2Tagged() override = default; @@ -308,6 +315,18 @@ return true; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + if (info_bits) + *info_bits = GetInfoBits(); + if (value_bits) + *value_bits = GetValueBitsSigned(); + if (payload) + *payload = GetPayload(); + return true; + } + uint64_t GetInstanceSize() override { return (IsValid() ? m_pointer_size : 0); } @@ -318,6 +337,8 @@ // these calls are not part of any formal tagged pointers specification virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); } + + virtual int64_t GetValueBitsSigned() { return (IsValid() ? m_value_bits_signed : 0); } virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); } @@ -329,6 +350,7 @@ bool m_valid; uint64_t m_info_bits; uint64_t m_value_bits; + int64_t m_value_bits_signed; uint64_t m_payload; }; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -64,6 +64,12 @@ return false; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; + } + uint64_t GetInstanceSize() override { return m_instance_size; } ObjCISA GetISA() override { return m_isa; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -2457,7 +2457,6 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); if (!IsPossibleTaggedPointer(unobfuscated)) @@ -2485,12 +2484,16 @@ m_cache[slot] = actual_class_descriptor_sp; } - data_payload = + uint64_t data_payload = (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift); - + int64_t data_payload_signed = + ((int64_t) ((int64_t) unobfuscated + << m_objc_debug_taggedpointer_payload_lshift) >> + m_objc_debug_taggedpointer_payload_rshift); return ClassDescriptorSP( - new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); + new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload, + data_payload_signed)); } AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended( @@ -2542,7 +2545,6 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); if (!IsPossibleTaggedPointer(unobfuscated)) @@ -2573,12 +2575,16 @@ m_ext_cache[slot] = actual_class_descriptor_sp; } - data_payload = (((uint64_t)unobfuscated + uint64_t data_payload = (((uint64_t)unobfuscated + << m_objc_debug_taggedpointer_ext_payload_lshift) >> + m_objc_debug_taggedpointer_ext_payload_rshift); + int64_t data_payload_signed = ((int64_t) ((int64_t)unobfuscated << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); return ClassDescriptorSP( - new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); + new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload, + data_payload_signed)); } AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache( diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -86,11 +86,18 @@ } virtual bool IsValid() = 0; - + // There are two routines in the ObjC runtime that tagged pointer clients + // can call to get the value from their tagged pointer, one that retrieves + // it as an unsigned value and one a signed value. These two + // GetTaggedPointerInfo methods mirror those two ObjC runtime calls. virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, uint64_t *value_bits = nullptr, uint64_t *payload = nullptr) = 0; + virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) = 0; + virtual uint64_t GetInstanceSize() = 0; // use to implement version-specific additional constraints on pointers diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py @@ -45,7 +45,6 @@ '(Point) point = (v=7, h=12)', '(Point *) point_ptr = (v=7, h=12)', '(SEL) foo_selector = "foo_selector_impl"' ] - self.expect("frame variable", substrs=expect_strings) if self.getArchitecture() in ['i386', 'x86_64']: @@ -56,3 +55,28 @@ '(HIRect) hi_rect = origin=(x = 3, y = 5) size=(width = 4, height = 6)', ] self.expect("frame variable", substrs=extra_string) + + # The original tests left out testing the NSNumber values, so do that here. + # This set is all pointers, with summaries, so we only check the summary. + var_list_pointer = [ + ['NSNumber *', 'num1', '(int)5'], + ['NSNumber *', 'num2', '(float)3.140000'], + ['NSNumber *', 'num3', '(double)3.14'], + ['NSNumber *', 'num4', '(int128_t)18446744073709551614'], + ['NSNumber *', 'num5', '(char)65'], + ['NSNumber *', 'num6', '(long)255'], + ['NSNumber *', 'num7', '(long)2000000'], + ['NSNumber *', 'num8_Y', 'YES'], + ['NSNumber *', 'num8_N', 'NO'], + ['NSNumber *', 'num9', '(short)-31616'], + ['NSNumber *', 'num_at1', '(int)12'], + ['NSNumber *', 'num_at2', '(int)-12'], + ['NSNumber *', 'num_at3', '(double)12.5'], + ['NSNumber *', 'num_at4', '(double)-12.5'], + ['NSDecimalNumber *', 'decimal_number', '123456 x 10^-10'], + ['NSDecimalNumber *', 'decimal_number_neg', '-123456 x 10^10'] + ] + for type, var_path, summary in var_list_pointer: + self.expect_var_path(var_path, summary, None, type) + +