15ffd83dbSDimitry Andric //===-- AppleObjCRuntime.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "AppleObjCRuntime.h"
105ffd83dbSDimitry Andric #include "AppleObjCRuntimeV1.h"
115ffd83dbSDimitry Andric #include "AppleObjCRuntimeV2.h"
120b57cec5SDimitry Andric #include "AppleObjCTrampolineHandler.h"
135ffd83dbSDimitry Andric #include "Plugins/Language/ObjC/NSString.h"
145ffd83dbSDimitry Andric #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
155ffd83dbSDimitry Andric #include "Plugins/Process/Utility/HistoryThread.h"
160b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
170b57cec5SDimitry Andric #include "lldb/Core/Module.h"
180b57cec5SDimitry Andric #include "lldb/Core/ModuleList.h"
190b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
200b57cec5SDimitry Andric #include "lldb/Core/Section.h"
210b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
220b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
230b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
240b57cec5SDimitry Andric #include "lldb/Expression/DiagnosticManager.h"
250b57cec5SDimitry Andric #include "lldb/Expression/FunctionCaller.h"
260b57cec5SDimitry Andric #include "lldb/Symbol/ObjectFile.h"
270b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h"
280b57cec5SDimitry Andric #include "lldb/Target/Process.h"
290b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
300b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
310b57cec5SDimitry Andric #include "lldb/Target/Target.h"
320b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
330b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h"
3481ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
350b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
360b57cec5SDimitry Andric #include "lldb/Utility/Scalar.h"
370b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
380b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
395ffd83dbSDimitry Andric #include "clang/AST/Type.h"
400b57cec5SDimitry Andric 
415ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric #include <vector>
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric using namespace lldb;
460b57cec5SDimitry Andric using namespace lldb_private;
470b57cec5SDimitry Andric 
485ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(AppleObjCRuntime)
495ffd83dbSDimitry Andric 
500b57cec5SDimitry Andric char AppleObjCRuntime::ID = 0;
510b57cec5SDimitry Andric 
52fe6060f1SDimitry Andric AppleObjCRuntime::~AppleObjCRuntime() = default;
530b57cec5SDimitry Andric 
AppleObjCRuntime(Process * process)540b57cec5SDimitry Andric AppleObjCRuntime::AppleObjCRuntime(Process *process)
550b57cec5SDimitry Andric     : ObjCLanguageRuntime(process), m_read_objc_library(false),
560b57cec5SDimitry Andric       m_objc_trampoline_handler_up(), m_Foundation_major() {
570b57cec5SDimitry Andric   ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
Initialize()605ffd83dbSDimitry Andric void AppleObjCRuntime::Initialize() {
615ffd83dbSDimitry Andric   AppleObjCRuntimeV2::Initialize();
625ffd83dbSDimitry Andric   AppleObjCRuntimeV1::Initialize();
635ffd83dbSDimitry Andric }
645ffd83dbSDimitry Andric 
Terminate()655ffd83dbSDimitry Andric void AppleObjCRuntime::Terminate() {
665ffd83dbSDimitry Andric   AppleObjCRuntimeV2::Terminate();
675ffd83dbSDimitry Andric   AppleObjCRuntimeV1::Terminate();
685ffd83dbSDimitry Andric }
695ffd83dbSDimitry Andric 
GetObjectDescription(Stream & str,ValueObject & valobj)700b57cec5SDimitry Andric bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) {
710b57cec5SDimitry Andric   CompilerType compiler_type(valobj.GetCompilerType());
720b57cec5SDimitry Andric   bool is_signed;
730b57cec5SDimitry Andric   // ObjC objects can only be pointers (or numbers that actually represents
740b57cec5SDimitry Andric   // pointers but haven't been typecast, because reasons..)
750b57cec5SDimitry Andric   if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType())
760b57cec5SDimitry Andric     return false;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // Make the argument list: we pass one arg, the address of our pointer, to
790b57cec5SDimitry Andric   // the print function.
800b57cec5SDimitry Andric   Value val;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   if (!valobj.ResolveValue(val.GetScalar()))
830b57cec5SDimitry Andric     return false;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   // Value Objects may not have a process in their ExecutionContextRef.  But we
860b57cec5SDimitry Andric   // need to have one in the ref we pass down to eventually call description.
870b57cec5SDimitry Andric   // Get it from the target if it isn't present.
880b57cec5SDimitry Andric   ExecutionContext exe_ctx;
890b57cec5SDimitry Andric   if (valobj.GetProcessSP()) {
900b57cec5SDimitry Andric     exe_ctx = ExecutionContext(valobj.GetExecutionContextRef());
910b57cec5SDimitry Andric   } else {
920b57cec5SDimitry Andric     exe_ctx.SetContext(valobj.GetTargetSP(), true);
930b57cec5SDimitry Andric     if (!exe_ctx.HasProcessScope())
940b57cec5SDimitry Andric       return false;
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric   return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope());
970b57cec5SDimitry Andric }
GetObjectDescription(Stream & strm,Value & value,ExecutionContextScope * exe_scope)980b57cec5SDimitry Andric bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
990b57cec5SDimitry Andric                                             ExecutionContextScope *exe_scope) {
1000b57cec5SDimitry Andric   if (!m_read_objc_library)
1010b57cec5SDimitry Andric     return false;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   ExecutionContext exe_ctx;
1040b57cec5SDimitry Andric   exe_scope->CalculateExecutionContext(exe_ctx);
1050b57cec5SDimitry Andric   Process *process = exe_ctx.GetProcessPtr();
1060b57cec5SDimitry Andric   if (!process)
1070b57cec5SDimitry Andric     return false;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // We need other parts of the exe_ctx, but the processes have to match.
1100b57cec5SDimitry Andric   assert(m_process == process);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Get the function address for the print function.
1130b57cec5SDimitry Andric   const Address *function_address = GetPrintForDebuggerAddr();
1140b57cec5SDimitry Andric   if (!function_address)
1150b57cec5SDimitry Andric     return false;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   Target *target = exe_ctx.GetTargetPtr();
1180b57cec5SDimitry Andric   CompilerType compiler_type = value.GetCompilerType();
1190b57cec5SDimitry Andric   if (compiler_type) {
1205ffd83dbSDimitry Andric     if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type)) {
1210b57cec5SDimitry Andric       strm.Printf("Value doesn't point to an ObjC object.\n");
1220b57cec5SDimitry Andric       return false;
1230b57cec5SDimitry Andric     }
1240b57cec5SDimitry Andric   } else {
1250b57cec5SDimitry Andric     // If it is not a pointer, see if we can make it into a pointer.
126bdd1243dSDimitry Andric     TypeSystemClangSP scratch_ts_sp =
127e8d8bef9SDimitry Andric         ScratchTypeSystemClang::GetForTarget(*target);
128bdd1243dSDimitry Andric     if (!scratch_ts_sp)
129480093f4SDimitry Andric       return false;
130480093f4SDimitry Andric 
131bdd1243dSDimitry Andric     CompilerType opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
1320b57cec5SDimitry Andric     if (!opaque_type)
133bdd1243dSDimitry Andric       opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1340b57cec5SDimitry Andric     // value.SetContext(Value::eContextTypeClangType, opaque_type_ptr);
1350b57cec5SDimitry Andric     value.SetCompilerType(opaque_type);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   ValueList arg_value_list;
1390b57cec5SDimitry Andric   arg_value_list.PushValue(value);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   // This is the return value:
142bdd1243dSDimitry Andric   TypeSystemClangSP scratch_ts_sp =
143bdd1243dSDimitry Andric       ScratchTypeSystemClang::GetForTarget(*target);
144bdd1243dSDimitry Andric   if (!scratch_ts_sp)
145480093f4SDimitry Andric     return false;
1460b57cec5SDimitry Andric 
147bdd1243dSDimitry Andric   CompilerType return_compiler_type = scratch_ts_sp->GetCStringType(true);
1480b57cec5SDimitry Andric   Value ret;
1490b57cec5SDimitry Andric   //    ret.SetContext(Value::eContextTypeClangType, return_compiler_type);
1500b57cec5SDimitry Andric   ret.SetCompilerType(return_compiler_type);
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   if (exe_ctx.GetFramePtr() == nullptr) {
1530b57cec5SDimitry Andric     Thread *thread = exe_ctx.GetThreadPtr();
1540b57cec5SDimitry Andric     if (thread == nullptr) {
1550b57cec5SDimitry Andric       exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread());
1560b57cec5SDimitry Andric       thread = exe_ctx.GetThreadPtr();
1570b57cec5SDimitry Andric     }
1580b57cec5SDimitry Andric     if (thread) {
15906c3fb27SDimitry Andric       exe_ctx.SetFrameSP(thread->GetSelectedFrame(DoNoSelectMostRelevantFrame));
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   // Now we're ready to call the function:
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   DiagnosticManager diagnostics;
1660b57cec5SDimitry Andric   lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   if (!m_print_object_caller_up) {
1690b57cec5SDimitry Andric     Status error;
1700b57cec5SDimitry Andric     m_print_object_caller_up.reset(
1710b57cec5SDimitry Andric         exe_scope->CalculateTarget()->GetFunctionCallerForLanguage(
1720b57cec5SDimitry Andric             eLanguageTypeObjC, return_compiler_type, *function_address,
1730b57cec5SDimitry Andric             arg_value_list, "objc-object-description", error));
1740b57cec5SDimitry Andric     if (error.Fail()) {
1750b57cec5SDimitry Andric       m_print_object_caller_up.reset();
1760b57cec5SDimitry Andric       strm.Printf("Could not get function runner to call print for debugger "
1770b57cec5SDimitry Andric                   "function: %s.",
1780b57cec5SDimitry Andric                   error.AsCString());
1790b57cec5SDimitry Andric       return false;
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric     m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr,
1820b57cec5SDimitry Andric                                              diagnostics);
1830b57cec5SDimitry Andric   } else {
1840b57cec5SDimitry Andric     m_print_object_caller_up->WriteFunctionArguments(
1850b57cec5SDimitry Andric         exe_ctx, wrapper_struct_addr, arg_value_list, diagnostics);
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   EvaluateExpressionOptions options;
1890b57cec5SDimitry Andric   options.SetUnwindOnError(true);
1900b57cec5SDimitry Andric   options.SetTryAllThreads(true);
1910b57cec5SDimitry Andric   options.SetStopOthers(true);
1920b57cec5SDimitry Andric   options.SetIgnoreBreakpoints(true);
1930b57cec5SDimitry Andric   options.SetTimeout(process->GetUtilityExpressionTimeout());
1940b57cec5SDimitry Andric   options.SetIsForUtilityExpr(true);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   ExpressionResults results = m_print_object_caller_up->ExecuteFunction(
1970b57cec5SDimitry Andric       exe_ctx, &wrapper_struct_addr, options, diagnostics, ret);
1980b57cec5SDimitry Andric   if (results != eExpressionCompleted) {
1990b57cec5SDimitry Andric     strm.Printf("Error evaluating Print Object function: %d.\n", results);
2000b57cec5SDimitry Andric     return false;
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   char buf[512];
2060b57cec5SDimitry Andric   size_t cstr_len = 0;
2070b57cec5SDimitry Andric   size_t full_buffer_len = sizeof(buf) - 1;
2080b57cec5SDimitry Andric   size_t curr_len = full_buffer_len;
2090b57cec5SDimitry Andric   while (curr_len == full_buffer_len) {
2100b57cec5SDimitry Andric     Status error;
2110b57cec5SDimitry Andric     curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf,
2120b57cec5SDimitry Andric                                               sizeof(buf), error);
2130b57cec5SDimitry Andric     strm.Write(buf, curr_len);
2140b57cec5SDimitry Andric     cstr_len += curr_len;
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric   return cstr_len > 0;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
GetObjCModule()2190b57cec5SDimitry Andric lldb::ModuleSP AppleObjCRuntime::GetObjCModule() {
2200b57cec5SDimitry Andric   ModuleSP module_sp(m_objc_module_wp.lock());
2210b57cec5SDimitry Andric   if (module_sp)
2220b57cec5SDimitry Andric     return module_sp;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   Process *process = GetProcess();
2250b57cec5SDimitry Andric   if (process) {
2260b57cec5SDimitry Andric     const ModuleList &modules = process->GetTarget().GetImages();
2270b57cec5SDimitry Andric     for (uint32_t idx = 0; idx < modules.GetSize(); idx++) {
2280b57cec5SDimitry Andric       module_sp = modules.GetModuleAtIndex(idx);
2290b57cec5SDimitry Andric       if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) {
2300b57cec5SDimitry Andric         m_objc_module_wp = module_sp;
2310b57cec5SDimitry Andric         return module_sp;
2320b57cec5SDimitry Andric       }
2330b57cec5SDimitry Andric     }
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric   return ModuleSP();
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
GetPrintForDebuggerAddr()2380b57cec5SDimitry Andric Address *AppleObjCRuntime::GetPrintForDebuggerAddr() {
2390b57cec5SDimitry Andric   if (!m_PrintForDebugger_addr) {
2400b57cec5SDimitry Andric     const ModuleList &modules = m_process->GetTarget().GetImages();
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     SymbolContextList contexts;
2430b57cec5SDimitry Andric     SymbolContext context;
2440b57cec5SDimitry Andric 
2459dba64beSDimitry Andric     modules.FindSymbolsWithNameAndType(ConstString("_NSPrintForDebugger"),
2469dba64beSDimitry Andric                                         eSymbolTypeCode, contexts);
2479dba64beSDimitry Andric     if (contexts.IsEmpty()) {
2489dba64beSDimitry Andric       modules.FindSymbolsWithNameAndType(ConstString("_CFPrintForDebugger"),
2499dba64beSDimitry Andric                                          eSymbolTypeCode, contexts);
2509dba64beSDimitry Andric       if (contexts.IsEmpty())
2510b57cec5SDimitry Andric         return nullptr;
2529dba64beSDimitry Andric     }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric     contexts.GetContextAtIndex(0, context);
2550b57cec5SDimitry Andric 
2565ffd83dbSDimitry Andric     m_PrintForDebugger_addr =
2575ffd83dbSDimitry Andric         std::make_unique<Address>(context.symbol->GetAddress());
2580b57cec5SDimitry Andric   }
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   return m_PrintForDebugger_addr.get();
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
CouldHaveDynamicValue(ValueObject & in_value)2630b57cec5SDimitry Andric bool AppleObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
2640b57cec5SDimitry Andric   return in_value.GetCompilerType().IsPossibleDynamicType(
2650b57cec5SDimitry Andric       nullptr,
2660b57cec5SDimitry Andric       false, // do not check C++
2670b57cec5SDimitry Andric       true); // check ObjC
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric 
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)2700b57cec5SDimitry Andric bool AppleObjCRuntime::GetDynamicTypeAndAddress(
2710b57cec5SDimitry Andric     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
2720b57cec5SDimitry Andric     TypeAndOrName &class_type_or_name, Address &address,
2730b57cec5SDimitry Andric     Value::ValueType &value_type) {
2740b57cec5SDimitry Andric   return false;
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric TypeAndOrName
FixUpDynamicType(const TypeAndOrName & type_and_or_name,ValueObject & static_value)2780b57cec5SDimitry Andric AppleObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
2790b57cec5SDimitry Andric                                    ValueObject &static_value) {
2800b57cec5SDimitry Andric   CompilerType static_type(static_value.GetCompilerType());
2810b57cec5SDimitry Andric   Flags static_type_flags(static_type.GetTypeInfo());
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   TypeAndOrName ret(type_and_or_name);
2840b57cec5SDimitry Andric   if (type_and_or_name.HasType()) {
2850b57cec5SDimitry Andric     // The type will always be the type of the dynamic object.  If our parent's
2860b57cec5SDimitry Andric     // type was a pointer, then our type should be a pointer to the type of the
2870b57cec5SDimitry Andric     // dynamic object.  If a reference, then the original type should be
2880b57cec5SDimitry Andric     // okay...
2890b57cec5SDimitry Andric     CompilerType orig_type = type_and_or_name.GetCompilerType();
2900b57cec5SDimitry Andric     CompilerType corrected_type = orig_type;
2910b57cec5SDimitry Andric     if (static_type_flags.AllSet(eTypeIsPointer))
2920b57cec5SDimitry Andric       corrected_type = orig_type.GetPointerType();
2930b57cec5SDimitry Andric     ret.SetCompilerType(corrected_type);
2940b57cec5SDimitry Andric   } else {
2950b57cec5SDimitry Andric     // If we are here we need to adjust our dynamic type name to include the
2960b57cec5SDimitry Andric     // correct & or * symbol
2970b57cec5SDimitry Andric     std::string corrected_name(type_and_or_name.GetName().GetCString());
2980b57cec5SDimitry Andric     if (static_type_flags.AllSet(eTypeIsPointer))
2990b57cec5SDimitry Andric       corrected_name.append(" *");
3000b57cec5SDimitry Andric     // the parent type should be a correctly pointer'ed or referenc'ed type
3010b57cec5SDimitry Andric     ret.SetCompilerType(static_type);
3020b57cec5SDimitry Andric     ret.SetName(corrected_name.c_str());
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric   return ret;
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
AppleIsModuleObjCLibrary(const ModuleSP & module_sp)3070b57cec5SDimitry Andric bool AppleObjCRuntime::AppleIsModuleObjCLibrary(const ModuleSP &module_sp) {
3080b57cec5SDimitry Andric   if (module_sp) {
3090b57cec5SDimitry Andric     const FileSpec &module_file_spec = module_sp->GetFileSpec();
3100b57cec5SDimitry Andric     static ConstString ObjCName("libobjc.A.dylib");
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric     if (module_file_spec) {
3130b57cec5SDimitry Andric       if (module_file_spec.GetFilename() == ObjCName)
3140b57cec5SDimitry Andric         return true;
3150b57cec5SDimitry Andric     }
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric   return false;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric // we use the version of Foundation to make assumptions about the ObjC runtime
3210b57cec5SDimitry Andric // on a target
GetFoundationVersion()3220b57cec5SDimitry Andric uint32_t AppleObjCRuntime::GetFoundationVersion() {
32381ad6265SDimitry Andric   if (!m_Foundation_major) {
3240b57cec5SDimitry Andric     const ModuleList &modules = m_process->GetTarget().GetImages();
3250b57cec5SDimitry Andric     for (uint32_t idx = 0; idx < modules.GetSize(); idx++) {
3260b57cec5SDimitry Andric       lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx);
3270b57cec5SDimitry Andric       if (!module_sp)
3280b57cec5SDimitry Andric         continue;
3290b57cec5SDimitry Andric       if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),
3300b57cec5SDimitry Andric                  "Foundation") == 0) {
3310b57cec5SDimitry Andric         m_Foundation_major = module_sp->GetVersion().getMajor();
3320b57cec5SDimitry Andric         return *m_Foundation_major;
3330b57cec5SDimitry Andric       }
3340b57cec5SDimitry Andric     }
3350b57cec5SDimitry Andric     return LLDB_INVALID_MODULE_VERSION;
3360b57cec5SDimitry Andric   } else
33781ad6265SDimitry Andric     return *m_Foundation_major;
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
GetValuesForGlobalCFBooleans(lldb::addr_t & cf_true,lldb::addr_t & cf_false)3400b57cec5SDimitry Andric void AppleObjCRuntime::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
3410b57cec5SDimitry Andric                                                     lldb::addr_t &cf_false) {
3420b57cec5SDimitry Andric   cf_true = cf_false = LLDB_INVALID_ADDRESS;
3430b57cec5SDimitry Andric }
3440b57cec5SDimitry Andric 
IsModuleObjCLibrary(const ModuleSP & module_sp)3450b57cec5SDimitry Andric bool AppleObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {
3460b57cec5SDimitry Andric   return AppleIsModuleObjCLibrary(module_sp);
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric 
ReadObjCLibrary(const ModuleSP & module_sp)3490b57cec5SDimitry Andric bool AppleObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {
3500b57cec5SDimitry Andric   // Maybe check here and if we have a handler already, and the UUID of this
3510b57cec5SDimitry Andric   // module is the same as the one in the current module, then we don't have to
3520b57cec5SDimitry Andric   // reread it?
3535ffd83dbSDimitry Andric   m_objc_trampoline_handler_up = std::make_unique<AppleObjCTrampolineHandler>(
3545ffd83dbSDimitry Andric       m_process->shared_from_this(), module_sp);
3550b57cec5SDimitry Andric   if (m_objc_trampoline_handler_up != nullptr) {
3560b57cec5SDimitry Andric     m_read_objc_library = true;
3570b57cec5SDimitry Andric     return true;
3580b57cec5SDimitry Andric   } else
3590b57cec5SDimitry Andric     return false;
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)3620b57cec5SDimitry Andric ThreadPlanSP AppleObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,
3630b57cec5SDimitry Andric                                                             bool stop_others) {
3640b57cec5SDimitry Andric   ThreadPlanSP thread_plan_sp;
3650b57cec5SDimitry Andric   if (m_objc_trampoline_handler_up)
3660b57cec5SDimitry Andric     thread_plan_sp = m_objc_trampoline_handler_up->GetStepThroughDispatchPlan(
3670b57cec5SDimitry Andric         thread, stop_others);
3680b57cec5SDimitry Andric   return thread_plan_sp;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric // Static Functions
3720b57cec5SDimitry Andric ObjCLanguageRuntime::ObjCRuntimeVersions
GetObjCVersion(Process * process,ModuleSP & objc_module_sp)3730b57cec5SDimitry Andric AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) {
3740b57cec5SDimitry Andric   if (!process)
3750b57cec5SDimitry Andric     return ObjCRuntimeVersions::eObjC_VersionUnknown;
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric   Target &target = process->GetTarget();
3780b57cec5SDimitry Andric   if (target.GetArchitecture().GetTriple().getVendor() !=
3790b57cec5SDimitry Andric       llvm::Triple::VendorType::Apple)
3800b57cec5SDimitry Andric     return ObjCRuntimeVersions::eObjC_VersionUnknown;
3810b57cec5SDimitry Andric 
382e8d8bef9SDimitry Andric   for (ModuleSP module_sp : target.GetImages().Modules()) {
3830b57cec5SDimitry Andric     // One tricky bit here is that we might get called as part of the initial
3840b57cec5SDimitry Andric     // module loading, but before all the pre-run libraries get winnowed from
3850b57cec5SDimitry Andric     // the module list.  So there might actually be an old and incorrect ObjC
3860b57cec5SDimitry Andric     // library sitting around in the list, and we don't want to look at that.
3870b57cec5SDimitry Andric     // That's why we call IsLoadedInTarget.
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     if (AppleIsModuleObjCLibrary(module_sp) &&
3900b57cec5SDimitry Andric         module_sp->IsLoadedInTarget(&target)) {
3910b57cec5SDimitry Andric       objc_module_sp = module_sp;
3920b57cec5SDimitry Andric       ObjectFile *ofile = module_sp->GetObjectFile();
3930b57cec5SDimitry Andric       if (!ofile)
3940b57cec5SDimitry Andric         return ObjCRuntimeVersions::eObjC_VersionUnknown;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric       SectionList *sections = module_sp->GetSectionList();
3970b57cec5SDimitry Andric       if (!sections)
3980b57cec5SDimitry Andric         return ObjCRuntimeVersions::eObjC_VersionUnknown;
3990b57cec5SDimitry Andric       SectionSP v1_telltale_section_sp =
4000b57cec5SDimitry Andric           sections->FindSectionByName(ConstString("__OBJC"));
4010b57cec5SDimitry Andric       if (v1_telltale_section_sp) {
4020b57cec5SDimitry Andric         return ObjCRuntimeVersions::eAppleObjC_V1;
4030b57cec5SDimitry Andric       }
4040b57cec5SDimitry Andric       return ObjCRuntimeVersions::eAppleObjC_V2;
4050b57cec5SDimitry Andric     }
4060b57cec5SDimitry Andric   }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   return ObjCRuntimeVersions::eObjC_VersionUnknown;
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
SetExceptionBreakpoints()4110b57cec5SDimitry Andric void AppleObjCRuntime::SetExceptionBreakpoints() {
4120b57cec5SDimitry Andric   const bool catch_bp = false;
4130b57cec5SDimitry Andric   const bool throw_bp = true;
4140b57cec5SDimitry Andric   const bool is_internal = true;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   if (!m_objc_exception_bp_sp) {
4170b57cec5SDimitry Andric     m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint(
4180b57cec5SDimitry Andric         m_process->GetTarget(), GetLanguageType(), catch_bp, throw_bp,
4190b57cec5SDimitry Andric         is_internal);
4200b57cec5SDimitry Andric     if (m_objc_exception_bp_sp)
4210b57cec5SDimitry Andric       m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception");
4220b57cec5SDimitry Andric   } else
4230b57cec5SDimitry Andric     m_objc_exception_bp_sp->SetEnabled(true);
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
ClearExceptionBreakpoints()4260b57cec5SDimitry Andric void AppleObjCRuntime::ClearExceptionBreakpoints() {
4270b57cec5SDimitry Andric   if (!m_process)
4280b57cec5SDimitry Andric     return;
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   if (m_objc_exception_bp_sp.get()) {
4310b57cec5SDimitry Andric     m_objc_exception_bp_sp->SetEnabled(false);
4320b57cec5SDimitry Andric   }
4330b57cec5SDimitry Andric }
4340b57cec5SDimitry Andric 
ExceptionBreakpointsAreSet()4350b57cec5SDimitry Andric bool AppleObjCRuntime::ExceptionBreakpointsAreSet() {
4360b57cec5SDimitry Andric   return m_objc_exception_bp_sp && m_objc_exception_bp_sp->IsEnabled();
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric 
ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason)4390b57cec5SDimitry Andric bool AppleObjCRuntime::ExceptionBreakpointsExplainStop(
4400b57cec5SDimitry Andric     lldb::StopInfoSP stop_reason) {
4410b57cec5SDimitry Andric   if (!m_process)
4420b57cec5SDimitry Andric     return false;
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint)
4450b57cec5SDimitry Andric     return false;
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   uint64_t break_site_id = stop_reason->GetValue();
4485f757f3fSDimitry Andric   return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint(
4490b57cec5SDimitry Andric       break_site_id, m_objc_exception_bp_sp->GetID());
4500b57cec5SDimitry Andric }
4510b57cec5SDimitry Andric 
CalculateHasNewLiteralsAndIndexing()4520b57cec5SDimitry Andric bool AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing() {
4530b57cec5SDimitry Andric   if (!m_process)
4540b57cec5SDimitry Andric     return false;
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   Target &target(m_process->GetTarget());
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   static ConstString s_method_signature(
4590b57cec5SDimitry Andric       "-[NSDictionary objectForKeyedSubscript:]");
4600b57cec5SDimitry Andric   static ConstString s_arclite_method_signature(
4610b57cec5SDimitry Andric       "__arclite_objectForKeyedSubscript");
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric   SymbolContextList sc_list;
4640b57cec5SDimitry Andric 
4659dba64beSDimitry Andric   target.GetImages().FindSymbolsWithNameAndType(s_method_signature,
4669dba64beSDimitry Andric                                                 eSymbolTypeCode, sc_list);
4679dba64beSDimitry Andric   if (sc_list.IsEmpty())
4689dba64beSDimitry Andric     target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature,
4699dba64beSDimitry Andric                                                   eSymbolTypeCode, sc_list);
4709dba64beSDimitry Andric   return !sc_list.IsEmpty();
4710b57cec5SDimitry Andric }
4720b57cec5SDimitry Andric 
CreateExceptionSearchFilter()4730b57cec5SDimitry Andric lldb::SearchFilterSP AppleObjCRuntime::CreateExceptionSearchFilter() {
4740b57cec5SDimitry Andric   Target &target = m_process->GetTarget();
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   FileSpecList filter_modules;
4770b57cec5SDimitry Andric   if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) {
4780b57cec5SDimitry Andric     filter_modules.Append(std::get<0>(GetExceptionThrowLocation()));
4790b57cec5SDimitry Andric   }
4800b57cec5SDimitry Andric   return target.GetSearchFilterForModuleList(&filter_modules);
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric 
GetExceptionObjectForThread(ThreadSP thread_sp)4830b57cec5SDimitry Andric ValueObjectSP AppleObjCRuntime::GetExceptionObjectForThread(
4840b57cec5SDimitry Andric     ThreadSP thread_sp) {
4850b57cec5SDimitry Andric   auto *cpp_runtime = m_process->GetLanguageRuntime(eLanguageTypeC_plus_plus);
4860b57cec5SDimitry Andric   if (!cpp_runtime) return ValueObjectSP();
4870b57cec5SDimitry Andric   auto cpp_exception = cpp_runtime->GetExceptionObjectForThread(thread_sp);
4880b57cec5SDimitry Andric   if (!cpp_exception) return ValueObjectSP();
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   auto descriptor = GetClassDescriptor(*cpp_exception);
4910b57cec5SDimitry Andric   if (!descriptor || !descriptor->IsValid()) return ValueObjectSP();
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   while (descriptor) {
4940b57cec5SDimitry Andric     ConstString class_name(descriptor->GetClassName());
4950b57cec5SDimitry Andric     if (class_name == "NSException")
4960b57cec5SDimitry Andric       return cpp_exception;
4970b57cec5SDimitry Andric     descriptor = descriptor->GetSuperclass();
4980b57cec5SDimitry Andric   }
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   return ValueObjectSP();
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric 
5035ffd83dbSDimitry Andric /// Utility method for error handling in GetBacktraceThreadFromException.
5045ffd83dbSDimitry Andric /// \param msg The message to add to the log.
5055ffd83dbSDimitry Andric /// \return An invalid ThreadSP to be returned from
5065ffd83dbSDimitry Andric ///         GetBacktraceThreadFromException.
507bdd1243dSDimitry Andric [[nodiscard]]
FailExceptionParsing(llvm::StringRef msg)5085ffd83dbSDimitry Andric static ThreadSP FailExceptionParsing(llvm::StringRef msg) {
50981ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Language);
5105ffd83dbSDimitry Andric   LLDB_LOG(log, "Failed getting backtrace from exception: {0}", msg);
5115ffd83dbSDimitry Andric   return ThreadSP();
5125ffd83dbSDimitry Andric }
5135ffd83dbSDimitry Andric 
GetBacktraceThreadFromException(lldb::ValueObjectSP exception_sp)5140b57cec5SDimitry Andric ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException(
5150b57cec5SDimitry Andric     lldb::ValueObjectSP exception_sp) {
5160b57cec5SDimitry Andric   ValueObjectSP reserved_dict =
51706c3fb27SDimitry Andric       exception_sp->GetChildMemberWithName("reserved");
5185ffd83dbSDimitry Andric   if (!reserved_dict)
5195ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get 'reserved' member.");
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric   reserved_dict = reserved_dict->GetSyntheticValue();
5225ffd83dbSDimitry Andric   if (!reserved_dict)
5235ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get synthetic value.");
5240b57cec5SDimitry Andric 
525bdd1243dSDimitry Andric   TypeSystemClangSP scratch_ts_sp =
526e8d8bef9SDimitry Andric       ScratchTypeSystemClang::GetForTarget(*exception_sp->GetTargetSP());
527bdd1243dSDimitry Andric   if (!scratch_ts_sp)
5285ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get scratch AST.");
529bdd1243dSDimitry Andric   CompilerType objc_id = scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID);
5300b57cec5SDimitry Andric   ValueObjectSP return_addresses;
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric   auto objc_object_from_address = [&exception_sp, &objc_id](uint64_t addr,
5330b57cec5SDimitry Andric                                                             const char *name) {
5340b57cec5SDimitry Andric     Value value(addr);
5350b57cec5SDimitry Andric     value.SetCompilerType(objc_id);
5360b57cec5SDimitry Andric     auto object = ValueObjectConstResult::Create(
5370b57cec5SDimitry Andric         exception_sp->GetTargetSP().get(), value, ConstString(name));
5380b57cec5SDimitry Andric     object = object->GetDynamicValue(eDynamicDontRunTarget);
5390b57cec5SDimitry Andric     return object;
5400b57cec5SDimitry Andric   };
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   for (size_t idx = 0; idx < reserved_dict->GetNumChildren(); idx++) {
54306c3fb27SDimitry Andric     ValueObjectSP dict_entry = reserved_dict->GetChildAtIndex(idx);
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric     DataExtractor data;
5460b57cec5SDimitry Andric     data.SetAddressByteSize(dict_entry->GetProcessSP()->GetAddressByteSize());
5470b57cec5SDimitry Andric     Status error;
5480b57cec5SDimitry Andric     dict_entry->GetData(data, error);
5490b57cec5SDimitry Andric     if (error.Fail()) return ThreadSP();
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric     lldb::offset_t data_offset = 0;
5525ffd83dbSDimitry Andric     auto dict_entry_key = data.GetAddress(&data_offset);
5535ffd83dbSDimitry Andric     auto dict_entry_value = data.GetAddress(&data_offset);
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric     auto key_nsstring = objc_object_from_address(dict_entry_key, "key");
5560b57cec5SDimitry Andric     StreamString key_summary;
5570b57cec5SDimitry Andric     if (lldb_private::formatters::NSStringSummaryProvider(
5580b57cec5SDimitry Andric             *key_nsstring, key_summary, TypeSummaryOptions()) &&
5590b57cec5SDimitry Andric         !key_summary.Empty()) {
5600b57cec5SDimitry Andric       if (key_summary.GetString() == "\"callStackReturnAddresses\"") {
5610b57cec5SDimitry Andric         return_addresses = objc_object_from_address(dict_entry_value,
5620b57cec5SDimitry Andric                                                     "callStackReturnAddresses");
5630b57cec5SDimitry Andric         break;
5640b57cec5SDimitry Andric       }
5650b57cec5SDimitry Andric     }
5660b57cec5SDimitry Andric   }
5670b57cec5SDimitry Andric 
5685ffd83dbSDimitry Andric   if (!return_addresses)
5695ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get return addresses.");
57006c3fb27SDimitry Andric   auto frames_value = return_addresses->GetChildMemberWithName("_frames");
5715ffd83dbSDimitry Andric   if (!frames_value)
5725ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get frames_value.");
5730b57cec5SDimitry Andric   addr_t frames_addr = frames_value->GetValueAsUnsigned(0);
57406c3fb27SDimitry Andric   auto count_value = return_addresses->GetChildMemberWithName("_cnt");
5755ffd83dbSDimitry Andric   if (!count_value)
5765ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get count_value.");
5770b57cec5SDimitry Andric   size_t count = count_value->GetValueAsUnsigned(0);
57806c3fb27SDimitry Andric   auto ignore_value = return_addresses->GetChildMemberWithName("_ignore");
5795ffd83dbSDimitry Andric   if (!ignore_value)
5805ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get ignore_value.");
5810b57cec5SDimitry Andric   size_t ignore = ignore_value->GetValueAsUnsigned(0);
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric   size_t ptr_size = m_process->GetAddressByteSize();
5840b57cec5SDimitry Andric   std::vector<lldb::addr_t> pcs;
5850b57cec5SDimitry Andric   for (size_t idx = 0; idx < count; idx++) {
5860b57cec5SDimitry Andric     Status error;
5870b57cec5SDimitry Andric     addr_t pc = m_process->ReadPointerFromMemory(
5880b57cec5SDimitry Andric         frames_addr + (ignore + idx) * ptr_size, error);
5890b57cec5SDimitry Andric     pcs.push_back(pc);
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5925ffd83dbSDimitry Andric   if (pcs.empty())
5935ffd83dbSDimitry Andric     return FailExceptionParsing("Failed to get PC list.");
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   ThreadSP new_thread_sp(new HistoryThread(*m_process, 0, pcs));
5960b57cec5SDimitry Andric   m_process->GetExtendedThreadList().AddThread(new_thread_sp);
5970b57cec5SDimitry Andric   return new_thread_sp;
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric std::tuple<FileSpec, ConstString>
GetExceptionThrowLocation()6010b57cec5SDimitry Andric AppleObjCRuntime::GetExceptionThrowLocation() {
6020b57cec5SDimitry Andric   return std::make_tuple(
6030b57cec5SDimitry Andric       FileSpec("libobjc.A.dylib"), ConstString("objc_exception_throw"));
6040b57cec5SDimitry Andric }
6050b57cec5SDimitry Andric 
ReadObjCLibraryIfNeeded(const ModuleList & module_list)6060b57cec5SDimitry Andric void AppleObjCRuntime::ReadObjCLibraryIfNeeded(const ModuleList &module_list) {
6070b57cec5SDimitry Andric   if (!HasReadObjCLibrary()) {
6080b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric     size_t num_modules = module_list.GetSize();
6110b57cec5SDimitry Andric     for (size_t i = 0; i < num_modules; i++) {
6120b57cec5SDimitry Andric       auto mod = module_list.GetModuleAtIndex(i);
6130b57cec5SDimitry Andric       if (IsModuleObjCLibrary(mod)) {
6140b57cec5SDimitry Andric         ReadObjCLibrary(mod);
6150b57cec5SDimitry Andric         break;
6160b57cec5SDimitry Andric       }
6170b57cec5SDimitry Andric     }
6180b57cec5SDimitry Andric   }
6190b57cec5SDimitry Andric }
6200b57cec5SDimitry Andric 
ModulesDidLoad(const ModuleList & module_list)6210b57cec5SDimitry Andric void AppleObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
6220b57cec5SDimitry Andric   ReadObjCLibraryIfNeeded(module_list);
6230b57cec5SDimitry Andric }
624