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 = ValueObject::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 } 220