mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 06:10:12 +00:00
Refine the reporting mechanism for interruption.
Also, make it possible for new Targets which haven't been added to the TargetList yet to check for interruption, and add a few more places in building modules where we can check for interruption. Differential Revision: https://reviews.llvm.org/D154542
This commit is contained in:
parent
a4a26374aa
commit
2b0c886542
@ -43,6 +43,7 @@
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Threading.h"
|
||||
|
||||
#include <cassert>
|
||||
@ -85,6 +86,8 @@ public:
|
||||
eBroadcastSymbolChange = (1 << 3),
|
||||
};
|
||||
|
||||
using DebuggerList = std::vector<lldb::DebuggerSP>;
|
||||
|
||||
static ConstString GetStaticBroadcasterClass();
|
||||
|
||||
/// Get the public broadcaster for this debugger.
|
||||
@ -411,12 +414,75 @@ public:
|
||||
/// If you are on the RunCommandInterpreter thread, it will check the
|
||||
/// command interpreter state, and if it is on another thread it will
|
||||
/// check the debugger Interrupt Request state.
|
||||
/// \param[in] cur_func
|
||||
/// For reporting if the interruption was requested. Don't provide this by
|
||||
/// hand, use INTERRUPT_REQUESTED so this gets done consistently.
|
||||
///
|
||||
/// \param[in] formatv
|
||||
/// A formatv string for the interrupt message. If the elements of the
|
||||
/// message are expensive to compute, you can use the no-argument form of
|
||||
/// InterruptRequested, then make up the report using REPORT_INTERRUPTION.
|
||||
///
|
||||
/// \return
|
||||
/// A boolean value, if \b true an interruptible operation should interrupt
|
||||
/// itself.
|
||||
bool InterruptRequested();
|
||||
template <typename... Args>
|
||||
bool InterruptRequested(const char *cur_func,
|
||||
const char *formatv, Args &&... args) {
|
||||
bool ret_val = InterruptRequested();
|
||||
if (ret_val) {
|
||||
if (!formatv)
|
||||
formatv = "Unknown message";
|
||||
if (!cur_func)
|
||||
cur_func = "<UNKNOWN>";
|
||||
ReportInterruption(InterruptionReport(cur_func,
|
||||
llvm::formatv(formatv,
|
||||
std::forward<Args>(args)...)));
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/// This handy define will keep you from having to generate a report for the
|
||||
/// interruption by hand. Use this except in the case where the arguments to
|
||||
/// the message description are expensive to compute.
|
||||
#define INTERRUPT_REQUESTED(debugger, ...) \
|
||||
(debugger).InterruptRequested(__func__, __VA_ARGS__)
|
||||
|
||||
// This form just queries for whether to interrupt, and does no reporting:
|
||||
bool InterruptRequested();
|
||||
|
||||
// FIXME: Do we want to capture a backtrace at the interruption point?
|
||||
class InterruptionReport {
|
||||
public:
|
||||
InterruptionReport(std::string function_name, std::string description) :
|
||||
m_function_name(std::move(function_name)),
|
||||
m_description(std::move(description)),
|
||||
m_interrupt_time(std::chrono::system_clock::now()),
|
||||
m_thread_id(llvm::get_threadid()) {}
|
||||
|
||||
InterruptionReport(std::string function_name,
|
||||
const llvm::formatv_object_base &payload);
|
||||
|
||||
template <typename... Args>
|
||||
InterruptionReport(std::string function_name,
|
||||
const char *format, Args &&... args) :
|
||||
InterruptionReport(function_name, llvm::formatv(format, std::forward<Args>(args)...)) {}
|
||||
|
||||
std::string m_function_name;
|
||||
std::string m_description;
|
||||
const std::chrono::time_point<std::chrono::system_clock> m_interrupt_time;
|
||||
const uint64_t m_thread_id;
|
||||
};
|
||||
void ReportInterruption(const InterruptionReport &report);
|
||||
#define REPORT_INTERRUPTION(debugger, ...) \
|
||||
(debugger).ReportInterruption(Debugger::InterruptionReport(__func__, \
|
||||
__VA_ARGS__))
|
||||
|
||||
static DebuggerList DebuggersRequestingInterruption();
|
||||
|
||||
public:
|
||||
|
||||
// This is for use in the command interpreter, when you either want the
|
||||
// selected target, or if no target is present you want to prime the dummy
|
||||
// target with entities that will be copied over to new targets.
|
||||
|
@ -184,6 +184,12 @@ public:
|
||||
void SetSelectedTarget(const lldb::TargetSP &target);
|
||||
|
||||
lldb::TargetSP GetSelectedTarget();
|
||||
|
||||
/// Returns whether any module, including ones in the process of being
|
||||
/// added, contains this module. I don't want to give direct access to
|
||||
/// these not yet added target, but for interruption purposes, we might
|
||||
/// need to ask whether this target contains this module.
|
||||
bool AnyTargetContainsModule(Module &module);
|
||||
|
||||
TargetIterable Targets() {
|
||||
return TargetIterable(m_target_list, m_target_list_mutex);
|
||||
@ -191,6 +197,7 @@ public:
|
||||
|
||||
private:
|
||||
collection m_target_list;
|
||||
std::unordered_set<lldb::TargetSP> m_in_process_target_list;
|
||||
mutable std::recursive_mutex m_target_list_mutex;
|
||||
uint32_t m_selected_target_idx;
|
||||
|
||||
@ -206,6 +213,12 @@ private:
|
||||
lldb::PlatformSP &platform_sp,
|
||||
lldb::TargetSP &target_sp);
|
||||
|
||||
void RegisterInProcessTarget(lldb::TargetSP target_sp);
|
||||
|
||||
void UnregisterInProcessTarget(lldb::TargetSP target_sp);
|
||||
|
||||
bool IsTargetInProcess(lldb::TargetSP target_sp);
|
||||
|
||||
void AddTargetInternal(lldb::TargetSP target_sp, bool do_select);
|
||||
|
||||
void SetSelectedTargetInternal(uint32_t index);
|
||||
|
@ -813,12 +813,13 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
|
||||
if (variable_list) {
|
||||
const size_t num_variables = variable_list->GetSize();
|
||||
if (num_variables) {
|
||||
size_t num_produced = 0;
|
||||
for (const VariableSP &variable_sp : *variable_list) {
|
||||
if (dbg.InterruptRequested()) {
|
||||
Log *log = GetLog(LLDBLog::Host);
|
||||
LLDB_LOG(log, "Interrupted SBFrame::GetVariables");
|
||||
if (INTERRUPT_REQUESTED(dbg,
|
||||
"Interrupted getting frame variables with {0} of {1} "
|
||||
"produced.", num_produced, num_variables))
|
||||
return {};
|
||||
}
|
||||
|
||||
if (variable_sp) {
|
||||
bool add_variable = false;
|
||||
switch (variable_sp->GetScope()) {
|
||||
@ -862,6 +863,7 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
num_produced++;
|
||||
}
|
||||
}
|
||||
if (recognized_arguments) {
|
||||
|
@ -735,7 +735,7 @@ void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter,
|
||||
lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
|
||||
StreamString strm;
|
||||
// Dumping frames can be slow, allow interruption.
|
||||
if (dbg.InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(dbg, "Interrupted in frame completion"))
|
||||
break;
|
||||
frame_sp->Dump(&strm, false, true);
|
||||
request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
|
||||
|
@ -326,21 +326,29 @@ protected:
|
||||
}
|
||||
} else if (*m_options.relative_frame_offset > 0) {
|
||||
// I don't want "up 20" where "20" takes you past the top of the stack
|
||||
// to produce
|
||||
// an error, but rather to just go to the top. So I have to count the
|
||||
// stack here...
|
||||
const uint32_t num_frames = thread->GetStackFrameCount();
|
||||
if (static_cast<int32_t>(num_frames - frame_idx) >
|
||||
*m_options.relative_frame_offset)
|
||||
frame_idx += *m_options.relative_frame_offset;
|
||||
// to produce an error, but rather to just go to the top. OTOH, start
|
||||
// by seeing if the requested frame exists, in which case we can avoid
|
||||
// counting the stack here...
|
||||
const uint32_t frame_requested = frame_idx
|
||||
+ *m_options.relative_frame_offset;
|
||||
StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
|
||||
if (frame_sp)
|
||||
frame_idx = frame_requested;
|
||||
else {
|
||||
if (frame_idx == num_frames - 1) {
|
||||
// If we are already at the top of the stack, just warn and don't
|
||||
// reset the frame.
|
||||
result.AppendError("Already at the top of the stack.");
|
||||
return false;
|
||||
} else
|
||||
frame_idx = num_frames - 1;
|
||||
// The request went past the stack, so handle that case:
|
||||
const uint32_t num_frames = thread->GetStackFrameCount();
|
||||
if (static_cast<int32_t>(num_frames - frame_idx) >
|
||||
*m_options.relative_frame_offset)
|
||||
frame_idx += *m_options.relative_frame_offset;
|
||||
else {
|
||||
if (frame_idx == num_frames - 1) {
|
||||
// If we are already at the top of the stack, just warn and don't
|
||||
// reset the frame.
|
||||
result.AppendError("Already at the top of the stack.");
|
||||
return false;
|
||||
} else
|
||||
frame_idx = num_frames - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2005,8 +2005,11 @@ protected:
|
||||
result.GetOutputStream().EOL();
|
||||
result.GetOutputStream().EOL();
|
||||
}
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump all symtabs with {0} "
|
||||
"of {1} dumped.", num_dumped, num_modules))
|
||||
break;
|
||||
|
||||
num_dumped++;
|
||||
DumpModuleSymtab(m_interpreter, result.GetOutputStream(),
|
||||
module_sp.get(), m_options.m_sort_order,
|
||||
@ -2032,8 +2035,11 @@ protected:
|
||||
result.GetOutputStream().EOL();
|
||||
result.GetOutputStream().EOL();
|
||||
}
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump symtab list with {0} of {1} dumped.",
|
||||
num_dumped, num_matches))
|
||||
break;
|
||||
|
||||
num_dumped++;
|
||||
DumpModuleSymtab(m_interpreter, result.GetOutputStream(),
|
||||
module_sp.get(), m_options.m_sort_order,
|
||||
@ -2093,8 +2099,11 @@ protected:
|
||||
result.GetOutputStream().Format("Dumping sections for {0} modules.\n",
|
||||
num_modules);
|
||||
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump all sections with {0} of {1} dumped",
|
||||
image_idx, num_modules))
|
||||
break;
|
||||
|
||||
num_dumped++;
|
||||
DumpModuleSections(
|
||||
m_interpreter, result.GetOutputStream(),
|
||||
@ -2111,8 +2120,11 @@ protected:
|
||||
FindModulesByName(target, arg_cstr, module_list, true);
|
||||
if (num_matches > 0) {
|
||||
for (size_t i = 0; i < num_matches; ++i) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump section list with {0} of {1} dumped.",
|
||||
i, num_matches))
|
||||
break;
|
||||
|
||||
Module *module = module_list.GetModulePointerAtIndex(i);
|
||||
if (module) {
|
||||
num_dumped++;
|
||||
@ -2228,7 +2240,7 @@ protected:
|
||||
result.GetOutputStream().Format("Dumping clang ast for {0} modules.\n",
|
||||
num_modules);
|
||||
for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping clang ast"))
|
||||
break;
|
||||
if (SymbolFile *sf = module_sp->GetSymbolFile())
|
||||
sf->DumpClangAST(result.GetOutputStream());
|
||||
@ -2253,8 +2265,11 @@ protected:
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_matches; ++i) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump clang ast list with {0} of {1} dumped.",
|
||||
i, num_matches))
|
||||
break;
|
||||
|
||||
Module *m = module_list.GetModulePointerAtIndex(i);
|
||||
if (SymbolFile *sf = m->GetSymbolFile())
|
||||
sf->DumpClangAST(result.GetOutputStream());
|
||||
@ -2302,8 +2317,11 @@ protected:
|
||||
result.GetOutputStream().Format(
|
||||
"Dumping debug symbols for {0} modules.\n", num_modules);
|
||||
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted in dumping all "
|
||||
"debug symbols with {0} of {1} modules dumped",
|
||||
num_dumped, num_modules))
|
||||
break;
|
||||
|
||||
if (DumpModuleSymbolFile(result.GetOutputStream(), module_sp.get()))
|
||||
num_dumped++;
|
||||
}
|
||||
@ -2318,7 +2336,9 @@ protected:
|
||||
FindModulesByName(target, arg_cstr, module_list, true);
|
||||
if (num_matches > 0) {
|
||||
for (size_t i = 0; i < num_matches; ++i) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping {0} "
|
||||
"of {1} requested modules",
|
||||
i, num_matches))
|
||||
break;
|
||||
Module *module = module_list.GetModulePointerAtIndex(i);
|
||||
if (module) {
|
||||
@ -2382,11 +2402,16 @@ protected:
|
||||
|
||||
const ModuleList &target_modules = target->GetImages();
|
||||
std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
|
||||
if (target_modules.GetSize() > 0) {
|
||||
size_t num_modules = target_modules.GetSize();
|
||||
if (num_modules > 0) {
|
||||
uint32_t num_dumped = 0;
|
||||
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
|
||||
if (GetDebugger().InterruptRequested())
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted in dump all line tables with "
|
||||
"{0} of {1} dumped", num_dumped,
|
||||
num_modules))
|
||||
break;
|
||||
|
||||
if (DumpCompileUnitLineTable(
|
||||
m_interpreter, result.GetOutputStream(), module_sp.get(),
|
||||
file_spec,
|
||||
|
@ -228,8 +228,11 @@ protected:
|
||||
thread->GetIndexID());
|
||||
return false;
|
||||
}
|
||||
if (m_options.m_extended_backtrace && !GetDebugger().InterruptRequested()) {
|
||||
DoExtendedBacktrace(thread, result);
|
||||
if (m_options.m_extended_backtrace) {
|
||||
if (!INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupt skipped extended backtrace")) {
|
||||
DoExtendedBacktrace(thread, result);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -99,10 +99,9 @@ static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
|
||||
|
||||
#pragma mark Static Functions
|
||||
|
||||
typedef std::vector<DebuggerSP> DebuggerList;
|
||||
static std::recursive_mutex *g_debugger_list_mutex_ptr =
|
||||
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
|
||||
static DebuggerList *g_debugger_list_ptr =
|
||||
static Debugger::DebuggerList *g_debugger_list_ptr =
|
||||
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
|
||||
static llvm::ThreadPool *g_thread_pool = nullptr;
|
||||
|
||||
@ -1276,6 +1275,33 @@ bool Debugger::InterruptRequested() {
|
||||
return GetCommandInterpreter().WasInterrupted();
|
||||
}
|
||||
|
||||
Debugger::InterruptionReport::InterruptionReport(std::string function_name,
|
||||
const llvm::formatv_object_base &payload) :
|
||||
m_function_name(std::move(function_name)),
|
||||
m_interrupt_time(std::chrono::system_clock::now()),
|
||||
m_thread_id(llvm::get_threadid()) {
|
||||
llvm::raw_string_ostream desc(m_description);
|
||||
desc << payload << "\n";
|
||||
}
|
||||
|
||||
void Debugger::ReportInterruption(const InterruptionReport &report) {
|
||||
// For now, just log the description:
|
||||
Log *log = GetLog(LLDBLog::Host);
|
||||
LLDB_LOG(log, "Interruption: {0}", report.m_description);
|
||||
}
|
||||
|
||||
Debugger::DebuggerList Debugger::DebuggersRequestingInterruption() {
|
||||
DebuggerList result;
|
||||
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
||||
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
||||
for (auto debugger_sp : *g_debugger_list_ptr) {
|
||||
if (debugger_sp->InterruptRequested())
|
||||
result.push_back(debugger_sp);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t Debugger::GetNumDebuggers() {
|
||||
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
||||
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
||||
|
@ -1047,10 +1047,38 @@ void Module::FindTypes(
|
||||
symbols->FindTypes(pattern, languages, searched_symbol_files, types);
|
||||
}
|
||||
|
||||
static Debugger::DebuggerList
|
||||
DebuggersOwningModuleRequestingInterruption(Module &module) {
|
||||
Debugger::DebuggerList requestors
|
||||
= Debugger::DebuggersRequestingInterruption();
|
||||
Debugger::DebuggerList interruptors;
|
||||
if (requestors.empty())
|
||||
return interruptors;
|
||||
|
||||
for (auto debugger_sp : requestors) {
|
||||
if (!debugger_sp->InterruptRequested())
|
||||
continue;
|
||||
if (debugger_sp->GetTargetList()
|
||||
.AnyTargetContainsModule(module))
|
||||
interruptors.push_back(debugger_sp);
|
||||
}
|
||||
return interruptors;
|
||||
}
|
||||
|
||||
SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) {
|
||||
if (!m_did_load_symfile.load()) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
if (!m_did_load_symfile.load() && can_create) {
|
||||
Debugger::DebuggerList interruptors
|
||||
= DebuggersOwningModuleRequestingInterruption(*this);
|
||||
if (!interruptors.empty()) {
|
||||
for (auto debugger_sp : interruptors) {
|
||||
REPORT_INTERRUPTION(*(debugger_sp.get()),
|
||||
"Interrupted fetching symbols for module {0}",
|
||||
this->GetFileSpec());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
ObjectFile *obj_file = GetObjectFile();
|
||||
if (obj_file != nullptr) {
|
||||
LLDB_SCOPED_TIMER();
|
||||
|
@ -1894,7 +1894,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
|
||||
LLDB_LOGF(log, "Processing command: %s", command_line);
|
||||
LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
|
||||
|
||||
if (GetDebugger().InterruptRequested()) {
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
|
||||
result.AppendError("... Interrupted");
|
||||
return false;
|
||||
}
|
||||
@ -3071,7 +3071,8 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
|
||||
if (had_output && GetDebugger().InterruptRequested())
|
||||
if (had_output && INTERRUPT_REQUESTED(GetDebugger(),
|
||||
"Interrupted dumping command output"))
|
||||
stream->Printf("\n... Interrupted.\n");
|
||||
stream->Flush();
|
||||
}
|
||||
|
@ -509,11 +509,11 @@ bool StackFrameList::GetFramesUpTo(uint32_t end_idx,
|
||||
} else {
|
||||
// Check for interruption when building the frames.
|
||||
// Do the check in idx > 0 so that we'll always create a 0th frame.
|
||||
if (allow_interrupt && dbg.InterruptRequested()) {
|
||||
Log *log = GetLog(LLDBLog::Host);
|
||||
LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
|
||||
was_interrupted = true;
|
||||
break;
|
||||
if (allow_interrupt
|
||||
&& INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
|
||||
m_frames.size())) {
|
||||
was_interrupted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool success =
|
||||
@ -965,11 +965,11 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
|
||||
// Check for interruption here. If we're fetching arguments, this loop
|
||||
// can go slowly:
|
||||
Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger();
|
||||
if (dbg.InterruptRequested()) {
|
||||
Log *log = GetLog(LLDBLog::Host);
|
||||
LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
|
||||
if (INTERRUPT_REQUESTED(dbg,
|
||||
"Interrupted dumping stack for thread {0:hex} with {1} shown.",
|
||||
m_thread.GetID(), num_frames_displayed))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!frame_sp->GetStatus(strm, show_frame_info,
|
||||
num_frames_with_source > (first_frame - frame_idx),
|
||||
|
@ -2236,7 +2236,6 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify,
|
||||
// each library in parallel.
|
||||
if (GetPreloadSymbols())
|
||||
module_sp->PreloadSymbols();
|
||||
|
||||
llvm::SmallVector<ModuleSP, 1> replaced_modules;
|
||||
for (ModuleSP &old_module_sp : old_modules) {
|
||||
if (m_images.GetIndexForModule(old_module_sp.get()) !=
|
||||
@ -4205,6 +4204,10 @@ bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) {
|
||||
}
|
||||
|
||||
bool TargetProperties::GetPreloadSymbols() const {
|
||||
if (INTERRUPT_REQUESTED(m_target->GetDebugger(),
|
||||
"Interrupted checking preload symbols")) {
|
||||
return false;
|
||||
}
|
||||
const uint32_t idx = ePropertyPreloadSymbols;
|
||||
return GetPropertyAtIndexAs<bool>(
|
||||
idx, g_target_properties[idx].default_uint_value != 0);
|
||||
|
@ -325,6 +325,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
|
||||
return error;
|
||||
}
|
||||
target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
|
||||
debugger.GetTargetList().RegisterInProcessTarget(target_sp);
|
||||
target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
|
||||
if (user_exe_path_is_bundle)
|
||||
exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
|
||||
@ -336,6 +337,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
|
||||
// No file was specified, just create an empty target with any arch if a
|
||||
// valid arch was specified
|
||||
target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
|
||||
debugger.GetTargetList().RegisterInProcessTarget(target_sp);
|
||||
}
|
||||
|
||||
if (!target_sp)
|
||||
@ -513,6 +515,7 @@ uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
|
||||
void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
|
||||
lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
|
||||
"target already exists it the list");
|
||||
UnregisterInProcessTarget(target_sp);
|
||||
m_target_list.push_back(std::move(target_sp));
|
||||
if (do_select)
|
||||
SetSelectedTargetInternal(m_target_list.size() - 1);
|
||||
@ -540,3 +543,35 @@ lldb::TargetSP TargetList::GetSelectedTarget() {
|
||||
m_selected_target_idx = 0;
|
||||
return GetTargetAtIndex(m_selected_target_idx);
|
||||
}
|
||||
|
||||
bool TargetList::AnyTargetContainsModule(Module &module) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
|
||||
for (const auto &target_sp : m_target_list) {
|
||||
if (target_sp->GetImages().FindModule(&module))
|
||||
return true;
|
||||
}
|
||||
for (const auto &target_sp: m_in_process_target_list) {
|
||||
if (target_sp->GetImages().FindModule(&module))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
|
||||
std::unordered_set<TargetSP>::iterator iter;
|
||||
bool was_added;
|
||||
std::tie(iter, was_added) = m_in_process_target_list.insert(target_sp);
|
||||
assert(was_added && "Target pointer was left in the in-process map");
|
||||
}
|
||||
|
||||
void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
|
||||
bool was_present = m_in_process_target_list.erase(target_sp);
|
||||
assert(was_present && "Target pointer being removed was not registered");
|
||||
}
|
||||
|
||||
bool TargetList::IsTargetInProcess(TargetSP target_sp) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
|
||||
return m_in_process_target_list.count(target_sp) == 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user