blob: c627cd03192640d24482a0082a58670acff60c1b [file] [log] [blame]
Eugene Zelenko26f34fb2015-11-07 00:28:50 +00001//===-- NSError.cpp ---------------------------------------------*- C++ -*-===//
Enrico Granata16709ef2015-11-06 02:43:32 +00002//
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
Eugene Zelenko26f34fb2015-11-07 00:28:50 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13#include "clang/AST/DeclCXX.h"
14
15// Project includes
Enrico Granata16709ef2015-11-06 02:43:32 +000016#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
Enrico Granata16709ef2015-11-06 02:43:32 +000031#include "Plugins/Language/ObjC/NSString.h"
32
33using namespace lldb;
34using namespace lldb_private;
35using namespace lldb_private::formatters;
36
37bool
38lldb_private::formatters::NSError_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 code_location = ptr_value + 2 * ptr_size;
60 lldb::addr_t domain_location = ptr_value + 3 * ptr_size;
61
62 Error error;
63 uint64_t code = process_sp->ReadUnsignedIntegerFromMemory(code_location, ptr_size, 0, error);
64 if (error.Fail())
65 return false;
66
67 lldb::addr_t domain_str_value = process_sp->ReadPointerFromMemory(domain_location, error);
68 if (error.Fail() || domain_str_value == LLDB_INVALID_ADDRESS)
69 return false;
70
71 if (!domain_str_value)
72 {
73 stream.Printf("domain: nil - code: %" PRIu64, code);
74 return true;
75 }
76
77 InferiorSizedWord isw(domain_str_value, *process_sp);
78
79 ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData("domain_str", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeVoid).GetPointerType());
80
81 if (!domain_str_sp)
82 return false;
83
84 StreamString domain_str_summary;
85 if (NSStringSummaryProvider(*domain_str_sp, domain_str_summary, options) && !domain_str_summary.Empty())
86 {
87 stream.Printf("domain: %s - code: %" PRIu64, domain_str_summary.GetData(), code);
88 return true;
89 }
90 else
91 {
92 stream.Printf("domain: nil - code: %" PRIu64, code);
93 return true;
94 }
95}
96
97class NSErrorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
98{
99public:
100 NSErrorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
101 SyntheticChildrenFrontEnd(*valobj_sp)
102 {}
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000103
104 ~NSErrorSyntheticFrontEnd() override = default;
105 // no need to delete m_child_ptr - it's kept alive by the cluster manager on our behalf
106
107 size_t
108 CalculateNumChildren() override
Enrico Granata16709ef2015-11-06 02:43:32 +0000109 {
110 if (m_child_ptr)
111 return 1;
112 if (m_child_sp)
113 return 1;
114 return 0;
115 }
116
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000117 lldb::ValueObjectSP
118 GetChildAtIndex(size_t idx) override
Enrico Granata16709ef2015-11-06 02:43:32 +0000119 {
120 if (idx != 0)
121 return lldb::ValueObjectSP();
122
123 if (m_child_ptr)
124 return m_child_ptr->GetSP();
125 return m_child_sp;
126 }
127
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000128 bool
129 Update() override
Enrico Granata16709ef2015-11-06 02:43:32 +0000130 {
131 m_child_ptr = nullptr;
132 m_child_sp.reset();
133
134 ProcessSP process_sp(m_backend.GetProcessSP());
135 if (!process_sp)
136 return false;
137
138 lldb::addr_t userinfo_location = LLDB_INVALID_ADDRESS;
139
140 CompilerType valobj_type(m_backend.GetCompilerType());
141 Flags type_flags(valobj_type.GetTypeInfo());
142 if (type_flags.AllClear(eTypeHasValue))
143 {
144 if (m_backend.IsBaseClass() && m_backend.GetParent())
145 userinfo_location = m_backend.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
146 }
147 else
148 userinfo_location = m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
149
150 if (userinfo_location == LLDB_INVALID_ADDRESS)
151 return false;
152
153 size_t ptr_size = process_sp->GetAddressByteSize();
154
155 userinfo_location += 4 * ptr_size;
156 Error error;
157 lldb::addr_t userinfo = process_sp->ReadPointerFromMemory(userinfo_location, error);
158 if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
159 return false;
160 InferiorSizedWord isw(userinfo,*process_sp);
161 m_child_sp = ValueObject::CreateValueObjectFromData("_userInfo",
162 isw.GetAsData(process_sp->GetByteOrder()),
163 m_backend.GetExecutionContextRef(),
164 process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeObjCID));
165 return false;
166 }
167
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000168 bool
169 MightHaveChildren() override
Enrico Granata16709ef2015-11-06 02:43:32 +0000170 {
171 return true;
172 }
173
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000174 size_t
175 GetIndexOfChildWithName(const ConstString &name) override
Enrico Granata16709ef2015-11-06 02:43:32 +0000176 {
177 static ConstString g___userInfo("_userInfo");
178 if (name == g___userInfo)
179 return 0;
180 return UINT32_MAX;
181 }
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000182
Enrico Granata16709ef2015-11-06 02:43:32 +0000183private:
184 // the child here can be "real" (i.e. an actual child of the root) or synthetized from raw memory
185 // 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
186 // 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
187 // oh joy!
188 ValueObject* m_child_ptr;
189 ValueObjectSP m_child_sp;
190};
191
192SyntheticChildrenFrontEnd*
193lldb_private::formatters::NSErrorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
194{
195 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
196 if (!process_sp)
197 return nullptr;
198 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
199 if (!runtime)
200 return nullptr;
201
202 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
203
204 if (!descriptor.get() || !descriptor->IsValid())
205 return nullptr;
206
207 const char* class_name = descriptor->GetClassName().GetCString();
208
209 if (!class_name || !*class_name)
210 return nullptr;
211
212 if (!strcmp(class_name,"NSError"))
213 return (new NSErrorSyntheticFrontEnd(valobj_sp));
214 else if (!strcmp(class_name,"__NSCFError"))
215 return (new NSErrorSyntheticFrontEnd(valobj_sp));
216
217 return nullptr;
218}