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