blob: 80b4347823dab38ae83c430c938ea44cad8a0137 [file] [log] [blame]
Eugene Zelenko26f34fb2015-11-07 00:28:50 +00001//===-- NSException.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"
Enrico Granata16709ef2015-11-06 02:43:32 +000019#include "lldb/Core/ValueObject.h"
20#include "lldb/Core/ValueObjectConstResult.h"
21#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata16709ef2015-11-06 02:43:32 +000022#include "lldb/Symbol/ClangASTContext.h"
23#include "lldb/Target/ObjCLanguageRuntime.h"
Zachary Turner01c32432017-02-14 19:06:07 +000024#include "lldb/Target/ProcessStructReader.h"
Enrico Granata16709ef2015-11-06 02:43:32 +000025#include "lldb/Target/Target.h"
Zachary Turner01c32432017-02-14 19:06:07 +000026#include "lldb/Utility/Endian.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000027#include "lldb/Utility/Error.h"
28#include "lldb/Utility/Stream.h"
Enrico Granata16709ef2015-11-06 02:43:32 +000029
Enrico Granata16709ef2015-11-06 02:43:32 +000030#include "Plugins/Language/ObjC/NSString.h"
31
32using namespace lldb;
33using namespace lldb_private;
34using namespace lldb_private::formatters;
35
Kate Stoneb9c1b512016-09-06 20:57:50 +000036bool 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 Error 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;
Enrico Granata16709ef2015-11-06 02:43:32 +000096}
97
Kate Stoneb9c1b512016-09-06 20:57:50 +000098class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
Enrico Granata16709ef2015-11-06 02:43:32 +000099public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100 NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
101 : SyntheticChildrenFrontEnd(*valobj_sp) {}
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000102
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 ~NSExceptionSyntheticFrontEnd() override = default;
104 // no need to delete m_child_ptr - it's kept alive by the cluster manager on
105 // our behalf
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 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 Error 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 }
Eugene Zelenko26f34fb2015-11-07 00:28:50 +0000171
Enrico Granata16709ef2015-11-06 02:43:32 +0000172private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173 // the child here can be "real" (i.e. an actual child of the root) or
174 // synthetized from raw memory
175 // if the former, I need to store a plain pointer to it - or else a loop of
176 // references will cause this entire hierarchy of values to leak
177 // if the latter, then I need to store a SharedPointer to it - so that it only
178 // goes away when everyone else in the cluster goes away
179 // oh joy!
180 ValueObject *m_child_ptr;
181 ValueObjectSP m_child_sp;
Enrico Granata16709ef2015-11-06 02:43:32 +0000182};
183
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184SyntheticChildrenFrontEnd *
185lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
186 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
187 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
188 if (!process_sp)
Enrico Granata16709ef2015-11-06 02:43:32 +0000189 return nullptr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 ObjCLanguageRuntime *runtime =
191 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
192 lldb::eLanguageTypeObjC);
193 if (!runtime)
194 return nullptr;
195
196 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
197 runtime->GetClassDescriptor(*valobj_sp.get()));
198
199 if (!descriptor.get() || !descriptor->IsValid())
200 return nullptr;
201
202 const char *class_name = descriptor->GetClassName().GetCString();
203
204 if (!class_name || !*class_name)
205 return nullptr;
206
207 if (!strcmp(class_name, "NSException"))
208 return (new NSExceptionSyntheticFrontEnd(valobj_sp));
209 else if (!strcmp(class_name, "NSCFException"))
210 return (new NSExceptionSyntheticFrontEnd(valobj_sp));
211 else if (!strcmp(class_name, "__NSCFException"))
212 return (new NSExceptionSyntheticFrontEnd(valobj_sp));
213
214 return nullptr;
Enrico Granata16709ef2015-11-06 02:43:32 +0000215}