Currently, the instrumentation runtime is caching a library the first time it sees it in the module list. However, in some rare cases on Darwin, the cached pre-run unloaded modules are different from the runtime module that is loaded at runtime. This patch removes the cached module if the plugin fails to activate, ensuring that on subsequent calls we don't try to activate using the unloaded cached module. There are a few related bugs to fix in a follow up: CheckIfRuntimeValid should have a stronger check to ensure the module is loaded and can be activated. Further investigation in UpdateSpecialBinariesFromNewImageInfos calling ModulesDidLoad when the module list may have unloaded modules. I have not included a test for the following reasons: 1. This is an incredibly rare occurance and is only observed in a specific circumstance on Darwin. It is tied to behavior in the DynamicLoader thai is not commonly encountered. 2. It is difficult to reproduce -- this bug requires precise conditions on darwin and it is unclear how we'd reproduce that in a controlled testing environment. rdar://128971453
78 lines
2.5 KiB
C++
78 lines
2.5 KiB
C++
//===-- InstrumentationRuntime.cpp ----------------------------------------===//
|
|
//
|
|
// 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 "lldb/Target/InstrumentationRuntime.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleList.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Utility/RegularExpression.h"
|
|
#include "lldb/lldb-private.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
void InstrumentationRuntime::ModulesDidLoad(
|
|
lldb_private::ModuleList &module_list, lldb_private::Process *process,
|
|
InstrumentationRuntimeCollection &runtimes) {
|
|
InstrumentationRuntimeCreateInstance create_callback = nullptr;
|
|
InstrumentationRuntimeGetType get_type_callback;
|
|
for (uint32_t idx = 0;; ++idx) {
|
|
create_callback =
|
|
PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx);
|
|
if (create_callback == nullptr)
|
|
break;
|
|
get_type_callback =
|
|
PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx);
|
|
InstrumentationRuntimeType type = get_type_callback();
|
|
|
|
InstrumentationRuntimeCollection::iterator pos;
|
|
pos = runtimes.find(type);
|
|
if (pos == runtimes.end()) {
|
|
runtimes[type] = create_callback(process->shared_from_this());
|
|
}
|
|
}
|
|
}
|
|
|
|
void InstrumentationRuntime::ModulesDidLoad(
|
|
lldb_private::ModuleList &module_list) {
|
|
if (IsActive())
|
|
return;
|
|
|
|
if (GetRuntimeModuleSP()) {
|
|
Activate();
|
|
return;
|
|
}
|
|
|
|
module_list.ForEach([this](const lldb::ModuleSP module_sp) -> bool {
|
|
const FileSpec &file_spec = module_sp->GetFileSpec();
|
|
if (!file_spec)
|
|
return true; // Keep iterating.
|
|
|
|
const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary();
|
|
if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) ||
|
|
module_sp->IsExecutable()) {
|
|
if (CheckIfRuntimeIsValid(module_sp)) {
|
|
SetRuntimeModuleSP(module_sp);
|
|
Activate();
|
|
if (!IsActive())
|
|
SetRuntimeModuleSP({}); // Don't cache module if activation failed.
|
|
return false; // Stop iterating, we're done.
|
|
}
|
|
}
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
lldb::ThreadCollectionSP
|
|
InstrumentationRuntime::GetBacktracesFromExtendedStopInfo(
|
|
StructuredData::ObjectSP info) {
|
|
return ThreadCollectionSP(new ThreadCollection());
|
|
}
|