llvm-project/lldb/source/Core/Debugger.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1633 lines
58 KiB
C++
Raw Normal View History

//===-- Debugger.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 "lldb/Core/Debugger.h"
#include "lldb/Breakpoint/Breakpoint.h"
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class. Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing. The new code improves on this with the following features: 1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry. 2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format 3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it. 4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly 5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings 6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features. 7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries. These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more). llvm-svn: 228207
2015-02-05 06:00:53 +08:00
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/Expression/REPL.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-30 05:13:06 +08:00
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StructuredDataPlugin.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Listener.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamCallback.h"
#include "lldb/Utility/StreamString.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
#include "lldb/Host/windows/windows.h"
#endif
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#include <list>
#include <memory>
#include <mutex>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <system_error>
namespace lldb_private {
class Address;
}
using namespace lldb;
using namespace lldb_private;
static lldb::user_id_t g_unique_id = 1;
static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
Added code that will allow completely customizable prompts for use in replacing the "(lldb)" prompt, the "frame #1..." displays when doing stack backtracing and the "thread #1....". This will allow you to see exactly the information that you want to see where you want to see it. This currently isn't hookup up to the prompts yet, but it will be soon. So what is the format of the prompts? Prompts can contain variables that have access to the current program state. Variables are text that appears in between a prefix of "${" and ends with a "}". Some of the interesting variables include: // The frame index (0, 1, 2, 3...) ${frame.index} // common frame registers with generic names ${frame.pc} ${frame.sp} ${frame.fp} ${frame.ra} ${frame.flags} // Access to any frame registers by name where REGNAME is any register name: ${frame.reg.REGNAME} // The current compile unit file where the frame is located ${file.basename} ${file.fullpath} // Function information ${function.name} ${function.pc-offset} // Process info ${process.file.basename} ${process.file.fullpath} ${process.id} ${process.name} // Thread info ${thread.id} ${thread.index} ${thread.name} ${thread.queue} ${thread.stop-reason} // Target information ${target.arch} // The current module for the current frame (the shared library or executable // that contains the current frame PC value): ${module.file.basename} ${module.file.fullpath} // Access to the line entry for where the current frame is when your thread // is stopped: ${line.file.basename} ${line.file.fullpath} ${line.number} ${line.start-addr} ${line.end-addr} Many times the information that you might have in your prompt might not be available and you won't want it to print out if it isn't valid. To take care of this you can enclose everything that must resolve into a scope. A scope is starts with '{' and ends with '}'. For example in order to only display the current file and line number when the information is available the format would be: "{ at {$line.file.basename}:${line.number}}" Broken down this is: start the scope: "{" format whose content will only be displayed if all information is available: "at {$line.file.basename}:${line.number}" end the scope: "}" We currently can represent the infomration we see when stopped at a frame: frame #0: 0x0000000100000e85 a.out`main + 4 at test.c:19 with the following format: "frame #${frame.index}: ${frame.pc} {${module.file.basename}`}{${function.name}{${function.pc-offset}}{ at ${line.file.basename}:${line.number}}\n" This breaks down to always print: "frame #${frame.index}: ${frame.pc} " only print the module followed by a tick if we have a valid module: "{${module.file.basename}`}" print the function name with optional offset: "{${function.name}{${function.pc-offset}}" print the line info if it is available: "{ at ${line.file.basename}:${line.number}}" then finish off with a newline: "\n" Notice you can also put newlines ("\n") and tabs and everything else you are used to putting in a format string when desensitized with the \ character. Cleaned up some of the user settings controller subclasses. All of them do not have any global settings variables and were all implementing stubs for the get/set global settings variable. Now there is a default version in UserSettingsController that will do nothing. llvm-svn: 114306
2010-09-19 10:33:57 +08:00
#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 =
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
{
Debugger::eStopDisassemblyTypeNever,
"never",
"Never show disassembly when displaying a stop context.",
},
{
Debugger::eStopDisassemblyTypeNoDebugInfo,
"no-debuginfo",
"Show disassembly when there is no debug information.",
},
{
Debugger::eStopDisassemblyTypeNoSource,
"no-source",
"Show disassembly when there is no source information, or the source "
"file "
"is missing when displaying a stop context.",
},
{
Debugger::eStopDisassemblyTypeAlways,
"always",
"Always show disassembly when displaying a stop context.",
},
};
static constexpr OptionEnumValueElement g_language_enumerators[] = {
{
eScriptLanguageNone,
"none",
"Disable scripting languages.",
},
{
eScriptLanguagePython,
"python",
"Select python as the default scripting language.",
},
{
eScriptLanguageDefault,
"default",
"Select the lldb default as the default scripting language.",
},
};
#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}}" \
Initial merge of some of the iOS 8 / Mac OS X Yosemite specific lldb support. I'll be doing more testing & cleanup but I wanted to get the initial checkin done. This adds a new SBExpressionOptions::SetLanguage API for selecting a language of an expression. I added adds a new SBThread::GetInfoItemByPathString for retriving information about a thread from that thread's StructuredData. I added a new StructuredData class for representing key-value/array/dictionary information (e.g. JSON formatted data). Helper functions to read JSON and create a StructuredData object, and to print a StructuredData object in JSON format are included. A few Cocoa / Cocoa Touch data formatters were updated by Enrico to track changes in iOS 8 / Yosemite. Before we query a thread's extended information, the system runtime may provide hints to the remote debug stub that it will use to retrieve values out of runtime structures. I added a new SystemRuntime method AddThreadExtendedInfoPacketHints which allows the SystemRuntime to add key-value type data to the initial request that we send to the remote stub. The thread-format formatter string can now retrieve values out of a thread's extended info structured data. The default thread-format string picks up two of these - thread.info.activity.name and thread.info.trace_messages. I added a new "jThreadExtendedInfo" packet in debugserver; I will add documentation to the lldb-gdb-remote.txt doc soon. It accepts JSON formatted arguments (most importantly, "thread":threadnum) and it returns a variety of information regarding the thread to lldb in JSON format. This JSON return is scanned into a StructuredData object that is associated with the thread; UI layers can query the thread's StructuredData to see if key-values are present, and if so, show them to the user. These key-values are likely to be specific to different targets with some commonality among many targets. For instance, many targets will be able to advertise the pthread_t value for a thread. I added an initial rough cut of "thread info" command which will print the information about a thread from the jThreadExtendedInfo result. I need to do more work to make this format reasonably. Han Ming added calls into the pmenergy and pmsample libraries if debugserver is run on Mac OS X Yosemite to get information about the inferior's power use. I added support to debugserver for gathering the Genealogy information about threads, if it exists, and returning it in the jThreadExtendedInfo JSON result. llvm-svn: 210874
2014-06-13 10:37:02 +08:00
"{, ${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,
"ansi-or-caret",
"Highlight the stop column with ANSI terminal codes when color/ANSI "
"mode is enabled; otherwise, fall back to using a text-only caret (^) "
"as if \"caret-only\" mode was selected.",
},
{
eStopShowColumnAnsi,
"ansi",
"Highlight the stop column with ANSI terminal codes when running LLDB "
"with color/ANSI enabled.",
},
{
eStopShowColumnCaret,
"caret",
"Highlight the stop column with a caret character (^) underneath the "
"stop column. This method introduces a new line in source listings "
"that display thread stop locations.",
},
{
eStopShowColumnNone,
"none",
"Do not highlight the stop column.",
},
};
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
#define LLDB_PROPERTIES_debugger
#include "CoreProperties.inc"
enum {
#define LLDB_PROPERTIES_debugger
#include "CorePropertiesEnum.inc"
};
Added code that will allow completely customizable prompts for use in replacing the "(lldb)" prompt, the "frame #1..." displays when doing stack backtracing and the "thread #1....". This will allow you to see exactly the information that you want to see where you want to see it. This currently isn't hookup up to the prompts yet, but it will be soon. So what is the format of the prompts? Prompts can contain variables that have access to the current program state. Variables are text that appears in between a prefix of "${" and ends with a "}". Some of the interesting variables include: // The frame index (0, 1, 2, 3...) ${frame.index} // common frame registers with generic names ${frame.pc} ${frame.sp} ${frame.fp} ${frame.ra} ${frame.flags} // Access to any frame registers by name where REGNAME is any register name: ${frame.reg.REGNAME} // The current compile unit file where the frame is located ${file.basename} ${file.fullpath} // Function information ${function.name} ${function.pc-offset} // Process info ${process.file.basename} ${process.file.fullpath} ${process.id} ${process.name} // Thread info ${thread.id} ${thread.index} ${thread.name} ${thread.queue} ${thread.stop-reason} // Target information ${target.arch} // The current module for the current frame (the shared library or executable // that contains the current frame PC value): ${module.file.basename} ${module.file.fullpath} // Access to the line entry for where the current frame is when your thread // is stopped: ${line.file.basename} ${line.file.fullpath} ${line.number} ${line.start-addr} ${line.end-addr} Many times the information that you might have in your prompt might not be available and you won't want it to print out if it isn't valid. To take care of this you can enclose everything that must resolve into a scope. A scope is starts with '{' and ends with '}'. For example in order to only display the current file and line number when the information is available the format would be: "{ at {$line.file.basename}:${line.number}}" Broken down this is: start the scope: "{" format whose content will only be displayed if all information is available: "at {$line.file.basename}:${line.number}" end the scope: "}" We currently can represent the infomration we see when stopped at a frame: frame #0: 0x0000000100000e85 a.out`main + 4 at test.c:19 with the following format: "frame #${frame.index}: ${frame.pc} {${module.file.basename}`}{${function.name}{${function.pc-offset}}{ at ${line.file.basename}:${line.number}}\n" This breaks down to always print: "frame #${frame.index}: ${frame.pc} " only print the module followed by a tick if we have a valid module: "{${module.file.basename}`}" print the function name with optional offset: "{${function.name}{${function.pc-offset}}" print the line info if it is available: "{ at ${line.file.basename}:${line.number}}" then finish off with a newline: "\n" Notice you can also put newlines ("\n") and tabs and everything else you are used to putting in a format string when desensitized with the \ character. Cleaned up some of the user settings controller subclasses. All of them do not have any global settings variables and were all implementing stubs for the get/set global settings variable. Now there is a default version in UserSettingsController that will do nothing. llvm-svn: 114306
2010-09-19 10:33:57 +08:00
LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
VarSetOperationType op,
llvm::StringRef property_path,
llvm::StringRef value) {
bool is_load_script =
(property_path == "target.load-script-from-symbol-file");
// These properties might change how we visualize data.
bool invalidate_data_vis = (property_path == "escape-non-printables");
invalidate_data_vis |=
(property_path == "target.max-zero-padding-in-float-format");
if (invalidate_data_vis) {
DataVisualization::ForceUpdate();
}
TargetSP target_sp;
LoadScriptFromSymFile load_script_old_value;
if (is_load_script && exe_ctx->GetTargetSP()) {
target_sp = exe_ctx->GetTargetSP();
load_script_old_value =
target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
}
Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
if (error.Success()) {
// FIXME it would be nice to have "on-change" callbacks for properties
if (property_path == g_debugger_properties[ePropertyPrompt].name) {
llvm::StringRef new_prompt = GetPrompt();
std::string str = lldb_private::ansi::FormatAnsiTerminalCodes(
new_prompt, GetUseColor());
if (str.length())
new_prompt = str;
GetCommandInterpreter().UpdatePrompt(new_prompt);
auto bytes = std::make_unique<EventDataBytes>(new_prompt);
auto prompt_change_event_sp = std::make_shared<Event>(
CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());
GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);
} else if (property_path == g_debugger_properties[ePropertyUseColor].name) {
// use-color changed. Ping the prompt so it can reset the ansi terminal
// codes.
SetPrompt(GetPrompt());
} else if (is_load_script && target_sp &&
load_script_old_value == eLoadScriptFromSymFileWarn) {
if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
eLoadScriptFromSymFileTrue) {
std::list<Status> errors;
StreamString feedback_stream;
if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) {
Stream &s = GetErrorStream();
for (auto error : errors) {
s.Printf("%s\n", error.AsCString());
}
if (feedback_stream.GetSize())
s.PutCString(feedback_stream.GetString());
}
}
}
}
return error;
}
bool Debugger::GetAutoConfirm() const {
const uint32_t idx = ePropertyAutoConfirm;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const {
const uint32_t idx = ePropertyDisassemblyFormat;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
const FormatEntity::Entry *Debugger::GetFrameFormat() const {
const uint32_t idx = ePropertyFrameFormat;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {
const uint32_t idx = ePropertyFrameFormatUnique;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
bool Debugger::GetNotifyVoid() const {
const uint32_t idx = ePropertyNotiftVoid;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
llvm::StringRef Debugger::GetPrompt() const {
const uint32_t idx = ePropertyPrompt;
return m_collection_sp->GetPropertyAtIndexAsString(
nullptr, idx, g_debugger_properties[idx].default_cstr_value);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
void Debugger::SetPrompt(llvm::StringRef p) {
const uint32_t idx = ePropertyPrompt;
m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p);
llvm::StringRef new_prompt = GetPrompt();
std::string str =
lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor());
if (str.length())
new_prompt = str;
GetCommandInterpreter().UpdatePrompt(new_prompt);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
llvm::StringRef Debugger::GetReproducerPath() const {
auto &r = repro::Reproducer::Instance();
return r.GetReproducerPath().GetCString();
}
const FormatEntity::Entry *Debugger::GetThreadFormat() const {
const uint32_t idx = ePropertyThreadFormat;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
const FormatEntity::Entry *Debugger::GetThreadStopFormat() const {
const uint32_t idx = ePropertyThreadStopFormat;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
lldb::ScriptLanguage Debugger::GetScriptLanguage() const {
const uint32_t idx = ePropertyScriptLanguage;
return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) {
const uint32_t idx = ePropertyScriptLanguage;
return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx,
script_lang);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
uint32_t Debugger::GetTerminalWidth() const {
const uint32_t idx = ePropertyTerminalWidth;
return m_collection_sp->GetPropertyAtIndexAsSInt64(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
bool Debugger::SetTerminalWidth(uint32_t term_width) {
const uint32_t idx = ePropertyTerminalWidth;
return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
bool Debugger::GetUseExternalEditor() const {
const uint32_t idx = ePropertyUseExternalEditor;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
bool Debugger::SetUseExternalEditor(bool b) {
const uint32_t idx = ePropertyUseExternalEditor;
return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
}
bool Debugger::GetUseColor() const {
const uint32_t idx = ePropertyUseColor;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
}
bool Debugger::SetUseColor(bool b) {
const uint32_t idx = ePropertyUseColor;
bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
SetPrompt(GetPrompt());
return ret;
}
bool Debugger::GetHighlightSource() const {
const uint32_t idx = ePropertyHighlightSource;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
}
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
StopShowColumn Debugger::GetStopShowColumn() const {
const uint32_t idx = ePropertyStopShowColumn;
return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
}
llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const {
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
}
llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
add stop column highlighting support This change introduces optional marking of the column within a source line where a thread is stopped. This marking will show up when the source code for a thread stop is displayed, when the debug info knows the column information, and if the optional column marking is enabled. There are two separate methods for handling the marking of the stop column: * via ANSI terminal codes, which are added inline to the source line display. The default ANSI mark-up is to underline the column. * via a pure text-based caret that is added in the appropriate column in a newly-inserted blank line underneath the source line in question. There are some new options that control how this all works. * settings set stop-show-column This takes one of 4 values: * ansi-or-caret: use the ANSI terminal code mechanism if LLDB is running with color enabled; if not, use the caret-based, pure text method (see the "caret" mode below). * ansi: only use the ANSI terminal code mechanism to highlight the stop line. If LLDB is running with color disabled, no stop column marking will occur. * caret: only use the pure text caret method, which introduces a newly-inserted line underneath the current line, where the only character in the new line is a caret that highlights the stop column in question. * none: no stop column marking will be attempted. * settings set stop-show-column-ansi-prefix This is a text format that indicates the ANSI formatting code to insert into the stream immediately preceding the column where the stop column character will be marked up. It defaults to ${ansi.underline}; however, it can contain any valid LLDB format codes, e.g. ${ansi.fg.red}${ansi.bold}${ansi.underline} * settings set stop-show-column-ansi-suffix This is the text format that specifies the ANSI terminal codes to end the markup that was started with the prefix described above. It defaults to: ${ansi.normal}. This should be sufficient for the common cases. Significant leg-work was done by Adrian Prantl. (Thanks, Adrian!) differential review: https://reviews.llvm.org/D20835 reviewers: clayborg, jingham llvm-svn: 282105
2016-09-22 04:13:14 +08:00
}
uint32_t Debugger::GetStopSourceLineCount(bool before) const {
const uint32_t idx =
before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
return m_collection_sp->GetPropertyAtIndexAsSInt64(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
}
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const {
const uint32_t idx = ePropertyStopDisassemblyDisplay;
return (Debugger::StopDisassemblyType)
m_collection_sp->GetPropertyAtIndexAsEnumeration(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
}
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
uint32_t Debugger::GetDisassemblyLineCount() const {
const uint32_t idx = ePropertyStopDisassemblyCount;
return m_collection_sp->GetPropertyAtIndexAsSInt64(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
}
Many GDB users always want to display disassembly when they stop by using something like "display/4i $pc" (or something like this). With LLDB we already were showing 3 lines of source before and 3 lines of source after the current source line when showing a stop context. We now improve this by allowing the user to control the number of lines with the new "stop-line-count-before" and "stop-line-count-after" settings. Also, there is a new setting for how many disassembly lines to show: "stop-disassembly-count". This will control how many source lines are shown when there is no source or when we have no source line info. settings set stop-line-count-before 3 settings set stop-line-count-after 3 settings set stop-disassembly-count 4 settings set stop-disassembly-display no-source The default values are set as shown above and allow 3 lines of source before and after (what we used to do) the current stop location, and will display 4 lines of disassembly if the source is not available or if we have no debug info. If both "stop-source-context-before" and "stop-source-context-after" are set to zero, this will disable showing any source when stopped. The "stop-disassembly-display" setting is an enumeration that allows you to control when to display disassembly. It has 3 possible values: "never" - never show disassembly no matter what "no-source" - only show disassembly when there is no source line info or the source files are missing "always" - always show disassembly. llvm-svn: 145050
2011-11-22 05:44:34 +08:00
bool Debugger::GetAutoOneLineSummaries() const {
const uint32_t idx = ePropertyAutoOneLineSummaries;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
}
bool Debugger::GetEscapeNonPrintables() const {
const uint32_t idx = ePropertyEscapeNonPrintables;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
}
bool Debugger::GetAutoIndent() const {
const uint32_t idx = ePropertyAutoIndent;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
}
bool Debugger::SetAutoIndent(bool b) {
const uint32_t idx = ePropertyAutoIndent;
return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}
bool Debugger::GetPrintDecls() const {
const uint32_t idx = ePropertyPrintDecls;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
}
bool Debugger::SetPrintDecls(bool b) {
const uint32_t idx = ePropertyPrintDecls;
return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}
uint32_t Debugger::GetTabSize() const {
const uint32_t idx = ePropertyTabSize;
return m_collection_sp->GetPropertyAtIndexAsUInt64(
nullptr, idx, g_debugger_properties[idx].default_uint_value);
}
bool Debugger::SetTabSize(uint32_t tab_size) {
const uint32_t idx = ePropertyTabSize;
return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size);
}
Added code that will allow completely customizable prompts for use in replacing the "(lldb)" prompt, the "frame #1..." displays when doing stack backtracing and the "thread #1....". This will allow you to see exactly the information that you want to see where you want to see it. This currently isn't hookup up to the prompts yet, but it will be soon. So what is the format of the prompts? Prompts can contain variables that have access to the current program state. Variables are text that appears in between a prefix of "${" and ends with a "}". Some of the interesting variables include: // The frame index (0, 1, 2, 3...) ${frame.index} // common frame registers with generic names ${frame.pc} ${frame.sp} ${frame.fp} ${frame.ra} ${frame.flags} // Access to any frame registers by name where REGNAME is any register name: ${frame.reg.REGNAME} // The current compile unit file where the frame is located ${file.basename} ${file.fullpath} // Function information ${function.name} ${function.pc-offset} // Process info ${process.file.basename} ${process.file.fullpath} ${process.id} ${process.name} // Thread info ${thread.id} ${thread.index} ${thread.name} ${thread.queue} ${thread.stop-reason} // Target information ${target.arch} // The current module for the current frame (the shared library or executable // that contains the current frame PC value): ${module.file.basename} ${module.file.fullpath} // Access to the line entry for where the current frame is when your thread // is stopped: ${line.file.basename} ${line.file.fullpath} ${line.number} ${line.start-addr} ${line.end-addr} Many times the information that you might have in your prompt might not be available and you won't want it to print out if it isn't valid. To take care of this you can enclose everything that must resolve into a scope. A scope is starts with '{' and ends with '}'. For example in order to only display the current file and line number when the information is available the format would be: "{ at {$line.file.basename}:${line.number}}" Broken down this is: start the scope: "{" format whose content will only be displayed if all information is available: "at {$line.file.basename}:${line.number}" end the scope: "}" We currently can represent the infomration we see when stopped at a frame: frame #0: 0x0000000100000e85 a.out`main + 4 at test.c:19 with the following format: "frame #${frame.index}: ${frame.pc} {${module.file.basename}`}{${function.name}{${function.pc-offset}}{ at ${line.file.basename}:${line.number}}\n" This breaks down to always print: "frame #${frame.index}: ${frame.pc} " only print the module followed by a tick if we have a valid module: "{${module.file.basename}`}" print the function name with optional offset: "{${function.name}{${function.pc-offset}}" print the line info if it is available: "{ at ${line.file.basename}:${line.number}}" then finish off with a newline: "\n" Notice you can also put newlines ("\n") and tabs and everything else you are used to putting in a format string when desensitized with the \ character. Cleaned up some of the user settings controller subclasses. All of them do not have any global settings variables and were all implementing stubs for the get/set global settings variable. Now there is a default version in UserSettingsController that will do nothing. llvm-svn: 114306
2010-09-19 10:33:57 +08:00
#pragma mark Debugger
// const DebuggerPropertiesSP &
// Debugger::GetSettings() const
//{
// return m_properties_sp;
//}
//
void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {
assert(g_debugger_list_ptr == nullptr &&
"Debugger::Initialize called more than once!");
g_debugger_list_mutex_ptr = new std::recursive_mutex();
g_debugger_list_ptr = new DebuggerList();
g_load_plugin_callback = load_plugin_callback;
}
void Debugger::Terminate() {
assert(g_debugger_list_ptr &&
"Debugger::Terminate called without a matching Debugger::Initialize!");
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
// Clear our master list of debugger objects
{
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
for (const auto &debugger : *g_debugger_list_ptr)
debugger->Clear();
g_debugger_list_ptr->clear();
}
}
}
void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }
void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }
bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {
if (g_load_plugin_callback) {
llvm::sys::DynamicLibrary dynlib =
g_load_plugin_callback(shared_from_this(), spec, error);
if (dynlib.isValid()) {
m_loaded_plugins.push_back(dynlib);
return true;
}
} else {
// The g_load_plugin_callback is registered in SBDebugger::Initialize() and
// if the public API layer isn't available (code is linking against all of
// the internal LLDB static libraries), then we can't load plugins
error.SetErrorString("Public API layer is not available");
}
return false;
}
static FileSystem::EnumerateDirectoryResult
LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
llvm::StringRef path) {
Status error;
static ConstString g_dylibext(".dylib");
static ConstString g_solibext(".so");
if (!baton)
return FileSystem::eEnumerateDirectoryResultQuit;
Debugger *debugger = (Debugger *)baton;
namespace fs = llvm::sys::fs;
// If we have a regular file, a symbolic link or unknown file type, try and
// process the file. We must handle unknown as sometimes the directory
// enumeration might be enumerating a file system that doesn't have correct
// file type information.
if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
ft == fs::file_type::type_unknown) {
FileSpec plugin_file_spec(path);
FileSystem::Instance().Resolve(plugin_file_spec);
2014-06-27 10:42:12 +08:00
if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
plugin_file_spec.GetFileNameExtension() != g_solibext) {
return FileSystem::eEnumerateDirectoryResultNext;
}
Status plugin_load_error;
debugger->LoadPlugin(plugin_file_spec, plugin_load_error);
return FileSystem::eEnumerateDirectoryResultNext;
} else if (ft == fs::file_type::directory_file ||
ft == fs::file_type::symlink_file ||
ft == fs::file_type::type_unknown) {
// Try and recurse into anything that a directory or symbolic link. We must
// also do this for unknown as sometimes the directory enumeration might be
// enumerating a file system that doesn't have correct file type
// information.
return FileSystem::eEnumerateDirectoryResultEnter;
}
return FileSystem::eEnumerateDirectoryResultNext;
}
void Debugger::InstanceInitialize() {
const bool find_directories = true;
const bool find_files = true;
const bool find_other = true;
char dir_path[PATH_MAX];
if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) {
if (FileSystem::Instance().Exists(dir_spec) &&
dir_spec.GetPath(dir_path, sizeof(dir_path))) {
FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
find_files, find_other,
LoadPluginCallback, this);
}
}
if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) {
if (FileSystem::Instance().Exists(dir_spec) &&
dir_spec.GetPath(dir_path, sizeof(dir_path))) {
FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
find_files, find_other,
LoadPluginCallback, this);
}
}
PluginManager::DebuggerInitialize(*this);
}
DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,
void *baton) {
DebuggerSP debugger_sp(new Debugger(log_callback, baton));
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
g_debugger_list_ptr->push_back(debugger_sp);
}
debugger_sp->InstanceInitialize();
return debugger_sp;
}
void Debugger::Destroy(DebuggerSP &debugger_sp) {
if (!debugger_sp)
return;
debugger_sp->Clear();
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
if ((*pos).get() == debugger_sp.get()) {
g_debugger_list_ptr->erase(pos);
return;
}
}
}
}
DebuggerSP Debugger::FindDebuggerWithInstanceName(ConstString instance_name) {
DebuggerSP debugger_sp;
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
if ((*pos)->m_instance_name == instance_name) {
debugger_sp = *pos;
break;
}
}
}
return debugger_sp;
}
TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) {
TargetSP target_sp;
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid);
if (target_sp)
break;
}
}
return target_sp;
}
TargetSP Debugger::FindTargetWithProcess(Process *process) {
TargetSP target_sp;
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process);
if (target_sp)
break;
}
}
return target_sp;
}
Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
: UserID(g_unique_id++),
Properties(std::make_shared<OptionValueProperties>()),
m_input_file_sp(std::make_shared<NativeFile>(stdin, false)),
m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)),
m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)),
m_input_recorder(nullptr),
m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
m_terminal_state(), m_target_list(*this), m_platform_list(),
m_listener_sp(Listener::MakeListener("lldb.Debugger")),
m_source_manager_up(), m_source_file_cache(),
m_command_interpreter_up(
std::make_unique<CommandInterpreter>(*this, false)),
m_script_interpreter_sp(), m_input_reader_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() {
char instance_cstr[256];
snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
m_instance_name.SetCString(instance_cstr);
if (log_callback)
m_log_callback_stream_sp =
std::make_shared<StreamCallback>(log_callback, baton);
m_command_interpreter_up->Initialize();
// Always add our default platform to the platform list
PlatformSP default_platform_sp(Platform::GetHostPlatform());
assert(default_platform_sp);
m_platform_list.Append(default_platform_sp, true);
m_dummy_target_sp = m_target_list.GetDummyTarget(*this);
assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?");
m_collection_sp->Initialize(g_debugger_properties);
m_collection_sp->AppendProperty(
ConstString("target"),
ConstString("Settings specify to debugging targets."), true,
Target::GetGlobalProperties()->GetValueProperties());
m_collection_sp->AppendProperty(
ConstString("platform"), ConstString("Platform settings."), true,
Platform::GetGlobalPlatformProperties()->GetValueProperties());
m_collection_sp->AppendProperty(
ConstString("symbols"), ConstString("Symbol lookup and cache settings."),
true, ModuleList::GetGlobalModuleListProperties().GetValueProperties());
if (m_command_interpreter_up) {
m_collection_sp->AppendProperty(
ConstString("interpreter"),
ConstString("Settings specify to the debugger's command interpreter."),
true, m_command_interpreter_up->GetValueProperties());
}
OptionValueSInt64 *term_width =
m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64(
nullptr, ePropertyTerminalWidth);
term_width->SetMinimumValue(10);
term_width->SetMaximumValue(1024);
// Turn off use-color if this is a dumb terminal.
const char *term = getenv("TERM");
if (term && !strcmp(term, "dumb"))
SetUseColor(false);
// Turn off use-color if we don't write to a terminal with color support.
if (!GetOutputFile().GetIsTerminalWithColors())
SetUseColor(false);
#if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
// Enabling use of ANSI color codes because LLDB is using them to highlight
// text.
llvm::sys::Process::UseANSIEscapeCodes(true);
#endif
}
Debugger::~Debugger() { Clear(); }
void Debugger::Clear() {
// Make sure we call this function only once. With the C++ global destructor
// chain having a list of debuggers and with code that can be running on
// other threads, we need to ensure this doesn't happen multiple times.
//
// The following functions call Debugger::Clear():
// Debugger::~Debugger();
// static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
// static void Debugger::Terminate();
llvm::call_once(m_clear_once, [this]() {
ClearIOHandlers();
StopIOHandlerThread();
StopEventHandlerThread();
m_listener_sp->Clear();
int num_targets = m_target_list.GetNumTargets();
for (int i = 0; i < num_targets; i++) {
TargetSP target_sp(m_target_list.GetTargetAtIndex(i));
if (target_sp) {
ProcessSP process_sp(target_sp->GetProcessSP());
if (process_sp)
process_sp->Finalize();
target_sp->Destroy();
}
}
m_broadcaster_manager_sp->Clear();
// Close the input file _before_ we close the input read communications
// class as it does NOT own the input file, our m_input_file does.
m_terminal_state.Clear();
GetInputFile().Close();
m_command_interpreter_up->Clear();
});
}
bool Debugger::GetCloseInputOnEOF() const {
// return m_input_comm.GetCloseOnEOF();
return false;
}
void Debugger::SetCloseInputOnEOF(bool b) {
// m_input_comm.SetCloseOnEOF(b);
}
bool Debugger::GetAsyncExecution() {
return !m_command_interpreter_up->GetSynchronous();
}
void Debugger::SetAsyncExecution(bool async_execution) {
m_command_interpreter_up->SetSynchronous(!async_execution);
}
repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; }
void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) {
assert(file_sp && file_sp->IsValid());
m_input_recorder = recorder;
m_input_file_sp = file_sp;
// Save away the terminal state if that is relevant, so that we can restore
// it in RestoreInputState.
SaveInputTerminalState();
}
void Debugger::SetOutputFile(FileSP file_sp) {
assert(file_sp && file_sp->IsValid());
m_output_stream_sp = std::make_shared<StreamFile>(file_sp);
}
void Debugger::SetErrorFile(FileSP file_sp) {
assert(file_sp && file_sp->IsValid());
m_error_stream_sp = std::make_shared<StreamFile>(file_sp);
}
void Debugger::SaveInputTerminalState() {
int fd = GetInputFile().GetDescriptor();
if (fd != File::kInvalidDescriptor)
m_terminal_state.Save(fd, true);
}
void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); }
ExecutionContext Debugger::GetSelectedExecutionContext() {
ExecutionContext exe_ctx;
TargetSP target_sp(GetSelectedTarget());
exe_ctx.SetTargetSP(target_sp);
if (target_sp) {
ProcessSP process_sp(target_sp->GetProcessSP());
exe_ctx.SetProcessSP(process_sp);
if (process_sp && !process_sp->IsRunning()) {
ThreadSP thread_sp(process_sp->GetThreadList().GetSelectedThread());
if (thread_sp) {
exe_ctx.SetThreadSP(thread_sp);
exe_ctx.SetFrameSP(thread_sp->GetSelectedFrame());
if (exe_ctx.GetFramePtr() == nullptr)
exe_ctx.SetFrameSP(thread_sp->GetStackFrameAtIndex(0));
}
}
}
return exe_ctx;
}
void Debugger::DispatchInputInterrupt() {
std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
IOHandlerSP reader_sp(m_input_reader_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());
if (reader_sp)
reader_sp->GotEOF();
}
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());
if (reader_sp)
PopIOHandler(reader_sp);
}
}
void Debugger::ExecuteIOHandlers() {
while (true) {
IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (!reader_sp)
break;
reader_sp->Run();
// Remove all input readers that are done from the top of the stack
while (true) {
IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
PopIOHandler(top_reader_sp);
else
break;
}
}
ClearIOHandlers();
}
bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {
return m_input_reader_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);
}
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);
}
ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {
return m_input_reader_stack.GetTopIOHandlerControlSequence(ch);
}
const char *Debugger::GetIOHandlerCommandPrefix() {
return m_input_reader_stack.GetTopIOHandlerCommandPrefix();
}
const char *Debugger::GetIOHandlerHelpPrologue() {
return m_input_reader_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;
}
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::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
StreamFileSP &err) {
// Before an IOHandler runs, it must have in/out/err streams. This function
// is called when one ore more of the streams are nullptr. We use the top
// 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());
// If no STDIN has been set, then set it appropriately
if (!in) {
if (top_reader_sp)
in = top_reader_sp->GetInputFileSP();
else
in = GetInputFileSP();
// If there is nothing, use stdin
if (!in)
in = std::make_shared<NativeFile>(stdin, false);
}
// If no STDOUT has been set, then set it appropriately
if (!out) {
if (top_reader_sp)
out = top_reader_sp->GetOutputStreamFileSP();
else
out = GetOutputStreamSP();
// If there is nothing, use stdout
if (!out)
out = std::make_shared<StreamFile>(stdout, false);
}
// If no STDERR has been set, then set it appropriately
if (!err) {
if (top_reader_sp)
err = top_reader_sp->GetErrorStreamFileSP();
else
err = GetErrorStreamSP();
// If there is nothing, use stderr
if (!err)
err = std::make_shared<StreamFile>(stderr, false);
}
}
Don't cancel the current IOHandler when we push a handler for an utility function run. Summary: D48465 is currently blocked by the fact that tab-completing the first expression is deadlocking LLDB. The reason for this deadlock is that when we push the ProcessIO handler for reading the Objective-C runtime information from the executable (which is triggered when we parse the an expression for the first time), the IOHandler can't be pushed as the Editline::Cancel method is deadlocking. The deadlock in Editline is coming from the m_output_mutex, which is locked before we go into tab completion. Even without this lock, calling Cancel on Editline will mean that Editline cleans up behind itself and deletes the current user-input, which is screws up the console when we are tab-completing at the same time. I think for now the most reasonable way of fixing this is to just not call Cancel on the current IOHandler when we push the IOHandler for running an internal utility function. As we can't really write unit tests for IOHandler itself (due to the hard dependency on an initialized Debugger including all its global state) and Editline completion is currently also not really testable in an automatic fashion, the test for this has to be that the expression command completion in D48465 doesn't fail when requesting completion the first time. A more precise test plan for this is: 1. Apply D48465. 2. Start lldb and break in some function. 3. Type `expr foo` and press tab to request completion. 4. Without this patch, we deadlock and LLDB stops responding. I'll provide an actual unit test for this once I got around and made the IOHandler code testable, but for now unblocking D48465 is more critical. Thanks to Jim for helping me debugging this. Reviewers: jingham Reviewed By: jingham Subscribers: emaste, clayborg, abidh, lldb-commits Differential Revision: https://reviews.llvm.org/D50912 llvm-svn: 340988
2018-08-30 06:50:54 +08:00
void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,
bool cancel_top_handler) {
if (!reader_sp)
return;
std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
// Get the current top input reader...
IOHandlerSP top_reader_sp(m_input_reader_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);
reader_sp->Activate();
// Interrupt the top input reader to it will exit its Run() function and let
// this new input reader take over
if (top_reader_sp) {
top_reader_sp->Deactivate();
Don't cancel the current IOHandler when we push a handler for an utility function run. Summary: D48465 is currently blocked by the fact that tab-completing the first expression is deadlocking LLDB. The reason for this deadlock is that when we push the ProcessIO handler for reading the Objective-C runtime information from the executable (which is triggered when we parse the an expression for the first time), the IOHandler can't be pushed as the Editline::Cancel method is deadlocking. The deadlock in Editline is coming from the m_output_mutex, which is locked before we go into tab completion. Even without this lock, calling Cancel on Editline will mean that Editline cleans up behind itself and deletes the current user-input, which is screws up the console when we are tab-completing at the same time. I think for now the most reasonable way of fixing this is to just not call Cancel on the current IOHandler when we push the IOHandler for running an internal utility function. As we can't really write unit tests for IOHandler itself (due to the hard dependency on an initialized Debugger including all its global state) and Editline completion is currently also not really testable in an automatic fashion, the test for this has to be that the expression command completion in D48465 doesn't fail when requesting completion the first time. A more precise test plan for this is: 1. Apply D48465. 2. Start lldb and break in some function. 3. Type `expr foo` and press tab to request completion. 4. Without this patch, we deadlock and LLDB stops responding. I'll provide an actual unit test for this once I got around and made the IOHandler code testable, but for now unblocking D48465 is more critical. Thanks to Jim for helping me debugging this. Reviewers: jingham Reviewed By: jingham Subscribers: emaste, clayborg, abidh, lldb-commits Differential Revision: https://reviews.llvm.org/D50912 llvm-svn: 340988
2018-08-30 06:50:54 +08:00
if (cancel_top_handler)
top_reader_sp->Cancel();
}
}
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());
// 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())
return false;
IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (pop_reader_sp != reader_sp)
return false;
reader_sp->Deactivate();
reader_sp->Cancel();
m_input_reader_stack.Pop();
reader_sp = m_input_reader_stack.Top();
if (reader_sp)
reader_sp->Activate();
return true;
}
StreamSP Debugger::GetAsyncOutputStream() {
return std::make_shared<StreamAsynchronousIO>(*this, true);
}
StreamSP Debugger::GetAsyncErrorStream() {
return std::make_shared<StreamAsynchronousIO>(*this, false);
}
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);
return g_debugger_list_ptr->size();
}
return 0;
}
lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) {
DebuggerSP debugger_sp;
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
if (index < g_debugger_list_ptr->size())
debugger_sp = g_debugger_list_ptr->at(index);
}
return debugger_sp;
}
DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) {
DebuggerSP debugger_sp;
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
if ((*pos)->GetID() == id) {
debugger_sp = *pos;
break;
}
}
}
return debugger_sp;
}
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class. Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing. The new code improves on this with the following features: 1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry. 2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format 3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it. 4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly 5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings 6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features. 7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries. These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more). llvm-svn: 228207
2015-02-05 06:00:53 +08:00
bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,
const SymbolContext *sc,
const SymbolContext *prev_sc,
const ExecutionContext *exe_ctx,
const Address *addr, Stream &s) {
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class. Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing. The new code improves on this with the following features: 1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry. 2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format 3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it. 4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly 5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings 6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features. 7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries. These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more). llvm-svn: 228207
2015-02-05 06:00:53 +08:00
FormatEntity::Entry format_entry;
if (format == nullptr) {
if (exe_ctx != nullptr && exe_ctx->HasTargetScope())
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class. Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing. The new code improves on this with the following features: 1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry. 2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format 3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it. 4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly 5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings 6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features. 7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries. These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more). llvm-svn: 228207
2015-02-05 06:00:53 +08:00
format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
if (format == nullptr) {
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class. Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing. The new code improves on this with the following features: 1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry. 2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format 3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it. 4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly 5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings 6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features. 7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries. These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more). llvm-svn: 228207
2015-02-05 06:00:53 +08:00
FormatEntity::Parse("${addr}: ", format_entry);
format = &format_entry;
}
}
bool function_changed = false;
bool initial_function = false;
if (prev_sc && (prev_sc->function || prev_sc->symbol)) {
if (sc && (sc->function || sc->symbol)) {
if (prev_sc->symbol && sc->symbol) {
if (!sc->symbol->Compare(prev_sc->symbol->GetName(),
prev_sc->symbol->GetType())) {
function_changed = true;
}
} else if (prev_sc->function && sc->function) {
if (prev_sc->function->GetMangled() != sc->function->GetMangled()) {
function_changed = true;
}
}
}
}
// The first context on a list of instructions will have a prev_sc that has
// no Function or Symbol -- if SymbolContext had an IsValid() method, it
// would return false. But we do get a prev_sc pointer.
if ((sc && (sc->function || sc->symbol)) && prev_sc &&
(prev_sc->function == nullptr && prev_sc->symbol == nullptr)) {
initial_function = true;
}
return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr,
function_changed, initial_function);
}
void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
void *baton) {
// For simplicity's sake, I am not going to deal with how to close down any
// open logging streams, I just redirect everything from here on out to the
// callback.
m_log_callback_stream_sp =
std::make_shared<StreamCallback>(log_callback, baton);
}
bool Debugger::EnableLog(llvm::StringRef channel,
llvm::ArrayRef<const char *> categories,
llvm::StringRef log_file, uint32_t log_options,
llvm::raw_ostream &error_stream) {
const bool should_close = true;
const bool unbuffered = true;
std::shared_ptr<llvm::raw_ostream> log_stream_sp;
if (m_log_callback_stream_sp) {
log_stream_sp = m_log_callback_stream_sp;
// For now when using the callback mode you always get thread & timestamp.
log_options |=
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
} else if (log_file.empty()) {
log_stream_sp = std::make_shared<llvm::raw_fd_ostream>(
GetOutputFile().GetDescriptor(), !should_close, unbuffered);
} else {
auto pos = m_log_streams.find(log_file);
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;
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();
return false;
}
log_stream_sp =
std::make_shared<llvm::raw_fd_ostream>(FD, should_close, unbuffered);
m_log_streams[log_file] = log_stream_sp;
}
}
assert(log_stream_sp);
if (log_options == 0)
log_options =
LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories,
error_stream);
}
ScriptInterpreter *Debugger::GetScriptInterpreter(bool can_create) {
std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);
if (!m_script_interpreter_sp) {
if (!can_create)
return nullptr;
m_script_interpreter_sp = PluginManager::GetScriptInterpreterForLanguage(
GetScriptLanguage(), *this);
}
return m_script_interpreter_sp.get();
}
SourceManager &Debugger::GetSourceManager() {
if (!m_source_manager_up)
m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
return *m_source_manager_up;
}
// This function handles events that were broadcast by the process.
void Debugger::HandleBreakpointEvent(const EventSP &event_sp) {
using namespace lldb;
const uint32_t event_type =
Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(
event_sp);
// if (event_type & eBreakpointEventTypeAdded
// || event_type & eBreakpointEventTypeRemoved
// || event_type & eBreakpointEventTypeEnabled
// || event_type & eBreakpointEventTypeDisabled
// || event_type & eBreakpointEventTypeCommandChanged
// || event_type & eBreakpointEventTypeConditionChanged
// || event_type & eBreakpointEventTypeIgnoreChanged
// || event_type & eBreakpointEventTypeLocationsResolved)
// {
// // Don't do anything about these events, since the breakpoint
// commands already echo these actions.
// }
//
if (event_type & eBreakpointEventTypeLocationsAdded) {
uint32_t num_new_locations =
Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(
event_sp);
if (num_new_locations > 0) {
BreakpointSP breakpoint =
Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
StreamSP output_sp(GetAsyncOutputStream());
if (output_sp) {
output_sp->Printf("%d location%s added to breakpoint %d\n",
num_new_locations, num_new_locations == 1 ? "" : "s",
breakpoint->GetID());
output_sp->Flush();
}
}
}
// else if (event_type & eBreakpointEventTypeLocationsRemoved)
// {
// // These locations just get disabled, not sure it is worth spamming
// folks about this on the command line.
// }
// else if (event_type & eBreakpointEventTypeLocationsResolved)
// {
// // This might be an interesting thing to note, but I'm going to
// leave it quiet for now, it just looked noisy.
// }
}
void Debugger::FlushProcessOutput(Process &process, bool flush_stdout,
bool flush_stderr) {
const auto &flush = [&](Stream &stream,
size_t (Process::*get)(char *, size_t, Status &)) {
Status error;
size_t len;
char buffer[1024];
while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0)
stream.Write(buffer, len);
stream.Flush();
};
std::lock_guard<std::mutex> guard(m_output_flush_mutex);
if (flush_stdout)
flush(*GetAsyncOutputStream(), &Process::GetSTDOUT);
if (flush_stderr)
flush(*GetAsyncErrorStream(), &Process::GetSTDERR);
}
// This function handles events that were broadcast by the process.
void Debugger::HandleProcessEvent(const EventSP &event_sp) {
using namespace lldb;
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp =
(event_type == Process::eBroadcastBitStructuredData)
? EventDataStructuredData::GetProcessFromEvent(event_sp.get())
: Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
StreamSP output_stream_sp = GetAsyncOutputStream();
StreamSP error_stream_sp = GetAsyncErrorStream();
const bool gui_enabled = IsForwardingEvents();
if (!gui_enabled) {
bool pop_process_io_handler = false;
assert(process_sp);
bool state_is_stopped = false;
const bool got_state_changed =
(event_type & Process::eBroadcastBitStateChanged) != 0;
const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
const bool got_structured_data =
(event_type & Process::eBroadcastBitStructuredData) != 0;
if (got_state_changed) {
StateType event_state =
Process::ProcessEventData::GetStateFromEvent(event_sp.get());
state_is_stopped = StateIsStoppedState(event_state, false);
}
// Display running state changes first before any STDIO
if (got_state_changed && !state_is_stopped) {
Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
pop_process_io_handler);
}
// Now display STDOUT and STDERR
FlushProcessOutput(*process_sp, got_stdout || got_state_changed,
got_stderr || got_state_changed);
// Give structured data events an opportunity to display.
if (got_structured_data) {
StructuredDataPluginSP plugin_sp =
EventDataStructuredData::GetPluginFromEvent(event_sp.get());
if (plugin_sp) {
auto structured_data_sp =
EventDataStructuredData::GetObjectFromEvent(event_sp.get());
if (output_stream_sp) {
StreamString content_stream;
Status error =
plugin_sp->GetDescription(structured_data_sp, content_stream);
if (error.Success()) {
if (!content_stream.GetString().empty()) {
// Add newline.
content_stream.PutChar('\n');
content_stream.Flush();
// Print it.
output_stream_sp->PutCString(content_stream.GetString());
}
} else {
error_stream_sp->Printf("Failed to print structured "
"data with plugin %s: %s",
plugin_sp->GetPluginName().AsCString(),
error.AsCString());
}
}
}
}
// Now display any stopped state changes after any STDIO
if (got_state_changed && state_is_stopped) {
Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
pop_process_io_handler);
}
output_stream_sp->Flush();
error_stream_sp->Flush();
if (pop_process_io_handler)
process_sp->PopProcessIOHandler();
}
}
void Debugger::HandleThreadEvent(const EventSP &event_sp) {
// At present the only thread event we handle is the Frame Changed event, and
// all we do for that is just reprint the thread status for that thread.
using namespace lldb;
const uint32_t event_type = event_sp->GetType();
const bool stop_format = true;
if (event_type == Thread::eBroadcastBitStackChanged ||
event_type == Thread::eBroadcastBitThreadSelected) {
ThreadSP thread_sp(
Thread::ThreadEventData::GetThreadFromEvent(event_sp.get()));
if (thread_sp) {
thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format);
}
}
}
bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }
void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) {
m_forward_listener_sp = listener_sp;
}
void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {
m_forward_listener_sp.reset();
}
void Debugger::DefaultEventHandler() {
ListenerSP listener_sp(GetListener());
ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
BroadcastEventSpec target_event_spec(broadcaster_class_target,
Target::eBroadcastBitBreakpointChanged);
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
BroadcastEventSpec process_event_spec(
broadcaster_class_process,
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT |
Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData);
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
BroadcastEventSpec thread_event_spec(broadcaster_class_thread,
Thread::eBroadcastBitStackChanged |
Thread::eBroadcastBitThreadSelected);
listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
target_event_spec);
listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
process_event_spec);
listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
thread_event_spec);
listener_sp->StartListeningForEvents(
m_command_interpreter_up.get(),
CommandInterpreter::eBroadcastBitQuitCommandReceived |
CommandInterpreter::eBroadcastBitAsynchronousOutputData |
CommandInterpreter::eBroadcastBitAsynchronousErrorData);
// Let the thread that spawned us know that we have started up and that we
// are now listening to all required events so no events get missed
m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
bool done = false;
while (!done) {
EventSP event_sp;
if (listener_sp->GetEvent(event_sp, llvm::None)) {
if (event_sp) {
Broadcaster *broadcaster = event_sp->GetBroadcaster();
if (broadcaster) {
uint32_t event_type = event_sp->GetType();
ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process) {
HandleProcessEvent(event_sp);
} else if (broadcaster_class == broadcaster_class_target) {
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
event_sp.get())) {
HandleBreakpointEvent(event_sp);
}
} else if (broadcaster_class == broadcaster_class_thread) {
HandleThreadEvent(event_sp);
} else if (broadcaster == m_command_interpreter_up.get()) {
if (event_type &
CommandInterpreter::eBroadcastBitQuitCommandReceived) {
done = true;
} else if (event_type &
CommandInterpreter::eBroadcastBitAsynchronousErrorData) {
const char *data = reinterpret_cast<const char *>(
EventDataBytes::GetBytesFromEvent(event_sp.get()));
if (data && data[0]) {
StreamSP error_sp(GetAsyncErrorStream());
if (error_sp) {
error_sp->PutCString(data);
error_sp->Flush();
}
}
} else if (event_type & CommandInterpreter::
eBroadcastBitAsynchronousOutputData) {
const char *data = reinterpret_cast<const char *>(
EventDataBytes::GetBytesFromEvent(event_sp.get()));
if (data && data[0]) {
StreamSP output_sp(GetAsyncOutputStream());
if (output_sp) {
output_sp->PutCString(data);
output_sp->Flush();
}
}
}
}
}
if (m_forward_listener_sp)
m_forward_listener_sp->AddEvent(event_sp);
}
}
}
}
lldb::thread_result_t Debugger::EventHandlerThread(lldb::thread_arg_t arg) {
((Debugger *)arg)->DefaultEventHandler();
[lldb] fix cannot convert from 'nullptr' to 'lldb::thread_result_t' Summary: On Windows `lldb::thread_result_t` resolves to `typedef unsigned thread_result_t;` and on other platforms it resolves to `typedef void *thread_result_t;`. Therefore one cannot use `nullptr` when returning from a function that returns `thread_result_t`. I've made this change because a windows build bot fails with these errors: ``` E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Communication.cpp(362): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Communication.cpp(362): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type ``` and ``` E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1619): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1619): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1664): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1664): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type ``` This is the failing build: http://lab.llvm.org:8011/builders/lldb-x64-windows-ninja/builds/5035/steps/build/logs/stdio Reviewers: JDevlieghere, teemperor, jankratochvil, labath, clayborg, RKSimon, courbet, jhenderson Reviewed By: labath, clayborg Subscribers: labath, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D62305 llvm-svn: 361503
2019-05-23 23:17:39 +08:00
return {};
}
bool Debugger::StartEventHandlerThread() {
if (!m_event_handler_thread.IsJoinable()) {
// We must synchronize with the DefaultEventHandler() thread to ensure it
// is up and running and listening to events before we return from this
// function. We do this by listening to events for the
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
// eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
ConstString full_name("lldb.debugger.event-handler");
ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString()));
listener_sp->StartListeningForEvents(&m_sync_broadcaster,
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
eBroadcastBitEventThreadIsListening);
auto thread_name =
full_name.GetLength() < llvm::get_max_thread_name_length()
? full_name.AsCString()
: "dbg.evt-handler";
// Use larger 8MB stack for this thread
llvm::Expected<HostThread> event_handler_thread =
ThreadLauncher::LaunchThread(thread_name, EventHandlerThread, this,
g_debugger_event_thread_stack_bytes);
if (event_handler_thread) {
m_event_handler_thread = *event_handler_thread;
} else {
LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
"failed to launch host thread: {}",
llvm::toString(event_handler_thread.takeError()));
}
// Make sure DefaultEventHandler() is running and listening to events
// before we return from this function. We are only listening for events of
// type eBroadcastBitEventThreadIsListening so we don't need to check the
// event, we just need to wait an infinite amount of time for it (nullptr
// timeout as the first parameter)
lldb can deadlock when launched with an non-existing executable: % lldb /bin/nonono (lldb) target create "/bin/nonono" error: unable to find executable for '/usr/bin/nonono' <deadlock> The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with: void CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { // Always re-create the command intepreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); m_stopped_for_crash = false; if (auto_handle_events) m_debugger.StartEventHandlerThread(); if (spawn_thread) { m_debugger.StartIOHandlerThread(); } else { m_debugger.ExecuteIOHanders(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); } } If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute: m_debugger.StartEventHandlerThread(); m_debugger.ExecuteIOHanders(); m_debugger.StopEventHandlerThread(); The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do: void Debugger::StopEventHandlerThread() { if (m_event_handler_thread.IsJoinable()) { GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); m_event_handler_thread.Join(nullptr); } } The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet. The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition. This fixes radar: <rdar://problem/19041192> llvm-svn: 223083
2014-12-02 06:41:27 +08:00
lldb::EventSP event_sp;
listener_sp->GetEvent(event_sp, llvm::None);
}
return m_event_handler_thread.IsJoinable();
}
void Debugger::StopEventHandlerThread() {
if (m_event_handler_thread.IsJoinable()) {
GetCommandInterpreter().BroadcastEvent(
CommandInterpreter::eBroadcastBitQuitCommandReceived);
m_event_handler_thread.Join(nullptr);
}
}
lldb::thread_result_t Debugger::IOHandlerThread(lldb::thread_arg_t arg) {
Debugger *debugger = (Debugger *)arg;
debugger->ExecuteIOHandlers();
debugger->StopEventHandlerThread();
[lldb] fix cannot convert from 'nullptr' to 'lldb::thread_result_t' Summary: On Windows `lldb::thread_result_t` resolves to `typedef unsigned thread_result_t;` and on other platforms it resolves to `typedef void *thread_result_t;`. Therefore one cannot use `nullptr` when returning from a function that returns `thread_result_t`. I've made this change because a windows build bot fails with these errors: ``` E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Communication.cpp(362): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Communication.cpp(362): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type ``` and ``` E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1619): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1619): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1664): error C2440: 'return': cannot convert from 'nullptr' to 'lldb::thread_result_t' E:\build_slave\lldb-x64-windows-ninja\llvm\tools\lldb\source\Core\Debugger.cpp(1664): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type ``` This is the failing build: http://lab.llvm.org:8011/builders/lldb-x64-windows-ninja/builds/5035/steps/build/logs/stdio Reviewers: JDevlieghere, teemperor, jankratochvil, labath, clayborg, RKSimon, courbet, jhenderson Reviewed By: labath, clayborg Subscribers: labath, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D62305 llvm-svn: 361503
2019-05-23 23:17:39 +08:00
return {};
}
bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); }
bool Debugger::StartIOHandlerThread() {
if (!m_io_handler_thread.IsJoinable()) {
llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread(
"lldb.debugger.io-handler", IOHandlerThread, this,
8 * 1024 * 1024); // Use larger 8MB stack for this thread
if (io_handler_thread) {
m_io_handler_thread = *io_handler_thread;
} else {
LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
"failed to launch host thread: {}",
llvm::toString(io_handler_thread.takeError()));
}
}
return m_io_handler_thread.IsJoinable();
}
void Debugger::StopIOHandlerThread() {
if (m_io_handler_thread.IsJoinable()) {
GetInputFile().Close();
m_io_handler_thread.Join(nullptr);
}
}
void Debugger::JoinIOHandlerThread() {
if (HasIOHandlerThread()) {
thread_result_t result;
m_io_handler_thread.Join(&result);
m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
}
}
Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {
Target *target = nullptr;
if (!prefer_dummy) {
target = m_target_list.GetSelectedTarget().get();
if (target)
return target;
}
return GetDummyTarget();
}
Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
Status err;
FileSpec repl_executable;
if (language == eLanguageTypeUnknown) {
LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
if (auto single_lang = repl_languages.GetSingularLanguage()) {
language = *single_lang;
} else if (repl_languages.Empty()) {
err.SetErrorStringWithFormat(
"LLDB isn't configured with REPL support for any languages.");
return err;
} else {
err.SetErrorStringWithFormat(
"Multiple possible REPL languages. Please specify a language.");
return err;
}
}
Target *const target =
nullptr; // passing in an empty target means the REPL must create one
REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options));
if (!err.Success()) {
return err;
}
if (!repl_sp) {
err.SetErrorStringWithFormat("couldn't find a REPL for %s",
Language::GetNameForLanguageType(language));
return err;
}
repl_sp->SetCompilerOptions(repl_options);
repl_sp->RunLoop();
return err;
}