1 //===-- LanguageRuntime.cpp -------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/LanguageRuntime.h" 10 #include "Plugins/Language/ObjC/ObjCLanguage.h" 11 #include "lldb/Core/PluginManager.h" 12 #include "lldb/Core/SearchFilter.h" 13 #include "lldb/Interpreter/CommandInterpreter.h" 14 #include "lldb/Target/ObjCLanguageRuntime.h" 15 #include "lldb/Target/Target.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp, 21 lldb::LanguageType language, 22 bool update_module_list) 23 : SearchFilter(target_sp, FilterTy::Exception), m_language(language), 24 m_language_runtime(nullptr), m_filter_sp() { 25 if (update_module_list) 26 UpdateModuleListIfNeeded(); 27 } 28 29 bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) { 30 UpdateModuleListIfNeeded(); 31 if (m_filter_sp) 32 return m_filter_sp->ModulePasses(module_sp); 33 return false; 34 } 35 36 bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) { 37 UpdateModuleListIfNeeded(); 38 if (m_filter_sp) 39 return m_filter_sp->ModulePasses(spec); 40 return false; 41 } 42 43 void ExceptionSearchFilter::Search(Searcher &searcher) { 44 UpdateModuleListIfNeeded(); 45 if (m_filter_sp) 46 m_filter_sp->Search(searcher); 47 } 48 49 void ExceptionSearchFilter::GetDescription(Stream *s) { 50 UpdateModuleListIfNeeded(); 51 if (m_filter_sp) 52 m_filter_sp->GetDescription(s); 53 } 54 55 void ExceptionSearchFilter::UpdateModuleListIfNeeded() { 56 ProcessSP process_sp(m_target_sp->GetProcessSP()); 57 if (process_sp) { 58 bool refreash_filter = !m_filter_sp; 59 if (m_language_runtime == nullptr) { 60 m_language_runtime = process_sp->GetLanguageRuntime(m_language); 61 refreash_filter = true; 62 } else { 63 LanguageRuntime *language_runtime = 64 process_sp->GetLanguageRuntime(m_language); 65 if (m_language_runtime != language_runtime) { 66 m_language_runtime = language_runtime; 67 refreash_filter = true; 68 } 69 } 70 71 if (refreash_filter && m_language_runtime) { 72 m_filter_sp = m_language_runtime->CreateExceptionSearchFilter(); 73 } 74 } else { 75 m_filter_sp.reset(); 76 m_language_runtime = nullptr; 77 } 78 } 79 80 SearchFilterSP 81 ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) { 82 return SearchFilterSP( 83 new ExceptionSearchFilter(TargetSP(), m_language, false)); 84 } 85 86 SearchFilter *ExceptionSearchFilter::CreateFromStructuredData( 87 Target &target, const StructuredData::Dictionary &data_dict, 88 Status &error) { 89 SearchFilter *result = nullptr; 90 return result; 91 } 92 93 StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() { 94 StructuredData::ObjectSP result_sp; 95 96 return result_sp; 97 } 98 99 // The Target is the one that knows how to create breakpoints, so this function 100 // is meant to be used either by the target or internally in 101 // Set/ClearExceptionBreakpoints. 102 class ExceptionBreakpointResolver : public BreakpointResolver { 103 public: 104 ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp, 105 bool throw_bp) 106 : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver), 107 m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp), 108 m_throw_bp(throw_bp) {} 109 110 ~ExceptionBreakpointResolver() override = default; 111 112 Searcher::CallbackReturn SearchCallback(SearchFilter &filter, 113 SymbolContext &context, Address *addr, 114 bool containing) override { 115 116 if (SetActualResolver()) 117 return m_actual_resolver_sp->SearchCallback(filter, context, addr, 118 containing); 119 else 120 return eCallbackReturnStop; 121 } 122 123 lldb::SearchDepth GetDepth() override { 124 if (SetActualResolver()) 125 return m_actual_resolver_sp->GetDepth(); 126 else 127 return lldb::eSearchDepthTarget; 128 } 129 130 void GetDescription(Stream *s) override { 131 Language *language_plugin = Language::FindPlugin(m_language); 132 if (language_plugin) 133 language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp, 134 *s); 135 else 136 Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp, 137 *s); 138 139 SetActualResolver(); 140 if (m_actual_resolver_sp) { 141 s->Printf(" using: "); 142 m_actual_resolver_sp->GetDescription(s); 143 } else 144 s->Printf(" the correct runtime exception handler will be determined " 145 "when you run"); 146 } 147 148 void Dump(Stream *s) const override {} 149 150 /// Methods for support type inquiry through isa, cast, and dyn_cast: 151 static inline bool classof(const BreakpointResolverName *) { return true; } 152 static inline bool classof(const BreakpointResolver *V) { 153 return V->getResolverID() == BreakpointResolver::ExceptionResolver; 154 } 155 156 protected: 157 BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override { 158 return BreakpointResolverSP( 159 new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp)); 160 } 161 162 bool SetActualResolver() { 163 ProcessSP process_sp; 164 if (m_breakpoint) { 165 process_sp = m_breakpoint->GetTarget().GetProcessSP(); 166 if (process_sp) { 167 bool refreash_resolver = !m_actual_resolver_sp; 168 if (m_language_runtime == nullptr) { 169 m_language_runtime = process_sp->GetLanguageRuntime(m_language); 170 refreash_resolver = true; 171 } else { 172 LanguageRuntime *language_runtime = 173 process_sp->GetLanguageRuntime(m_language); 174 if (m_language_runtime != language_runtime) { 175 m_language_runtime = language_runtime; 176 refreash_resolver = true; 177 } 178 } 179 180 if (refreash_resolver && m_language_runtime) { 181 m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver( 182 m_breakpoint, m_catch_bp, m_throw_bp); 183 } 184 } else { 185 m_actual_resolver_sp.reset(); 186 m_language_runtime = nullptr; 187 } 188 } else { 189 m_actual_resolver_sp.reset(); 190 m_language_runtime = nullptr; 191 } 192 return (bool)m_actual_resolver_sp; 193 } 194 195 lldb::BreakpointResolverSP m_actual_resolver_sp; 196 lldb::LanguageType m_language; 197 LanguageRuntime *m_language_runtime; 198 bool m_catch_bp; 199 bool m_throw_bp; 200 }; 201 202 LanguageRuntime *LanguageRuntime::FindPlugin(Process *process, 203 lldb::LanguageType language) { 204 std::unique_ptr<LanguageRuntime> language_runtime_up; 205 LanguageRuntimeCreateInstance create_callback; 206 207 for (uint32_t idx = 0; 208 (create_callback = 209 PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != 210 nullptr; 211 ++idx) { 212 language_runtime_up.reset(create_callback(process, language)); 213 214 if (language_runtime_up) 215 return language_runtime_up.release(); 216 } 217 218 return nullptr; 219 } 220 221 LanguageRuntime::LanguageRuntime(Process *process) : m_process(process) {} 222 223 LanguageRuntime::~LanguageRuntime() = default; 224 225 Breakpoint::BreakpointPreconditionSP 226 LanguageRuntime::CreateExceptionPrecondition(lldb::LanguageType language, 227 bool catch_bp, bool throw_bp) { 228 switch (language) { 229 case eLanguageTypeObjC: 230 if (throw_bp) 231 return Breakpoint::BreakpointPreconditionSP( 232 new ObjCLanguageRuntime::ObjCExceptionPrecondition()); 233 break; 234 default: 235 break; 236 } 237 return Breakpoint::BreakpointPreconditionSP(); 238 } 239 240 BreakpointSP LanguageRuntime::CreateExceptionBreakpoint( 241 Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp, 242 bool is_internal) { 243 BreakpointResolverSP resolver_sp( 244 new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); 245 SearchFilterSP filter_sp( 246 new ExceptionSearchFilter(target.shared_from_this(), language)); 247 bool hardware = false; 248 bool resolve_indirect_functions = false; 249 BreakpointSP exc_breakpt_sp( 250 target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware, 251 resolve_indirect_functions)); 252 if (exc_breakpt_sp) { 253 Breakpoint::BreakpointPreconditionSP precondition_sp = 254 CreateExceptionPrecondition(language, catch_bp, throw_bp); 255 if (precondition_sp) 256 exc_breakpt_sp->SetPrecondition(precondition_sp); 257 258 if (is_internal) 259 exc_breakpt_sp->SetBreakpointKind("exception"); 260 } 261 262 return exc_breakpt_sp; 263 } 264 265 void LanguageRuntime::InitializeCommands(CommandObject *parent) { 266 if (!parent) 267 return; 268 269 if (!parent->IsMultiwordObject()) 270 return; 271 272 LanguageRuntimeCreateInstance create_callback; 273 274 for (uint32_t idx = 0; 275 (create_callback = 276 PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != 277 nullptr; 278 ++idx) { 279 if (LanguageRuntimeGetCommandObject command_callback = 280 PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) { 281 CommandObjectSP command = 282 command_callback(parent->GetCommandInterpreter()); 283 if (command) { 284 // the CommandObject vended by a Language plugin cannot be created once 285 // and cached because we may create multiple debuggers and need one 286 // instance of the command each - the implementing function is meant to 287 // create a new instance of the command each time it is invoked. 288 parent->LoadSubCommand(command->GetCommandName().str().c_str(), command); 289 } 290 } 291 } 292 } 293 294 lldb::SearchFilterSP LanguageRuntime::CreateExceptionSearchFilter() { 295 return m_process->GetTarget().GetSearchFilterForModule(nullptr); 296 } 297