[ObjC] Add dataformatter for NSDecimalNumber

This patch adds a data formatter for NSDecimalNumber. The latter is a
Foundation object used for representing and performing arithmetic on
base-10 numbers that bridges to Decimal.

Differential revision: https://reviews.llvm.org/D48114

llvm-svn: 334638
diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
index c185b81..8f278fc 100644
--- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
+++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -458,6 +458,9 @@
   if (class_name == "__NSCFBoolean")
     return ObjCBooleanSummaryProvider(valobj, stream, options);
 
+  if (class_name == "NSDecimalNumber")
+    return NSDecimalNumberSummaryProvider(valobj, stream, options);
+
   if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
     uint64_t value = 0;
     uint64_t i_bits = 0;
@@ -625,6 +628,55 @@
   return false;
 }
 
+bool lldb_private::formatters::NSDecimalNumberSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+  ProcessSP process_sp = valobj.GetProcessSP();
+  if (!process_sp)
+    return false;
+
+  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+  uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+  Status error;
+  int8_t exponent = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + ptr_size, 1, 0, error);
+  if (error.Fail())
+    return false;
+
+  uint8_t length_and_negative = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + ptr_size + 1, 1, 0, error);
+  if (error.Fail())
+    return false;
+
+  // Fifth bit marks negativity.
+  const bool is_negative = (length_and_negative >> 4) & 1;
+
+  // Zero length and negative means NaN.
+  uint8_t length = length_and_negative & 0xf;
+  const bool is_nan = is_negative && (length == 0);
+
+  if (is_nan) {
+    stream.Printf("NaN");
+    return true;
+  }
+
+  if (length == 0) {
+    stream.Printf("0");
+    return true;
+  }
+
+  uint64_t mantissa = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + ptr_size + 4, 8, 0, error);
+  if (error.Fail())
+    return false;
+
+  if (is_negative)
+    stream.Printf("-");
+
+  stream.Printf("%" PRIu64 " x 10^%" PRIi8, mantissa, exponent);
+  return true;
+}
+
 bool lldb_private::formatters::NSURLSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
   ProcessSP process_sp = valobj.GetProcessSP();