[lldb] Add synthetic frontend for _NSCallStackArray

An Obj-C array type _NSCallStackArray is used in NSException backtraces. This patch adds a synthetic frontend for _NSCallStackArray, which now correctly returns frame PCs.

Differential Revision: https://reviews.llvm.org/D44081

llvm-svn: 346708
diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index 8c6467e..6c110da 100644
--- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -214,6 +214,25 @@
 
 }
 
+namespace CallStackArray {
+struct DataDescriptor_32 {
+  uint32_t _data;
+  uint32_t _used;
+  uint32_t _offset;
+  const uint32_t _size = 0;
+};
+
+struct DataDescriptor_64 {
+  uint64_t _data;
+  uint64_t _used;
+  uint64_t _offset;
+  const uint64_t _size = 0;
+};
+
+using NSCallStackArraySyntheticFrontEnd =
+    GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+} // namespace CallStackArray
+
 template <typename D32, typename D64, bool Inline>
 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 public:
@@ -364,6 +383,7 @@
   static const ConstString g_NSArrayCF("__NSCFArray");
   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
+  static const ConstString g_NSCallStackArray("_NSCallStackArray");
 
   if (class_name.IsEmpty())
     return false;
@@ -413,7 +433,9 @@
     value = 0;
   } else if (class_name == g_NSArray1) {
     value = 1;
-  } else if (class_name == g_NSArrayCF) {
+  } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
+    // __NSCFArray and _NSCallStackArray store the number of elements as a
+    // pointer-sized value at offset `2 * ptr_size`.
     Status error;
     value = process_sp->ReadUnsignedIntegerFromMemory(
         valobj_addr + 2 * ptr_size, ptr_size, 0, error);
@@ -813,6 +835,7 @@
   static const ConstString g_NSArray1("__NSSingleObjectArrayI");
   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
+  static const ConstString g_NSCallStackArray("_NSCallStackArray");
 
   if (class_name.IsEmpty())
     return nullptr;
@@ -842,6 +865,8 @@
       return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
     else
       return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp));
+  } else if (class_name == g_NSCallStackArray) {
+    return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
   } else {
     auto &map(NSArray_Additionals::GetAdditionalSynthetics());
     auto iter = map.find(class_name), end = map.end();