]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Language / ObjC / NSException.cpp
1 //===-- NSException.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/AST/DeclCXX.h"
11
12 #include "Cocoa.h"
13
14 #include "lldb/Core/ValueObject.h"
15 #include "lldb/Core/ValueObjectConstResult.h"
16 #include "lldb/DataFormatters/FormattersHelpers.h"
17 #include "lldb/Symbol/ClangASTContext.h"
18 #include "lldb/Target/ObjCLanguageRuntime.h"
19 #include "lldb/Target/ProcessStructReader.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/Endian.h"
23 #include "lldb/Utility/Status.h"
24 #include "lldb/Utility/Stream.h"
25
26 #include "Plugins/Language/ObjC/NSString.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
31
32 static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
33                           ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp,
34                           ValueObjectSP *reserved_sp) {
35   ProcessSP process_sp(valobj.GetProcessSP());
36   if (!process_sp)
37     return false;
38
39   lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
40
41   CompilerType valobj_type(valobj.GetCompilerType());
42   Flags type_flags(valobj_type.GetTypeInfo());
43   if (type_flags.AllClear(eTypeHasValue)) {
44     if (valobj.IsBaseClass() && valobj.GetParent())
45       ptr = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
46   } else {
47     ptr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
48   }
49
50   if (ptr == LLDB_INVALID_ADDRESS)
51     return false;
52   size_t ptr_size = process_sp->GetAddressByteSize();
53
54   Status error;
55   auto name = process_sp->ReadPointerFromMemory(ptr + 1 * ptr_size, error);
56   if (error.Fail() || name == LLDB_INVALID_ADDRESS)
57     return false;
58   auto reason = process_sp->ReadPointerFromMemory(ptr + 2 * ptr_size, error);
59   if (error.Fail() || reason == LLDB_INVALID_ADDRESS)
60     return false;
61   auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error);
62   if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS)
63     return false;
64   auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error);
65   if (error.Fail() || reserved == LLDB_INVALID_ADDRESS)
66     return false;
67
68   InferiorSizedWord name_isw(name, *process_sp);
69   InferiorSizedWord reason_isw(reason, *process_sp);
70   InferiorSizedWord userinfo_isw(userinfo, *process_sp);
71   InferiorSizedWord reserved_isw(reserved, *process_sp);
72
73   CompilerType voidstar = process_sp->GetTarget()
74                               .GetScratchClangASTContext()
75                               ->GetBasicType(lldb::eBasicTypeVoid)
76                               .GetPointerType();
77
78   if (name_sp)
79     *name_sp = ValueObject::CreateValueObjectFromData(
80         "name", name_isw.GetAsData(process_sp->GetByteOrder()),
81         valobj.GetExecutionContextRef(), voidstar);
82   if (reason_sp)
83     *reason_sp = ValueObject::CreateValueObjectFromData(
84         "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
85         valobj.GetExecutionContextRef(), voidstar);
86   if (userinfo_sp)
87     *userinfo_sp = ValueObject::CreateValueObjectFromData(
88         "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
89         valobj.GetExecutionContextRef(), voidstar);
90   if (reserved_sp)
91     *reserved_sp = ValueObject::CreateValueObjectFromData(
92         "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
93         valobj.GetExecutionContextRef(), voidstar);
94
95   return true;
96 }
97
98 bool lldb_private::formatters::NSException_SummaryProvider(
99     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
100   lldb::ValueObjectSP name_sp;
101   lldb::ValueObjectSP reason_sp;
102   if (!ExtractFields(valobj, &name_sp, &reason_sp, nullptr, nullptr))
103     return false;
104
105   if (!name_sp || !reason_sp)
106     return false;
107
108   StreamString name_str_summary;
109   StreamString reason_str_summary;
110   if (NSStringSummaryProvider(*name_sp, name_str_summary, options) &&
111       NSStringSummaryProvider(*reason_sp, reason_str_summary, options) &&
112       !name_str_summary.Empty() && !reason_str_summary.Empty()) {
113     stream.Printf("name: %s - reason: %s", name_str_summary.GetData(),
114                   reason_str_summary.GetData());
115     return true;
116   } else
117     return false;
118 }
119
120 class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
121 public:
122   NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
123       : SyntheticChildrenFrontEnd(*valobj_sp) {}
124
125   ~NSExceptionSyntheticFrontEnd() override = default;
126
127   size_t CalculateNumChildren() override {
128     return 4;
129   }
130
131   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
132     switch (idx) {
133       case 0: return m_name_sp;
134       case 1: return m_reason_sp;
135       case 2: return m_userinfo_sp;
136       case 3: return m_reserved_sp;
137     }
138     return lldb::ValueObjectSP();
139   }
140
141   bool Update() override {
142     m_name_sp.reset();
143     m_reason_sp.reset();
144     m_userinfo_sp.reset();
145     m_reserved_sp.reset();
146
147     return ExtractFields(m_backend, &m_name_sp, &m_reason_sp, &m_userinfo_sp,
148                          &m_reserved_sp);
149   }
150
151   bool MightHaveChildren() override { return true; }
152
153   size_t GetIndexOfChildWithName(const ConstString &name) override {
154     // NSException has 4 members:
155     //   NSString *name;
156     //   NSString *reason;
157     //   NSDictionary *userInfo;
158     //   id reserved;
159     static ConstString g___name("name");
160     static ConstString g___reason("reason");
161     static ConstString g___userInfo("userInfo");
162     static ConstString g___reserved("reserved");
163     if (name == g___name) return 0;
164     if (name == g___reason) return 1;
165     if (name == g___userInfo) return 2;
166     if (name == g___reserved) return 3;
167     return UINT32_MAX;
168   }
169
170 private:
171   ValueObjectSP m_name_sp;
172   ValueObjectSP m_reason_sp;
173   ValueObjectSP m_userinfo_sp;
174   ValueObjectSP m_reserved_sp;
175 };
176
177 SyntheticChildrenFrontEnd *
178 lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
179     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
180   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
181   if (!process_sp)
182     return nullptr;
183   ObjCLanguageRuntime *runtime =
184       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
185           lldb::eLanguageTypeObjC);
186   if (!runtime)
187     return nullptr;
188
189   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
190       runtime->GetClassDescriptor(*valobj_sp.get()));
191
192   if (!descriptor.get() || !descriptor->IsValid())
193     return nullptr;
194
195   const char *class_name = descriptor->GetClassName().GetCString();
196
197   if (!class_name || !*class_name)
198     return nullptr;
199
200   if (!strcmp(class_name, "NSException"))
201     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
202   else if (!strcmp(class_name, "NSCFException"))
203     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
204   else if (!strcmp(class_name, "__NSCFException"))
205     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
206
207   return nullptr;
208 }