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/Target.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 char LanguageRuntime::ID = 0; 20 21 ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp, 22 lldb::LanguageType language, 23 bool update_module_list) 24 : SearchFilter(target_sp, FilterTy::Exception), m_language(language), 25 m_language_runtime(nullptr), m_filter_sp() { 26 if (update_module_list) 27 UpdateModuleListIfNeeded(); 28 } 29 30 bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) { 31 UpdateModuleListIfNeeded(); 32 if (m_filter_sp) 33 return m_filter_sp->ModulePasses(module_sp); 34 return false; 35 } 36 37 bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) { 38 UpdateModuleListIfNeeded(); 39 if (m_filter_sp) 40 return m_filter_sp->ModulePasses(spec); 41 return false; 42 } 43 44 void ExceptionSearchFilter::Search(Searcher &searcher) { 45 UpdateModuleListIfNeeded(); 46 if (m_filter_sp) 47 m_filter_sp->Search(searcher); 48 } 49 50 void ExceptionSearchFilter::GetDescription(Stream *s) { 51 UpdateModuleListIfNeeded(); 52 if (m_filter_sp) 53 m_filter_sp->GetDescription(s); 54 } 55 56 void ExceptionSearchFilter::UpdateModuleListIfNeeded() { 57 ProcessSP process_sp(m_target_sp->GetProcessSP()); 58 if (process_sp) { 59 bool refreash_filter = !m_filter_sp; 60 if (m_language_runtime == nullptr) { 61 m_language_runtime = process_sp->GetLanguageRuntime(m_language); 62 refreash_filter = true; 63 } else { 64 LanguageRuntime *language_runtime = 65 process_sp->GetLanguageRuntime(m_language); 66 if (m_language_runtime != language_runtime) { 67 m_language_runtime = language_runtime; 68 refreash_filter = true; 69 } 70 } 71 72 if (refreash_filter && m_language_runtime) { 73 m_filter_sp = m_language_runtime->CreateExceptionSearchFilter(); 74 } 75 } else { 76 m_filter_sp.reset(); 77 m_language_runtime = nullptr; 78 } 79 } 80 81 SearchFilterSP 82 ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) { 83 return SearchFilterSP( 84 new ExceptionSearchFilter(TargetSP(), m_language, false)); 85 } 86 87 SearchFilter *ExceptionSearchFilter::CreateFromStructuredData( 88 Target &target, const StructuredData::Dictionary &data_dict, 89 Status &error) { 90 SearchFilter *result = nullptr; 91 return result; 92 } 93 94 StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() { 95 StructuredData::ObjectSP result_sp; 96 97 return result_sp; 98 } 99 100 // The Target is the one that knows how to create breakpoints, so this function 101 // is meant to be used either by the target or internally in 102 // Set/ClearExceptionBreakpoints. 103 class ExceptionBreakpointResolver : public BreakpointResolver { 104 public: 105 ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp, 106 bool throw_bp) 107 : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver), 108 m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp), 109 m_throw_bp(throw_bp) {} 110 111 ~ExceptionBreakpointResolver() override = default; 112 113 Searcher::CallbackReturn SearchCallback(SearchFilter &filter, 114 SymbolContext &context, 115 Address *addr) override { 116 117 if (SetActualResolver()) 118 return m_actual_resolver_sp->SearchCallback(filter, context, addr); 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 BreakpointResolverSP ret_sp( 159 new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp)); 160 ret_sp->SetBreakpoint(&breakpoint); 161 return ret_sp; 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 BreakpointPreconditionSP 228 LanguageRuntime::GetExceptionPrecondition(LanguageType language, 229 bool throw_bp) { 230 LanguageRuntimeCreateInstance create_callback; 231 for (uint32_t idx = 0; 232 (create_callback = 233 PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != 234 nullptr; 235 idx++) { 236 if (auto precondition_callback = 237 PluginManager::GetLanguageRuntimeGetExceptionPreconditionAtIndex( 238 idx)) { 239 if (BreakpointPreconditionSP precond = 240 precondition_callback(language, throw_bp)) 241 return precond; 242 } 243 } 244 return BreakpointPreconditionSP(); 245 } 246 247 BreakpointSP LanguageRuntime::CreateExceptionBreakpoint( 248 Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp, 249 bool is_internal) { 250 BreakpointResolverSP resolver_sp( 251 new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); 252 SearchFilterSP filter_sp( 253 new ExceptionSearchFilter(target.shared_from_this(), language)); 254 bool hardware = false; 255 bool resolve_indirect_functions = false; 256 BreakpointSP exc_breakpt_sp( 257 target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware, 258 resolve_indirect_functions)); 259 if (exc_breakpt_sp) { 260 if (auto precond = GetExceptionPrecondition(language, throw_bp)) 261 exc_breakpt_sp->SetPrecondition(precond); 262 263 if (is_internal) 264 exc_breakpt_sp->SetBreakpointKind("exception"); 265 } 266 267 return exc_breakpt_sp; 268 } 269 270 void LanguageRuntime::InitializeCommands(CommandObject *parent) { 271 if (!parent) 272 return; 273 274 if (!parent->IsMultiwordObject()) 275 return; 276 277 LanguageRuntimeCreateInstance create_callback; 278 279 for (uint32_t idx = 0; 280 (create_callback = 281 PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != 282 nullptr; 283 ++idx) { 284 if (LanguageRuntimeGetCommandObject command_callback = 285 PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) { 286 CommandObjectSP command = 287 command_callback(parent->GetCommandInterpreter()); 288 if (command) { 289 // the CommandObject vended by a Language plugin cannot be created once 290 // and cached because we may create multiple debuggers and need one 291 // instance of the command each - the implementing function is meant to 292 // create a new instance of the command each time it is invoked. 293 parent->LoadSubCommand(command->GetCommandName().str().c_str(), command); 294 } 295 } 296 } 297 } 298