summaryrefslogtreecommitdiff
path: root/lldb/source/Core/Debugger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r--lldb/source/Core/Debugger.cpp265
1 files changed, 125 insertions, 140 deletions
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 33f72a0896cbd..5f4f1e266d81c 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -1,4 +1,4 @@
-//===-- Debugger.cpp --------------------------------------------*- C++ -*-===//
+//===-- Debugger.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -135,84 +135,6 @@ static constexpr OptionEnumValueElement g_language_enumerators[] = {
},
};
-#define MODULE_WITH_FUNC \
- "{ " \
- "${module.file.basename}{`${function.name-with-args}" \
- "{${frame.no-debug}${function.pc-offset}}}}"
-
-#define MODULE_WITH_FUNC_NO_ARGS \
- "{ " \
- "${module.file.basename}{`${function.name-without-args}" \
- "{${frame.no-debug}${function.pc-offset}}}}"
-
-#define FILE_AND_LINE \
- "{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}" \
- ":${ansi.fg.yellow}${line.number}${ansi.normal}" \
- "{:${ansi.fg.yellow}${line.column}${ansi.normal}}}"
-
-#define IS_OPTIMIZED "{${function.is-optimized} [opt]}"
-
-#define IS_ARTIFICIAL "{${frame.is-artificial} [artificial]}"
-
-#define DEFAULT_THREAD_FORMAT \
- "thread #${thread.index}: tid = ${thread.id%tid}" \
- "{, ${frame.pc}}" MODULE_WITH_FUNC FILE_AND_LINE \
- "{, name = ${ansi.fg.green}'${thread.name}'${ansi.normal}}" \
- "{, queue = ${ansi.fg.green}'${thread.queue}'${ansi.normal}}" \
- "{, activity = " \
- "${ansi.fg.green}'${thread.info.activity.name}'${ansi.normal}}" \
- "{, ${thread.info.trace_messages} messages}" \
- "{, stop reason = ${ansi.fg.red}${thread.stop-reason}${ansi.normal}}" \
- "{\\nReturn value: ${thread.return-value}}" \
- "{\\nCompleted expression: ${thread.completed-expression}}" \
- "\\n"
-
-#define DEFAULT_THREAD_STOP_FORMAT \
- "thread #${thread.index}{, name = '${thread.name}'}" \
- "{, queue = ${ansi.fg.green}'${thread.queue}'${ansi.normal}}" \
- "{, activity = " \
- "${ansi.fg.green}'${thread.info.activity.name}'${ansi.normal}}" \
- "{, ${thread.info.trace_messages} messages}" \
- "{, stop reason = ${ansi.fg.red}${thread.stop-reason}${ansi.normal}}" \
- "{\\nReturn value: ${thread.return-value}}" \
- "{\\nCompleted expression: ${thread.completed-expression}}" \
- "\\n"
-
-#define DEFAULT_FRAME_FORMAT \
- "frame #${frame.index}: " \
- "${ansi.fg.yellow}${frame.pc}${ansi.normal}" MODULE_WITH_FUNC FILE_AND_LINE \
- IS_OPTIMIZED IS_ARTIFICIAL "\\n"
-
-#define DEFAULT_FRAME_FORMAT_NO_ARGS \
- "frame #${frame.index}: " \
- "${ansi.fg.yellow}${frame.pc}${ansi.normal}" MODULE_WITH_FUNC_NO_ARGS \
- FILE_AND_LINE IS_OPTIMIZED IS_ARTIFICIAL "\\n"
-
-// Three parts to this disassembly format specification:
-// 1. If this is a new function/symbol (no previous symbol/function), print
-// dylib`funcname:\n
-// 2. If this is a symbol context change (different from previous
-// symbol/function), print
-// dylib`funcname:\n
-// 3. print
-// address <+offset>:
-#define DEFAULT_DISASSEMBLY_FORMAT \
- "{${function.initial-function}{${module.file.basename}`}{${function.name-" \
- "without-args}}:\\n}{${function.changed}\\n{${module.file.basename}`}{${" \
- "function.name-without-args}}:\\n}{${current-pc-arrow} " \
- "}${addr-file-or-load}{ " \
- "<${function.concrete-only-addr-offset-no-padding}>}: "
-
-// gdb's disassembly format can be emulated with ${current-pc-arrow}${addr-
-// file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-
-// offset-no-padding}>}:
-
-// lldb's original format for disassembly would look like this format string -
-// {${function.initial-function}{${module.file.basename}`}{${function.name-
-// without-
-// args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-
-// without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}:
-
static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
{
eStopShowColumnAnsiOrCaret,
@@ -290,6 +212,11 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
// use-color changed. Ping the prompt so it can reset the ansi terminal
// codes.
SetPrompt(GetPrompt());
+ } else if (property_path == g_debugger_properties[ePropertyUseSourceCache].name) {
+ // use-source-cache changed. Wipe out the cache contents if it was disabled.
+ if (!GetUseSourceCache()) {
+ m_source_file_cache.Clear();
+ }
} else if (is_load_script && target_sp &&
load_script_old_value == eLoadScriptFromSymFileWarn) {
if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
@@ -388,6 +315,9 @@ uint32_t Debugger::GetTerminalWidth() const {
}
bool Debugger::SetTerminalWidth(uint32_t term_width) {
+ if (auto handler_sp = m_io_handler_stack.Top())
+ handler_sp->TerminalSizeChanged();
+
const uint32_t idx = ePropertyTerminalWidth;
return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width);
}
@@ -416,6 +346,20 @@ bool Debugger::SetUseColor(bool b) {
return ret;
}
+bool Debugger::GetUseSourceCache() const {
+ const uint32_t idx = ePropertyUseSourceCache;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
+}
+
+bool Debugger::SetUseSourceCache(bool b) {
+ const uint32_t idx = ePropertyUseSourceCache;
+ bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
+ if (!ret) {
+ m_source_file_cache.Clear();
+ }
+ return ret;
+}
bool Debugger::GetHighlightSource() const {
const uint32_t idx = ePropertyHighlightSource;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -438,6 +382,16 @@ llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {
return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
}
+llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const {
+ const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix;
+ return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
+}
+
+llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const {
+ const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix;
+ return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
+}
+
uint32_t Debugger::GetStopSourceLineCount(bool before) const {
const uint32_t idx =
before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
@@ -708,7 +662,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
m_source_manager_up(), m_source_file_cache(),
m_command_interpreter_up(
std::make_unique<CommandInterpreter>(*this, false)),
- m_input_reader_stack(), m_instance_name(), m_loaded_plugins(),
+ m_io_handler_stack(), m_instance_name(), m_loaded_plugins(),
m_event_handler_thread(), m_io_handler_thread(),
m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
m_forward_listener_sp(), m_clear_once() {
@@ -870,15 +824,15 @@ ExecutionContext Debugger::GetSelectedExecutionContext() {
}
void Debugger::DispatchInputInterrupt() {
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
+ IOHandlerSP reader_sp(m_io_handler_stack.Top());
if (reader_sp)
reader_sp->Interrupt();
}
void Debugger::DispatchInputEndOfFile() {
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
+ IOHandlerSP reader_sp(m_io_handler_stack.Top());
if (reader_sp)
reader_sp->GotEOF();
}
@@ -886,81 +840,107 @@ void Debugger::DispatchInputEndOfFile() {
void Debugger::ClearIOHandlers() {
// The bottom input reader should be the main debugger input reader. We do
// not want to close that one here.
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
- while (m_input_reader_stack.GetSize() > 1) {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
+ while (m_io_handler_stack.GetSize() > 1) {
+ IOHandlerSP reader_sp(m_io_handler_stack.Top());
if (reader_sp)
PopIOHandler(reader_sp);
}
}
-void Debugger::ExecuteIOHandlers() {
+void Debugger::RunIOHandlers() {
+ IOHandlerSP reader_sp = m_io_handler_stack.Top();
while (true) {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (!reader_sp)
break;
reader_sp->Run();
+ {
+ std::lock_guard<std::recursive_mutex> guard(
+ m_io_handler_synchronous_mutex);
+
+ // Remove all input readers that are done from the top of the stack
+ while (true) {
+ IOHandlerSP top_reader_sp = m_io_handler_stack.Top();
+ if (top_reader_sp && top_reader_sp->GetIsDone())
+ PopIOHandler(top_reader_sp);
+ else
+ break;
+ }
+ reader_sp = m_io_handler_stack.Top();
+ }
+ }
+ ClearIOHandlers();
+}
+
+void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex);
+
+ PushIOHandler(reader_sp);
+ IOHandlerSP top_reader_sp = reader_sp;
+
+ while (top_reader_sp) {
+ if (!top_reader_sp)
+ break;
- // Remove all input readers that are done from the top of the stack
+ top_reader_sp->Run();
+
+ // Don't unwind past the starting point.
+ if (top_reader_sp.get() == reader_sp.get()) {
+ if (PopIOHandler(reader_sp))
+ break;
+ }
+
+ // If we pushed new IO handlers, pop them if they're done or restart the
+ // loop to run them if they're not.
while (true) {
- IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
- if (top_reader_sp && top_reader_sp->GetIsDone())
+ top_reader_sp = m_io_handler_stack.Top();
+ if (top_reader_sp && top_reader_sp->GetIsDone()) {
PopIOHandler(top_reader_sp);
- else
+ // Don't unwind past the starting point.
+ if (top_reader_sp.get() == reader_sp.get())
+ return;
+ } else {
break;
+ }
}
}
- ClearIOHandlers();
}
bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {
- return m_input_reader_stack.IsTop(reader_sp);
+ return m_io_handler_stack.IsTop(reader_sp);
}
bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
IOHandler::Type second_top_type) {
- return m_input_reader_stack.CheckTopIOHandlerTypes(top_type, second_top_type);
+ return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type);
}
void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
lldb_private::StreamFile &stream =
is_stdout ? GetOutputStream() : GetErrorStream();
- m_input_reader_stack.PrintAsync(&stream, s, len);
+ m_io_handler_stack.PrintAsync(&stream, s, len);
}
ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {
- return m_input_reader_stack.GetTopIOHandlerControlSequence(ch);
+ return m_io_handler_stack.GetTopIOHandlerControlSequence(ch);
}
const char *Debugger::GetIOHandlerCommandPrefix() {
- return m_input_reader_stack.GetTopIOHandlerCommandPrefix();
+ return m_io_handler_stack.GetTopIOHandlerCommandPrefix();
}
const char *Debugger::GetIOHandlerHelpPrologue() {
- return m_input_reader_stack.GetTopIOHandlerHelpPrologue();
+ return m_io_handler_stack.GetTopIOHandlerHelpPrologue();
}
-void Debugger::RunIOHandler(const IOHandlerSP &reader_sp) {
- PushIOHandler(reader_sp);
-
- IOHandlerSP top_reader_sp = reader_sp;
- while (top_reader_sp) {
- top_reader_sp->Run();
-
- if (top_reader_sp.get() == reader_sp.get()) {
- if (PopIOHandler(reader_sp))
- break;
- }
+bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) {
+ return PopIOHandler(reader_sp);
+}
- while (true) {
- top_reader_sp = m_input_reader_stack.Top();
- if (top_reader_sp && top_reader_sp->GetIsDone())
- PopIOHandler(top_reader_sp);
- else
- break;
- }
- }
+void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp,
+ bool cancel_top_handler) {
+ PushIOHandler(reader_sp, cancel_top_handler);
}
void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
@@ -970,8 +950,8 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
// input reader's in/out/err streams, or fall back to the debugger file
// handles, or we fall back onto stdin/stdout/stderr as a last resort.
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
- IOHandlerSP top_reader_sp(m_input_reader_stack.Top());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
+ IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
// If no STDIN has been set, then set it appropriately
if (!in || !in->IsValid()) {
if (top_reader_sp)
@@ -1009,17 +989,17 @@ void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,
if (!reader_sp)
return;
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
// Get the current top input reader...
- IOHandlerSP top_reader_sp(m_input_reader_stack.Top());
+ IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
// Don't push the same IO handler twice...
if (reader_sp == top_reader_sp)
return;
// Push our new input reader
- m_input_reader_stack.Push(reader_sp);
+ m_io_handler_stack.Push(reader_sp);
reader_sp->Activate();
// Interrupt the top input reader to it will exit its Run() function and let
@@ -1035,23 +1015,23 @@ bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {
if (!pop_reader_sp)
return false;
- std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
+ std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
// The reader on the stop of the stack is done, so let the next read on the
// stack refresh its prompt and if there is one...
- if (m_input_reader_stack.IsEmpty())
+ if (m_io_handler_stack.IsEmpty())
return false;
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
+ IOHandlerSP reader_sp(m_io_handler_stack.Top());
if (pop_reader_sp != reader_sp)
return false;
reader_sp->Deactivate();
reader_sp->Cancel();
- m_input_reader_stack.Pop();
+ m_io_handler_stack.Pop();
- reader_sp = m_input_reader_stack.Top();
+ reader_sp = m_io_handler_stack.Top();
if (reader_sp)
reader_sp->Activate();
@@ -1174,17 +1154,22 @@ bool Debugger::EnableLog(llvm::StringRef channel,
if (pos != m_log_streams.end())
log_stream_sp = pos->second.lock();
if (!log_stream_sp) {
- llvm::sys::fs::OpenFlags flags = llvm::sys::fs::OF_Text;
+ File::OpenOptions flags =
+ File::eOpenOptionWrite | File::eOpenOptionCanCreate;
if (log_options & LLDB_LOG_OPTION_APPEND)
- flags |= llvm::sys::fs::OF_Append;
- int FD;
- if (std::error_code ec = llvm::sys::fs::openFileForWrite(
- log_file, FD, llvm::sys::fs::CD_CreateAlways, flags)) {
- error_stream << "Unable to open log file: " << ec.message();
+ flags |= File::eOpenOptionAppend;
+ else
+ flags |= File::eOpenOptionTruncate;
+ auto file = FileSystem::Instance().Open(
+ FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false);
+ if (!file) {
+ // FIXME: This gets garbled when called from the log command.
+ error_stream << "Unable to open log file: " << log_file;
return false;
}
- log_stream_sp =
- std::make_shared<llvm::raw_fd_ostream>(FD, should_close, unbuffered);
+
+ log_stream_sp = std::make_shared<llvm::raw_fd_ostream>(
+ (*file)->GetDescriptor(), should_close, unbuffered);
m_log_streams[log_file] = log_stream_sp;
}
}
@@ -1503,9 +1488,9 @@ bool Debugger::StartEventHandlerThread() {
listener_sp->StartListeningForEvents(&m_sync_broadcaster,
eBroadcastBitEventThreadIsListening);
- auto thread_name =
+ llvm::StringRef thread_name =
full_name.GetLength() < llvm::get_max_thread_name_length()
- ? full_name.AsCString()
+ ? full_name.GetStringRef()
: "dbg.evt-handler";
// Use larger 8MB stack for this thread
@@ -1542,7 +1527,7 @@ void Debugger::StopEventHandlerThread() {
lldb::thread_result_t Debugger::IOHandlerThread(lldb::thread_arg_t arg) {
Debugger *debugger = (Debugger *)arg;
- debugger->ExecuteIOHandlers();
+ debugger->RunIOHandlers();
debugger->StopEventHandlerThread();
return {};
}