]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/Language/ObjC/NSException.cpp
Vendor import of lldb trunk r338150:
[FreeBSD/FreeBSD.git] / 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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 #include "clang/AST/DeclCXX.h"
14
15 // Project includes
16 #include "Cocoa.h"
17
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/DataFormatters/FormattersHelpers.h"
21 #include "lldb/Symbol/ClangASTContext.h"
22 #include "lldb/Target/ObjCLanguageRuntime.h"
23 #include "lldb/Target/ProcessStructReader.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Utility/DataBufferHeap.h"
26 #include "lldb/Utility/Endian.h"
27 #include "lldb/Utility/Status.h"
28 #include "lldb/Utility/Stream.h"
29
30 #include "Plugins/Language/ObjC/NSString.h"
31
32 using namespace lldb;
33 using namespace lldb_private;
34 using namespace lldb_private::formatters;
35
36 bool lldb_private::formatters::NSException_SummaryProvider(
37     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
38   ProcessSP process_sp(valobj.GetProcessSP());
39   if (!process_sp)
40     return false;
41
42   lldb::addr_t ptr_value = LLDB_INVALID_ADDRESS;
43
44   CompilerType valobj_type(valobj.GetCompilerType());
45   Flags type_flags(valobj_type.GetTypeInfo());
46   if (type_flags.AllClear(eTypeHasValue)) {
47     if (valobj.IsBaseClass() && valobj.GetParent())
48       ptr_value = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
49   } else
50     ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
51
52   if (ptr_value == LLDB_INVALID_ADDRESS)
53     return false;
54   size_t ptr_size = process_sp->GetAddressByteSize();
55   lldb::addr_t name_location = ptr_value + 1 * ptr_size;
56   lldb::addr_t reason_location = ptr_value + 2 * ptr_size;
57
58   Status error;
59   lldb::addr_t name = process_sp->ReadPointerFromMemory(name_location, error);
60   if (error.Fail() || name == LLDB_INVALID_ADDRESS)
61     return false;
62
63   lldb::addr_t reason =
64       process_sp->ReadPointerFromMemory(reason_location, error);
65   if (error.Fail() || reason == LLDB_INVALID_ADDRESS)
66     return false;
67
68   InferiorSizedWord name_isw(name, *process_sp);
69   InferiorSizedWord reason_isw(reason, *process_sp);
70
71   CompilerType voidstar = process_sp->GetTarget()
72                               .GetScratchClangASTContext()
73                               ->GetBasicType(lldb::eBasicTypeVoid)
74                               .GetPointerType();
75
76   ValueObjectSP name_sp = ValueObject::CreateValueObjectFromData(
77       "name_str", name_isw.GetAsData(process_sp->GetByteOrder()),
78       valobj.GetExecutionContextRef(), voidstar);
79   ValueObjectSP reason_sp = ValueObject::CreateValueObjectFromData(
80       "reason_str", reason_isw.GetAsData(process_sp->GetByteOrder()),
81       valobj.GetExecutionContextRef(), voidstar);
82
83   if (!name_sp || !reason_sp)
84     return false;
85
86   StreamString name_str_summary;
87   StreamString reason_str_summary;
88   if (NSStringSummaryProvider(*name_sp, name_str_summary, options) &&
89       NSStringSummaryProvider(*reason_sp, reason_str_summary, options) &&
90       !name_str_summary.Empty() && !reason_str_summary.Empty()) {
91     stream.Printf("name: %s - reason: %s", name_str_summary.GetData(),
92                   reason_str_summary.GetData());
93     return true;
94   } else
95     return false;
96 }
97
98 class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
99 public:
100   NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
101       : SyntheticChildrenFrontEnd(*valobj_sp) {}
102
103   ~NSExceptionSyntheticFrontEnd() override = default;
104   // no need to delete m_child_ptr - it's kept alive by the cluster manager on
105   // our behalf
106
107   size_t CalculateNumChildren() override {
108     if (m_child_ptr)
109       return 1;
110     if (m_child_sp)
111       return 1;
112     return 0;
113   }
114
115   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
116     if (idx != 0)
117       return lldb::ValueObjectSP();
118
119     if (m_child_ptr)
120       return m_child_ptr->GetSP();
121     return m_child_sp;
122   }
123
124   bool Update() override {
125     m_child_ptr = nullptr;
126     m_child_sp.reset();
127
128     ProcessSP process_sp(m_backend.GetProcessSP());
129     if (!process_sp)
130       return false;
131
132     lldb::addr_t userinfo_location = LLDB_INVALID_ADDRESS;
133
134     CompilerType valobj_type(m_backend.GetCompilerType());
135     Flags type_flags(valobj_type.GetTypeInfo());
136     if (type_flags.AllClear(eTypeHasValue)) {
137       if (m_backend.IsBaseClass() && m_backend.GetParent())
138         userinfo_location =
139             m_backend.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
140     } else
141       userinfo_location = m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
142
143     if (userinfo_location == LLDB_INVALID_ADDRESS)
144       return false;
145
146     size_t ptr_size = process_sp->GetAddressByteSize();
147
148     userinfo_location += 3 * ptr_size;
149     Status error;
150     lldb::addr_t userinfo =
151         process_sp->ReadPointerFromMemory(userinfo_location, error);
152     if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
153       return false;
154     InferiorSizedWord isw(userinfo, *process_sp);
155     m_child_sp = CreateValueObjectFromData(
156         "userInfo", isw.GetAsData(process_sp->GetByteOrder()),
157         m_backend.GetExecutionContextRef(),
158         process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(
159             lldb::eBasicTypeObjCID));
160     return false;
161   }
162
163   bool MightHaveChildren() override { return true; }
164
165   size_t GetIndexOfChildWithName(const ConstString &name) override {
166     static ConstString g___userInfo("userInfo");
167     if (name == g___userInfo)
168       return 0;
169     return UINT32_MAX;
170   }
171
172 private:
173   // the child here can be "real" (i.e. an actual child of the root) or
174   // synthetized from raw memory if the former, I need to store a plain pointer
175   // to it - or else a loop of references will cause this entire hierarchy of
176   // values to leak if the latter, then I need to store a SharedPointer to it -
177   // so that it only goes away when everyone else in the cluster goes away oh
178   // joy!
179   ValueObject *m_child_ptr;
180   ValueObjectSP m_child_sp;
181 };
182
183 SyntheticChildrenFrontEnd *
184 lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
185     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
186   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
187   if (!process_sp)
188     return nullptr;
189   ObjCLanguageRuntime *runtime =
190       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
191           lldb::eLanguageTypeObjC);
192   if (!runtime)
193     return nullptr;
194
195   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
196       runtime->GetClassDescriptor(*valobj_sp.get()));
197
198   if (!descriptor.get() || !descriptor->IsValid())
199     return nullptr;
200
201   const char *class_name = descriptor->GetClassName().GetCString();
202
203   if (!class_name || !*class_name)
204     return nullptr;
205
206   if (!strcmp(class_name, "NSException"))
207     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
208   else if (!strcmp(class_name, "NSCFException"))
209     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
210   else if (!strcmp(class_name, "__NSCFException"))
211     return (new NSExceptionSyntheticFrontEnd(valobj_sp));
212
213   return nullptr;
214 }