xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSException.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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