1dda28197Spatrick //===-- NSException.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "clang/AST/DeclCXX.h"
10061da546Spatrick
11061da546Spatrick #include "Cocoa.h"
12061da546Spatrick
13061da546Spatrick #include "lldb/Core/ValueObject.h"
14061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
15061da546Spatrick #include "lldb/DataFormatters/FormattersHelpers.h"
16061da546Spatrick #include "lldb/Target/ProcessStructReader.h"
17061da546Spatrick #include "lldb/Target/Target.h"
18061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
19061da546Spatrick #include "lldb/Utility/Endian.h"
20061da546Spatrick #include "lldb/Utility/Status.h"
21061da546Spatrick #include "lldb/Utility/Stream.h"
22061da546Spatrick
23061da546Spatrick #include "Plugins/Language/ObjC/NSString.h"
24061da546Spatrick #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
25dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
26061da546Spatrick
27061da546Spatrick using namespace lldb;
28061da546Spatrick using namespace lldb_private;
29061da546Spatrick using namespace lldb_private::formatters;
30061da546Spatrick
ExtractFields(ValueObject & valobj,ValueObjectSP * name_sp,ValueObjectSP * reason_sp,ValueObjectSP * userinfo_sp,ValueObjectSP * reserved_sp)31061da546Spatrick static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
32061da546Spatrick ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp,
33061da546Spatrick ValueObjectSP *reserved_sp) {
34061da546Spatrick ProcessSP process_sp(valobj.GetProcessSP());
35061da546Spatrick if (!process_sp)
36061da546Spatrick return false;
37061da546Spatrick
38061da546Spatrick lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
39061da546Spatrick
40061da546Spatrick CompilerType valobj_type(valobj.GetCompilerType());
41061da546Spatrick Flags type_flags(valobj_type.GetTypeInfo());
42061da546Spatrick if (type_flags.AllClear(eTypeHasValue)) {
43061da546Spatrick if (valobj.IsBaseClass() && valobj.GetParent())
44061da546Spatrick ptr = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
45061da546Spatrick } else {
46061da546Spatrick ptr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
47061da546Spatrick }
48061da546Spatrick
49061da546Spatrick if (ptr == LLDB_INVALID_ADDRESS)
50061da546Spatrick return false;
51061da546Spatrick size_t ptr_size = process_sp->GetAddressByteSize();
52061da546Spatrick
53061da546Spatrick Status error;
54061da546Spatrick auto name = process_sp->ReadPointerFromMemory(ptr + 1 * ptr_size, error);
55061da546Spatrick if (error.Fail() || name == LLDB_INVALID_ADDRESS)
56061da546Spatrick return false;
57061da546Spatrick auto reason = process_sp->ReadPointerFromMemory(ptr + 2 * ptr_size, error);
58061da546Spatrick if (error.Fail() || reason == LLDB_INVALID_ADDRESS)
59061da546Spatrick return false;
60061da546Spatrick auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error);
61061da546Spatrick if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS)
62061da546Spatrick return false;
63061da546Spatrick auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error);
64061da546Spatrick if (error.Fail() || reserved == LLDB_INVALID_ADDRESS)
65061da546Spatrick return false;
66061da546Spatrick
67061da546Spatrick InferiorSizedWord name_isw(name, *process_sp);
68061da546Spatrick InferiorSizedWord reason_isw(reason, *process_sp);
69061da546Spatrick InferiorSizedWord userinfo_isw(userinfo, *process_sp);
70061da546Spatrick InferiorSizedWord reserved_isw(reserved, *process_sp);
71061da546Spatrick
72*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
73be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
74*f6aab3d8Srobert if (!scratch_ts_sp)
75061da546Spatrick return false;
76061da546Spatrick
77061da546Spatrick CompilerType voidstar =
78*f6aab3d8Srobert scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
79061da546Spatrick
80061da546Spatrick if (name_sp)
81061da546Spatrick *name_sp = ValueObject::CreateValueObjectFromData(
82061da546Spatrick "name", name_isw.GetAsData(process_sp->GetByteOrder()),
83061da546Spatrick valobj.GetExecutionContextRef(), voidstar);
84061da546Spatrick if (reason_sp)
85061da546Spatrick *reason_sp = ValueObject::CreateValueObjectFromData(
86061da546Spatrick "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
87061da546Spatrick valobj.GetExecutionContextRef(), voidstar);
88061da546Spatrick if (userinfo_sp)
89061da546Spatrick *userinfo_sp = ValueObject::CreateValueObjectFromData(
90061da546Spatrick "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
91061da546Spatrick valobj.GetExecutionContextRef(), voidstar);
92061da546Spatrick if (reserved_sp)
93061da546Spatrick *reserved_sp = ValueObject::CreateValueObjectFromData(
94061da546Spatrick "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
95061da546Spatrick valobj.GetExecutionContextRef(), voidstar);
96061da546Spatrick
97061da546Spatrick return true;
98061da546Spatrick }
99061da546Spatrick
NSException_SummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)100061da546Spatrick bool lldb_private::formatters::NSException_SummaryProvider(
101061da546Spatrick ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
102061da546Spatrick lldb::ValueObjectSP reason_sp;
103061da546Spatrick if (!ExtractFields(valobj, nullptr, &reason_sp, nullptr, nullptr))
104061da546Spatrick return false;
105061da546Spatrick
106061da546Spatrick if (!reason_sp) {
107061da546Spatrick stream.Printf("No reason");
108061da546Spatrick return false;
109061da546Spatrick }
110061da546Spatrick
111061da546Spatrick StreamString reason_str_summary;
112061da546Spatrick if (NSStringSummaryProvider(*reason_sp, reason_str_summary, options) &&
113061da546Spatrick !reason_str_summary.Empty()) {
114061da546Spatrick stream.Printf("%s", reason_str_summary.GetData());
115061da546Spatrick return true;
116061da546Spatrick } else
117061da546Spatrick return false;
118061da546Spatrick }
119061da546Spatrick
120061da546Spatrick class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
121061da546Spatrick public:
NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)122061da546Spatrick NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
123061da546Spatrick : SyntheticChildrenFrontEnd(*valobj_sp) {}
124061da546Spatrick
125061da546Spatrick ~NSExceptionSyntheticFrontEnd() override = default;
126061da546Spatrick
CalculateNumChildren()127061da546Spatrick size_t CalculateNumChildren() override {
128061da546Spatrick return 4;
129061da546Spatrick }
130061da546Spatrick
GetChildAtIndex(size_t idx)131061da546Spatrick lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
132061da546Spatrick switch (idx) {
133061da546Spatrick case 0: return m_name_sp;
134061da546Spatrick case 1: return m_reason_sp;
135061da546Spatrick case 2: return m_userinfo_sp;
136061da546Spatrick case 3: return m_reserved_sp;
137061da546Spatrick }
138061da546Spatrick return lldb::ValueObjectSP();
139061da546Spatrick }
140061da546Spatrick
Update()141061da546Spatrick bool Update() override {
142061da546Spatrick m_name_sp.reset();
143061da546Spatrick m_reason_sp.reset();
144061da546Spatrick m_userinfo_sp.reset();
145061da546Spatrick m_reserved_sp.reset();
146061da546Spatrick
147061da546Spatrick return ExtractFields(m_backend, &m_name_sp, &m_reason_sp, &m_userinfo_sp,
148061da546Spatrick &m_reserved_sp);
149061da546Spatrick }
150061da546Spatrick
MightHaveChildren()151061da546Spatrick bool MightHaveChildren() override { return true; }
152061da546Spatrick
GetIndexOfChildWithName(ConstString name)153061da546Spatrick size_t GetIndexOfChildWithName(ConstString name) override {
154061da546Spatrick // NSException has 4 members:
155061da546Spatrick // NSString *name;
156061da546Spatrick // NSString *reason;
157061da546Spatrick // NSDictionary *userInfo;
158061da546Spatrick // id reserved;
159*f6aab3d8Srobert static ConstString g_name("name");
160*f6aab3d8Srobert static ConstString g_reason("reason");
161*f6aab3d8Srobert static ConstString g_userInfo("userInfo");
162*f6aab3d8Srobert static ConstString g_reserved("reserved");
163*f6aab3d8Srobert if (name == g_name) return 0;
164*f6aab3d8Srobert if (name == g_reason) return 1;
165*f6aab3d8Srobert if (name == g_userInfo) return 2;
166*f6aab3d8Srobert if (name == g_reserved) return 3;
167061da546Spatrick return UINT32_MAX;
168061da546Spatrick }
169061da546Spatrick
170061da546Spatrick private:
171061da546Spatrick ValueObjectSP m_name_sp;
172061da546Spatrick ValueObjectSP m_reason_sp;
173061da546Spatrick ValueObjectSP m_userinfo_sp;
174061da546Spatrick ValueObjectSP m_reserved_sp;
175061da546Spatrick };
176061da546Spatrick
177061da546Spatrick SyntheticChildrenFrontEnd *
NSExceptionSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)178061da546Spatrick lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
179061da546Spatrick CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
180061da546Spatrick lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
181061da546Spatrick if (!process_sp)
182061da546Spatrick return nullptr;
183061da546Spatrick ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
184061da546Spatrick if (!runtime)
185061da546Spatrick return nullptr;
186061da546Spatrick
187061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP descriptor(
188061da546Spatrick runtime->GetClassDescriptor(*valobj_sp.get()));
189061da546Spatrick
190061da546Spatrick if (!descriptor.get() || !descriptor->IsValid())
191061da546Spatrick return nullptr;
192061da546Spatrick
193061da546Spatrick const char *class_name = descriptor->GetClassName().GetCString();
194061da546Spatrick
195061da546Spatrick if (!class_name || !*class_name)
196061da546Spatrick return nullptr;
197061da546Spatrick
198061da546Spatrick if (!strcmp(class_name, "NSException"))
199061da546Spatrick return (new NSExceptionSyntheticFrontEnd(valobj_sp));
200061da546Spatrick else if (!strcmp(class_name, "NSCFException"))
201061da546Spatrick return (new NSExceptionSyntheticFrontEnd(valobj_sp));
202061da546Spatrick else if (!strcmp(class_name, "__NSCFException"))
203061da546Spatrick return (new NSExceptionSyntheticFrontEnd(valobj_sp));
204061da546Spatrick
205061da546Spatrick return nullptr;
206061da546Spatrick }
207