jingham created this revision.
jingham added a reviewer: JDevlieghere.
jingham requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

The ObjC runtime offers both signed & unsigned tagged pointer value
accessors to tagged pointer providers, but lldb's tagged pointer
code only implemented the unsigned one.  This patch adds an
emulation of the signed one.

      

The motivation for doing this is that NSNumbers use the signed
accessor (they are always signed) and we need to follow that in our
summary provider or we will get incorrect values for negative
NSNumbers.

      

The data-formatter-objc test file had NSNumber examples (along with lots of 
other
goodies) but the NSNumber values weren't tested.  So I also added
checks for those values to the test.

      

I also did a quick audit of the other types in that main.m file, and
it looks like pretty much all the other values are either intermediates
or are tested.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D99694

Files:
  lldb/source/Plugins/Language/ObjC/Cocoa.cpp
  
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
  lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
  
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
  lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py

Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py
+++ 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)
+
+            
Index: lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
+++ 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
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ 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(
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ 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; }
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ 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;
 };
 
Index: lldb/source/Plugins/Language/ObjC/Cocoa.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/Cocoa.cpp
+++ 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<bool>("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:
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to