diff options
Diffstat (limited to 'lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp')
-rw-r--r-- | lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp deleted file mode 100644 index b73b6c095368..000000000000 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "MainThreadCheckerRuntime.h" - -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/Symbol.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/Variable.h" -#include "lldb/Symbol/VariableList.h" -#include "lldb/Target/InstrumentationRuntimeStopInfo.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/SectionLoadList.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/RegularExpression.h" -#include "Plugins/Process/Utility/HistoryThread.h" - -#include <memory> - -using namespace lldb; -using namespace lldb_private; - -MainThreadCheckerRuntime::~MainThreadCheckerRuntime() { - Deactivate(); -} - -lldb::InstrumentationRuntimeSP -MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) { - return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp)); -} - -void MainThreadCheckerRuntime::Initialize() { - PluginManager::RegisterPlugin( - GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.", - CreateInstance, GetTypeStatic); -} - -void MainThreadCheckerRuntime::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() { - return ConstString("MainThreadChecker"); -} - -lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() { - return eInstrumentationRuntimeTypeMainThreadChecker; -} - -const RegularExpression & -MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() { - static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib")); - return regex; -} - -bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid( - const lldb::ModuleSP module_sp) { - static ConstString test_sym("__main_thread_checker_on_report"); - const Symbol *symbol = - module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny); - return symbol != nullptr; -} - -StructuredData::ObjectSP -MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { - ProcessSP process_sp = GetProcessSP(); - if (!process_sp) - return StructuredData::ObjectSP(); - - ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); - StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); - ModuleSP runtime_module_sp = GetRuntimeModuleSP(); - Target &target = process_sp->GetTarget(); - - if (!frame_sp) - return StructuredData::ObjectSP(); - - RegisterContextSP regctx_sp = frame_sp->GetRegisterContext(); - if (!regctx_sp) - return StructuredData::ObjectSP(); - - const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1"); - if (!reginfo) - return StructuredData::ObjectSP(); - - uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0); - if (!apiname_ptr) - return StructuredData::ObjectSP(); - - std::string apiName = ""; - Status read_error; - target.ReadCStringFromMemory(apiname_ptr, apiName, read_error); - if (read_error.Fail()) - return StructuredData::ObjectSP(); - - std::string className = ""; - std::string selector = ""; - if (apiName.substr(0, 2) == "-[") { - size_t spacePos = apiName.find(" "); - if (spacePos != std::string::npos) { - className = apiName.substr(2, spacePos - 2); - selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2); - } - } - - // Gather the PCs of the user frames in the backtrace. - StructuredData::Array *trace = new StructuredData::Array(); - auto trace_sp = StructuredData::ObjectSP(trace); - StackFrameSP responsible_frame; - for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { - StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I); - Address addr = frame->GetFrameCodeAddress(); - if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime. - continue; - - // The first non-runtime frame is responsible for the bug. - if (!responsible_frame) - responsible_frame = frame; - - // First frame in stacktrace should point to a real PC, not return address. - if (I != 0 && trace->GetSize() == 0) { - addr.Slide(-1); - } - - lldb::addr_t PC = addr.GetLoadAddress(&target); - trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC))); - } - - auto *d = new StructuredData::Dictionary(); - auto dict_sp = StructuredData::ObjectSP(d); - d->AddStringItem("instrumentation_class", "MainThreadChecker"); - d->AddStringItem("api_name", apiName); - d->AddStringItem("class_name", className); - d->AddStringItem("selector", selector); - d->AddStringItem("description", - apiName + " must be used from main thread only"); - d->AddIntegerItem("tid", thread_sp->GetIndexID()); - d->AddItem("trace", trace_sp); - return dict_sp; -} - -bool MainThreadCheckerRuntime::NotifyBreakpointHit( - void *baton, StoppointCallbackContext *context, user_id_t break_id, - user_id_t break_loc_id) { - assert(baton && "null baton"); - if (!baton) - return false; ///< false => resume execution. - - MainThreadCheckerRuntime *const instance = - static_cast<MainThreadCheckerRuntime *>(baton); - - ProcessSP process_sp = instance->GetProcessSP(); - ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); - if (!process_sp || !thread_sp || - process_sp != context->exe_ctx_ref.GetProcessSP()) - return false; - - if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) - return false; - - StructuredData::ObjectSP report = - instance->RetrieveReportData(context->exe_ctx_ref); - - if (report) { - std::string description = report->GetAsDictionary() - ->GetValueForKey("description") - ->GetAsString() - ->GetValue(); - thread_sp->SetStopInfo( - InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( - *thread_sp, description, report)); - return true; - } - - return false; -} - -void MainThreadCheckerRuntime::Activate() { - if (IsActive()) - return; - - ProcessSP process_sp = GetProcessSP(); - if (!process_sp) - return; - - ModuleSP runtime_module_sp = GetRuntimeModuleSP(); - - ConstString symbol_name("__main_thread_checker_on_report"); - const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType( - symbol_name, eSymbolTypeCode); - - if (symbol == nullptr) - return; - - if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) - return; - - Target &target = process_sp->GetTarget(); - addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); - - if (symbol_address == LLDB_INVALID_ADDRESS) - return; - - Breakpoint *breakpoint = - process_sp->GetTarget() - .CreateBreakpoint(symbol_address, /*internal=*/true, - /*hardware=*/false) - .get(); - breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this, - true); - breakpoint->SetBreakpointKind("main-thread-checker-report"); - SetBreakpointID(breakpoint->GetID()); - - SetActive(true); -} - -void MainThreadCheckerRuntime::Deactivate() { - SetActive(false); - - auto BID = GetBreakpointID(); - if (BID == LLDB_INVALID_BREAK_ID) - return; - - if (ProcessSP process_sp = GetProcessSP()) { - process_sp->GetTarget().RemoveBreakpointByID(BID); - SetBreakpointID(LLDB_INVALID_BREAK_ID); - } -} - -lldb::ThreadCollectionSP -MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( - StructuredData::ObjectSP info) { - ThreadCollectionSP threads; - threads = std::make_shared<ThreadCollection>(); - - ProcessSP process_sp = GetProcessSP(); - - if (info->GetObjectForDotSeparatedPath("instrumentation_class") - ->GetStringValue() != "MainThreadChecker") - return threads; - - std::vector<lldb::addr_t> PCs; - auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray(); - trace->ForEach([&PCs](StructuredData::Object *PC) -> bool { - PCs.push_back(PC->GetAsInteger()->GetValue()); - return true; - }); - - if (PCs.empty()) - return threads; - - StructuredData::ObjectSP thread_id_obj = - info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; - - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, PCs); - ThreadSP new_thread_sp(history_thread); - - // Save this in the Process' ExtendedThreadList so a strong pointer retains - // the object - process_sp->GetExtendedThreadList().AddThread(new_thread_sp); - threads->AddThread(new_thread_sp); - - return threads; -} |