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