[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-24 08:23:27 +01:00
|
|
|
//===-- Debugger.cpp ------------------------------------------------------===//
|
2010-06-08 16:52:24 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2010-06-08 16:52:24 +00:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2011-06-23 17:59:56 +00:00
|
|
|
#include "lldb/Core/Debugger.h"
|
|
|
|
|
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Breakpoint/Breakpoint.h"
|
2022-03-14 09:01:53 -07:00
|
|
|
#include "lldb/Core/DebuggerEvents.h"
|
2015-02-04 22:00:53 +00:00
|
|
|
#include "lldb/Core/FormatEntity.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Core/Mangled.h"
|
|
|
|
|
#include "lldb/Core/ModuleList.h"
|
[lldb] Fetching symbols in the background with dsymForUUID
On macOS, LLDB uses the DebugSymbols.framework to locate symbol rich
dSYM bundles. [1] The framework uses a variety of methods, one of them
calling into a binary or shell script to locate (and download) dSYMs.
Internally at Apple, that tool is called dsymForUUID and for simplicity
I'm just going to refer to it that way here too, even though it can be
be an arbitrary executable.
The most common use case for dsymForUUID is to fetch symbols from the
network. This can take a long time, and because the calls to the
DebugSymbols.framework are blocking, it takes a while to launch the
process. This is expected and therefore many people don't use this
functionality, but instead use add-dsym when they want symbols for a
given frame, backtrace or module. This is a little faster because you're
only fetching symbols for the module you care about, but it's still a
slow, blocking operation.
This patch introduces a hybrid approach between the two. When
symbols.enable-background-lookup is enabled, lldb will do the equivalent
of add-dsym in the background for every module that shows up in the
backtrace but doesn't have symbols for. From the user's perspective
there is no slowdown, because the process launches immediately, with
whatever symbols are available. Meanwhile, more symbol information is
added over time as the background fetching completes.
[1] https://lldb.llvm.org/use/symbols.html
rdar://76241471
Differential revision: https://reviews.llvm.org/D131328
2022-08-15 17:37:34 -07:00
|
|
|
#include "lldb/Core/ModuleSpec.h"
|
2012-10-19 18:02:49 +00:00
|
|
|
#include "lldb/Core/PluginManager.h"
|
2024-03-01 10:56:45 -08:00
|
|
|
#include "lldb/Core/Progress.h"
|
2025-06-20 10:48:04 -05:00
|
|
|
#include "lldb/Core/ProtocolServer.h"
|
2011-06-02 23:58:26 +00:00
|
|
|
#include "lldb/Core/StreamAsynchronousIO.h"
|
2025-03-03 10:07:54 -05:00
|
|
|
#include "lldb/Core/Telemetry.h"
|
2013-01-28 23:47:25 +00:00
|
|
|
#include "lldb/DataFormatters/DataVisualization.h"
|
2015-10-20 00:23:46 +00:00
|
|
|
#include "lldb/Expression/REPL.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Host/File.h"
|
2018-11-01 00:33:27 +00:00
|
|
|
#include "lldb/Host/FileSystem.h"
|
2014-08-21 17:29:12 +00:00
|
|
|
#include "lldb/Host/HostInfo.h"
|
2023-08-08 17:18:47 -07:00
|
|
|
#include "lldb/Host/StreamFile.h"
|
2011-02-07 23:24:47 +00:00
|
|
|
#include "lldb/Host/Terminal.h"
|
2014-09-09 20:54:56 +00:00
|
|
|
#include "lldb/Host/ThreadLauncher.h"
|
2010-06-23 01:19:29 +00:00
|
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
2021-06-28 19:27:55 +00:00
|
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Interpreter/OptionValue.h"
|
2022-01-05 14:42:21 -08:00
|
|
|
#include "lldb/Interpreter/OptionValueLanguage.h"
|
2015-03-04 01:58:01 +00:00
|
|
|
#include "lldb/Interpreter/OptionValueProperties.h"
|
2012-08-22 17:17:09 +00:00
|
|
|
#include "lldb/Interpreter/OptionValueSInt64.h"
|
|
|
|
|
#include "lldb/Interpreter/OptionValueString.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#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-29 21:13:06 +00:00
|
|
|
#include "lldb/Symbol/Function.h"
|
|
|
|
|
#include "lldb/Symbol/Symbol.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Symbol/SymbolContext.h"
|
2015-10-20 00:23:46 +00:00
|
|
|
#include "lldb/Target/Language.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Target/Process.h"
|
2016-08-19 04:21:48 +00:00
|
|
|
#include "lldb/Target/StructuredDataPlugin.h"
|
2013-05-20 22:29:23 +00:00
|
|
|
#include "lldb/Target/Target.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Target/TargetList.h"
|
|
|
|
|
#include "lldb/Target/Thread.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Target/ThreadList.h"
|
2011-10-14 07:41:33 +00:00
|
|
|
#include "lldb/Utility/AnsiTerminal.h"
|
2018-12-14 15:59:49 +00:00
|
|
|
#include "lldb/Utility/Event.h"
|
2022-02-03 13:26:10 +01:00
|
|
|
#include "lldb/Utility/LLDBLog.h"
|
2018-12-14 15:59:49 +00:00
|
|
|
#include "lldb/Utility/Listener.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Utility/Log.h"
|
2018-08-07 11:07:21 +00:00
|
|
|
#include "lldb/Utility/State.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Utility/Stream.h"
|
2017-02-02 21:39:50 +00:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
2025-03-03 10:07:54 -05:00
|
|
|
#include "lldb/Version/Version.h"
|
[lldb] Introduce dwim-print command
Implements `dwim-print`, a printing command that chooses the most direct,
efficient, and resilient means of printing a given expression.
DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
> attempt to anticipate what users intend to do, correcting trivial errors
> automatically rather than blindly executing users' explicit but
> potentially incorrect input
The `dwim-print` command serves as a single print command for users who don't
yet know, or prefer not to know, the various lldb commands that can be used to
print, and when to use them.
This initial implementation is the base foundation for `dwim-print`. It accepts
no flags, only an expression. If the expression is the name of a variable in
the frame, then effectively `frame variable` is used to get, and print, its
value. Otherwise, printing falls back to using `expression` evaluation. In this
initial version, frame variable paths will be handled with `expression`.
Following this, there are a number of improvements that can be made. Some
improvements include supporting `frame variable` expressions or registers.
To provide transparency, especially as the `dwim-print` command evolves, a new
setting is also introduced: `dwim-print-verbosity`. This setting instructs
`dwim-print` to optionally print a message showing the effective command being
run. For example `dwim-print var.meth()` can print a message such as: "note:
ran `expression var.meth()`".
See https://discourse.llvm.org/t/dwim-print-command/66078 for the proposal and
discussion.
Differential Revision: https://reviews.llvm.org/D138315
2022-11-17 17:11:30 -08:00
|
|
|
#include "lldb/lldb-enumerations.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
|
2018-04-10 13:33:45 +00:00
|
|
|
#if defined(_WIN32)
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "lldb/Host/windows/PosixApi.h"
|
2018-09-05 22:06:58 +00:00
|
|
|
#include "lldb/Host/windows/windows.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "llvm/ADT/iterator.h"
|
2025-03-03 10:07:54 -05:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
#include "llvm/Support/DynamicLibrary.h"
|
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
2018-09-05 22:06:58 +00:00
|
|
|
#include "llvm/Support/Process.h"
|
2022-04-06 15:48:22 +02:00
|
|
|
#include "llvm/Support/ThreadPool.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
#include "llvm/Support/Threading.h"
|
2018-11-11 23:16:43 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-04-06 21:28:29 +00:00
|
|
|
|
2025-03-03 10:07:54 -05:00
|
|
|
#include <chrono>
|
2021-05-26 12:19:37 +02:00
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
2018-11-11 23:16:43 +00:00
|
|
|
#include <list>
|
|
|
|
|
#include <memory>
|
2017-04-06 21:28:29 +00:00
|
|
|
#include <mutex>
|
2023-01-07 13:43:00 -08:00
|
|
|
#include <optional>
|
2018-11-11 23:16:43 +00:00
|
|
|
#include <set>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <system_error>
|
2017-04-06 21:28:29 +00:00
|
|
|
|
2021-11-24 16:13:48 +00:00
|
|
|
// Includes for pipe()
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <io.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-04-06 21:28:29 +00:00
|
|
|
namespace lldb_private {
|
|
|
|
|
class Address;
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
2010-06-30 16:22:25 +00:00
|
|
|
static lldb::user_id_t g_unique_id = 1;
|
2014-10-24 22:06:29 +00:00
|
|
|
static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
|
2010-06-30 16:22:25 +00:00
|
|
|
|
2010-09-19 02:33:57 +00:00
|
|
|
#pragma mark Static Functions
|
|
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
static std::recursive_mutex *g_debugger_list_mutex_ptr =
|
|
|
|
|
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
|
2023-05-23 11:13:36 -07:00
|
|
|
static Debugger::DebuggerList *g_debugger_list_ptr =
|
2012-08-22 17:17:09 +00:00
|
|
|
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
|
2024-03-06 10:17:58 +08:00
|
|
|
static llvm::DefaultThreadPool *g_thread_pool = nullptr;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-09-26 18:50:19 +00:00
|
|
|
static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
|
2019-08-02 00:18:44 +00:00
|
|
|
{
|
2025-04-25 23:35:20 +02:00
|
|
|
lldb::eStopDisassemblyTypeNever,
|
2019-08-02 00:18:44 +00:00
|
|
|
"never",
|
|
|
|
|
"Never show disassembly when displaying a stop context.",
|
|
|
|
|
},
|
|
|
|
|
{
|
2025-04-25 23:35:20 +02:00
|
|
|
lldb::eStopDisassemblyTypeNoDebugInfo,
|
2019-08-02 00:18:44 +00:00
|
|
|
"no-debuginfo",
|
|
|
|
|
"Show disassembly when there is no debug information.",
|
|
|
|
|
},
|
|
|
|
|
{
|
2025-04-25 23:35:20 +02:00
|
|
|
lldb::eStopDisassemblyTypeNoSource,
|
2019-08-02 00:18:44 +00:00
|
|
|
"no-source",
|
|
|
|
|
"Show disassembly when there is no source information, or the source "
|
|
|
|
|
"file "
|
|
|
|
|
"is missing when displaying a stop context.",
|
|
|
|
|
},
|
|
|
|
|
{
|
2025-04-25 23:35:20 +02:00
|
|
|
lldb::eStopDisassemblyTypeAlways,
|
2019-08-02 00:18:44 +00:00
|
|
|
"always",
|
|
|
|
|
"Always show disassembly when displaying a stop context.",
|
|
|
|
|
},
|
|
|
|
|
};
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-09-26 18:50:19 +00:00
|
|
|
static constexpr OptionEnumValueElement g_language_enumerators[] = {
|
2019-08-02 00:18:44 +00:00
|
|
|
{
|
|
|
|
|
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.",
|
|
|
|
|
},
|
|
|
|
|
};
|
2016-09-06 20:57:50 +00:00
|
|
|
|
[lldb] Introduce dwim-print command
Implements `dwim-print`, a printing command that chooses the most direct,
efficient, and resilient means of printing a given expression.
DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
> attempt to anticipate what users intend to do, correcting trivial errors
> automatically rather than blindly executing users' explicit but
> potentially incorrect input
The `dwim-print` command serves as a single print command for users who don't
yet know, or prefer not to know, the various lldb commands that can be used to
print, and when to use them.
This initial implementation is the base foundation for `dwim-print`. It accepts
no flags, only an expression. If the expression is the name of a variable in
the frame, then effectively `frame variable` is used to get, and print, its
value. Otherwise, printing falls back to using `expression` evaluation. In this
initial version, frame variable paths will be handled with `expression`.
Following this, there are a number of improvements that can be made. Some
improvements include supporting `frame variable` expressions or registers.
To provide transparency, especially as the `dwim-print` command evolves, a new
setting is also introduced: `dwim-print-verbosity`. This setting instructs
`dwim-print` to optionally print a message showing the effective command being
run. For example `dwim-print var.meth()` can print a message such as: "note:
ran `expression var.meth()`".
See https://discourse.llvm.org/t/dwim-print-command/66078 for the proposal and
discussion.
Differential Revision: https://reviews.llvm.org/D138315
2022-11-17 17:11:30 -08:00
|
|
|
static constexpr OptionEnumValueElement g_dwim_print_verbosities[] = {
|
|
|
|
|
{eDWIMPrintVerbosityNone, "none",
|
|
|
|
|
"Use no verbosity when running dwim-print."},
|
|
|
|
|
{eDWIMPrintVerbosityExpression, "expression",
|
|
|
|
|
"Use partial verbosity when running dwim-print - display a message when "
|
|
|
|
|
"`expression` evaluation is used."},
|
|
|
|
|
{eDWIMPrintVerbosityFull, "full",
|
|
|
|
|
"Use full verbosity when running dwim-print."},
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-26 18:50:19 +00:00
|
|
|
static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
|
2019-08-02 00:18:44 +00:00
|
|
|
{
|
|
|
|
|
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-21 20:13:14 +00:00
|
|
|
|
2019-07-25 21:36:37 +00:00
|
|
|
#define LLDB_PROPERTIES_debugger
|
2019-07-29 17:22:10 +00:00
|
|
|
#include "CoreProperties.inc"
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
enum {
|
2019-07-25 21:36:37 +00:00
|
|
|
#define LLDB_PROPERTIES_debugger
|
2019-07-29 17:22:10 +00:00
|
|
|
#include "CorePropertiesEnum.inc"
|
2012-08-22 17:17:09 +00:00
|
|
|
};
|
2010-09-19 02:33:57 +00:00
|
|
|
|
2016-03-02 02:18:18 +00:00
|
|
|
LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
|
2012-09-01 00:38:36 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
|
|
|
|
|
VarSetOperationType op,
|
|
|
|
|
llvm::StringRef property_path,
|
|
|
|
|
llvm::StringRef value) {
|
2019-08-02 00:18:44 +00:00
|
|
|
bool is_load_script =
|
|
|
|
|
(property_path == "target.load-script-from-symbol-file");
|
2019-09-04 11:41:23 +00:00
|
|
|
// 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();
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-20 22:29:23 +00:00
|
|
|
TargetSP target_sp;
|
[LLDB][NFC][Reliability] Fix uninitialized variables from Coverity scan. Part 3
Improve LLDB reliability by fixing the following "uninitialized variables" static code inspection warnings from
scan.coverity.com/projects/llvm:
1355854, 1347549, 1316348, 1372028, 1431625,
1315634, 1315637, 1355855, 1364803, 1420505,
1420563, 1420685, 1366014, 1203966, 1204029,
1204031, 1204032, 1328411, 1325969, 1325968,
1374921, 1094809
Differential Revision: https://reviews.llvm.org/D130602
2022-07-26 14:18:41 -07:00
|
|
|
LoadScriptFromSymFile load_script_old_value = eLoadScriptFromSymFileFalse;
|
2023-07-10 14:37:06 -07:00
|
|
|
if (is_load_script && exe_ctx && exe_ctx->GetTargetSP()) {
|
2013-05-20 22:29:23 +00:00
|
|
|
target_sp = exe_ctx->GetTargetSP();
|
|
|
|
|
load_script_old_value =
|
|
|
|
|
target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
|
|
|
|
|
}
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
|
2012-09-01 00:38:36 +00:00
|
|
|
if (error.Success()) {
|
2013-05-20 22:29:23 +00:00
|
|
|
// FIXME it would be nice to have "on-change" callbacks for properties
|
2019-07-29 16:41:30 +00:00
|
|
|
if (property_path == g_debugger_properties[ePropertyPrompt].name) {
|
2016-09-23 18:06:53 +00:00
|
|
|
llvm::StringRef new_prompt = GetPrompt();
|
2019-08-21 00:50:46 +00:00
|
|
|
std::string str = lldb_private::ansi::FormatAnsiTerminalCodes(
|
2013-05-23 20:47:45 +00:00
|
|
|
new_prompt, GetUseColor());
|
|
|
|
|
if (str.length())
|
2016-11-02 20:34:10 +00:00
|
|
|
new_prompt = str;
|
2014-01-27 23:43:24 +00:00
|
|
|
GetCommandInterpreter().UpdatePrompt(new_prompt);
|
2019-08-14 22:19:23 +00:00
|
|
|
auto bytes = std::make_unique<EventDataBytes>(new_prompt);
|
2017-04-06 21:28:29 +00:00
|
|
|
auto prompt_change_event_sp = std::make_shared<Event>(
|
|
|
|
|
CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());
|
2012-09-01 00:38:36 +00:00
|
|
|
GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);
|
2019-07-29 16:41:30 +00:00
|
|
|
} else if (property_path == g_debugger_properties[ePropertyUseColor].name) {
|
2025-04-22 12:21:23 +01:00
|
|
|
// use-color changed. set use-color, this also pings the prompt so it can
|
|
|
|
|
// reset the ansi terminal codes.
|
|
|
|
|
SetUseColor(GetUseColor());
|
2023-09-13 20:58:12 -07:00
|
|
|
} else if (property_path ==
|
|
|
|
|
g_debugger_properties[ePropertyPromptAnsiPrefix].name ||
|
|
|
|
|
property_path ==
|
|
|
|
|
g_debugger_properties[ePropertyPromptAnsiSuffix].name) {
|
2025-04-22 12:21:23 +01:00
|
|
|
// Prompt color changed. set use-color, this also pings the prompt so it
|
|
|
|
|
// can reset the ansi terminal codes.
|
|
|
|
|
SetUseColor(GetUseColor());
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
} else if (property_path ==
|
|
|
|
|
g_debugger_properties[ePropertyShowStatusline].name) {
|
|
|
|
|
// Statusline setting changed. If we have a statusline instance, update it
|
|
|
|
|
// now. Otherwise it will get created in the default event handler.
|
2025-04-11 08:53:49 -07:00
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
2025-09-23 14:18:11 -07:00
|
|
|
if (StatuslineSupported()) {
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
m_statusline.emplace(*this);
|
2025-09-23 14:18:11 -07:00
|
|
|
m_statusline->Enable(GetSelectedExecutionContextRef());
|
|
|
|
|
} else {
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
m_statusline.reset();
|
2025-09-23 14:18:11 -07:00
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
} else if (property_path ==
|
2025-04-22 22:38:28 -07:00
|
|
|
g_debugger_properties[ePropertyStatuslineFormat].name ||
|
|
|
|
|
property_path ==
|
|
|
|
|
g_debugger_properties[ePropertySeparator].name) {
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
// Statusline format changed. Redraw the statusline.
|
2025-09-23 14:18:11 -07:00
|
|
|
RedrawStatusline(std::nullopt);
|
2023-06-13 20:48:05 -07:00
|
|
|
} else if (property_path ==
|
|
|
|
|
g_debugger_properties[ePropertyUseSourceCache].name) {
|
|
|
|
|
// use-source-cache changed. Wipe out the cache contents if it was
|
|
|
|
|
// disabled.
|
2020-04-20 16:17:17 +02:00
|
|
|
if (!GetUseSourceCache()) {
|
|
|
|
|
m_source_file_cache.Clear();
|
|
|
|
|
}
|
2013-05-21 20:13:34 +00:00
|
|
|
} else if (is_load_script && target_sp &&
|
|
|
|
|
load_script_old_value == eLoadScriptFromSymFileWarn) {
|
|
|
|
|
if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
|
|
|
|
|
eLoadScriptFromSymFileTrue) {
|
2017-05-12 04:51:55 +00:00
|
|
|
std::list<Status> errors;
|
2013-05-21 00:00:30 +00:00
|
|
|
StreamString feedback_stream;
|
2023-07-10 13:19:13 -07:00
|
|
|
if (!target_sp->LoadScriptingResources(errors, feedback_stream)) {
|
2025-02-20 11:13:46 -08:00
|
|
|
lldb::StreamUP s = GetAsyncErrorStream();
|
2025-02-12 08:29:06 -08:00
|
|
|
for (auto &error : errors)
|
|
|
|
|
s->Printf("%s\n", error.AsCString());
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
if (feedback_stream.GetSize())
|
2025-02-12 08:29:06 -08:00
|
|
|
s->PutCString(feedback_stream.GetString());
|
2013-05-20 22:29:23 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-09-01 00:38:36 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-09-01 00:38:36 +00:00
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
bool Debugger::GetAutoConfirm() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyAutoConfirm;
|
|
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetDisassemblyFormat() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyDisassemblyFormat;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
2014-10-10 23:07:36 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetFrameFormat() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyFrameFormat;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
2017-06-12 16:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetFrameFormatUnique() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyFrameFormatUnique;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
2012-08-09 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 09:26:58 -07:00
|
|
|
uint64_t Debugger::GetStopDisassemblyMaxSize() const {
|
|
|
|
|
constexpr uint32_t idx = ePropertyStopDisassemblyMaxSize;
|
|
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
2021-02-25 21:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
bool Debugger::GetNotifyVoid() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyNotiftVoid;
|
|
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-23 18:06:53 +00:00
|
|
|
llvm::StringRef Debugger::GetPrompt() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyPrompt;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-13 20:58:12 -07:00
|
|
|
llvm::StringRef Debugger::GetPromptAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyPromptAnsiPrefix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetPromptAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyPromptAnsiSuffix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-23 18:06:53 +00:00
|
|
|
void Debugger::SetPrompt(llvm::StringRef p) {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyPrompt;
|
|
|
|
|
SetPropertyAtIndex(idx, p);
|
2016-09-23 18:06:53 +00:00
|
|
|
llvm::StringRef new_prompt = GetPrompt();
|
2013-05-23 20:47:45 +00:00
|
|
|
std::string str =
|
2019-08-21 00:50:46 +00:00
|
|
|
lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor());
|
2013-05-23 20:47:45 +00:00
|
|
|
if (str.length())
|
2016-11-02 20:34:10 +00:00
|
|
|
new_prompt = str;
|
2014-01-27 23:43:24 +00:00
|
|
|
GetCommandInterpreter().UpdatePrompt(new_prompt);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetThreadFormat() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyThreadFormat;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetThreadStopFormat() const {
|
2023-05-04 09:26:58 -07:00
|
|
|
constexpr uint32_t idx = ePropertyThreadStopFormat;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
2016-11-08 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
lldb::ScriptLanguage Debugger::GetScriptLanguage() const {
|
|
|
|
|
const uint32_t idx = ePropertyScriptLanguage;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<lldb::ScriptLanguage>(
|
|
|
|
|
idx, static_cast<lldb::ScriptLanguage>(
|
|
|
|
|
g_debugger_properties[idx].default_uint_value));
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) {
|
|
|
|
|
const uint32_t idx = ePropertyScriptLanguage;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, script_lang);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-05 14:42:21 -08:00
|
|
|
lldb::LanguageType Debugger::GetREPLLanguage() const {
|
|
|
|
|
const uint32_t idx = ePropertyREPLLanguage;
|
2023-05-04 23:15:28 -07:00
|
|
|
return GetPropertyAtIndexAs<LanguageType>(idx, {});
|
2022-01-05 14:42:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) {
|
|
|
|
|
const uint32_t idx = ePropertyREPLLanguage;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, repl_lang);
|
2022-01-05 14:42:21 -08:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 09:26:58 -07:00
|
|
|
uint64_t Debugger::GetTerminalWidth() const {
|
2012-08-22 17:17:09 +00:00
|
|
|
const uint32_t idx = ePropertyTerminalWidth;
|
2024-02-22 23:53:12 -08:00
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
2023-05-04 09:26:58 -07:00
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-14 19:58:16 -07:00
|
|
|
bool Debugger::SetTerminalWidth(uint64_t term_width) {
|
2024-12-16 11:11:17 -08:00
|
|
|
const uint32_t idx = ePropertyTerminalWidth;
|
|
|
|
|
const bool success = SetPropertyAtIndex(idx, term_width);
|
|
|
|
|
|
2020-05-08 15:14:14 -07:00
|
|
|
if (auto handler_sp = m_io_handler_stack.Top())
|
|
|
|
|
handler_sp->TerminalSizeChanged();
|
2025-04-11 08:53:49 -07:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
|
|
|
|
if (m_statusline)
|
|
|
|
|
m_statusline->TerminalSizeChanged();
|
|
|
|
|
}
|
2020-05-08 15:14:14 -07:00
|
|
|
|
2024-12-16 11:11:17 -08:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t Debugger::GetTerminalHeight() const {
|
|
|
|
|
const uint32_t idx = ePropertyTerminalHeight;
|
|
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetTerminalHeight(uint64_t term_height) {
|
|
|
|
|
const uint32_t idx = ePropertyTerminalHeight;
|
|
|
|
|
const bool success = SetPropertyAtIndex(idx, term_height);
|
|
|
|
|
|
|
|
|
|
if (auto handler_sp = m_io_handler_stack.Top())
|
|
|
|
|
handler_sp->TerminalSizeChanged();
|
2025-04-11 08:53:49 -07:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
|
|
|
|
if (m_statusline)
|
|
|
|
|
m_statusline->TerminalSizeChanged();
|
|
|
|
|
}
|
2024-12-16 11:11:17 -08:00
|
|
|
|
|
|
|
|
return success;
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
bool Debugger::GetUseExternalEditor() const {
|
|
|
|
|
const uint32_t idx = ePropertyUseExternalEditor;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
bool Debugger::SetUseExternalEditor(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyUseExternalEditor;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, b);
|
2011-11-21 21:44:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-01 14:08:43 -07:00
|
|
|
llvm::StringRef Debugger::GetExternalEditor() const {
|
|
|
|
|
const uint32_t idx = ePropertyExternalEditor;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2023-05-01 14:08:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetExternalEditor(llvm::StringRef editor) {
|
|
|
|
|
const uint32_t idx = ePropertyExternalEditor;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, editor);
|
2023-05-01 14:08:43 -07:00
|
|
|
}
|
|
|
|
|
|
2013-05-23 20:47:45 +00:00
|
|
|
bool Debugger::GetUseColor() const {
|
|
|
|
|
const uint32_t idx = ePropertyUseColor;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2013-05-23 20:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetUseColor(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyUseColor;
|
2023-05-04 09:26:58 -07:00
|
|
|
bool ret = SetPropertyAtIndex(idx, b);
|
2025-04-22 12:21:23 +01:00
|
|
|
|
|
|
|
|
GetCommandInterpreter().UpdateUseColor(b);
|
2013-05-23 20:47:45 +00:00
|
|
|
SetPrompt(GetPrompt());
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 15:45:52 -08:00
|
|
|
bool Debugger::GetShowProgress() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowProgress;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2022-03-05 15:45:52 -08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 10:42:59 -07:00
|
|
|
bool Debugger::SetShowProgress(bool show_progress) {
|
|
|
|
|
const uint32_t idx = ePropertyShowProgress;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, show_progress);
|
2022-04-11 10:42:59 -07:00
|
|
|
}
|
|
|
|
|
|
2022-03-05 17:52:01 -08:00
|
|
|
llvm::StringRef Debugger::GetShowProgressAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowProgressAnsiPrefix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2022-03-05 17:52:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetShowProgressAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowProgressAnsiSuffix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2022-03-05 17:52:01 -08:00
|
|
|
}
|
|
|
|
|
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
bool Debugger::GetShowStatusline() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowStatusline;
|
|
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-03 19:12:30 -07:00
|
|
|
FormatEntity::Entry Debugger::GetStatuslineFormat() const {
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
constexpr uint32_t idx = ePropertyStatuslineFormat;
|
2025-06-03 19:12:30 -07:00
|
|
|
return GetPropertyAtIndexAs<FormatEntity::Entry>(idx, {});
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
}
|
|
|
|
|
|
2025-04-10 15:36:28 -07:00
|
|
|
bool Debugger::SetStatuslineFormat(const FormatEntity::Entry &format) {
|
|
|
|
|
constexpr uint32_t idx = ePropertyStatuslineFormat;
|
2025-04-10 16:55:56 -07:00
|
|
|
bool ret = SetPropertyAtIndex(idx, format);
|
2025-09-23 14:18:11 -07:00
|
|
|
RedrawStatusline(std::nullopt);
|
2025-04-10 16:55:56 -07:00
|
|
|
return ret;
|
2025-04-10 15:36:28 -07:00
|
|
|
}
|
|
|
|
|
|
2025-04-22 12:59:46 -07:00
|
|
|
llvm::StringRef Debugger::GetSeparator() const {
|
|
|
|
|
constexpr uint32_t idx = ePropertySeparator;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 13:06:20 -07:00
|
|
|
llvm::StringRef Debugger::GetDisabledAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowDisabledAnsiPrefix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetDisabledAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowDisabledAnsiSuffix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-22 12:59:46 -07:00
|
|
|
bool Debugger::SetSeparator(llvm::StringRef s) {
|
|
|
|
|
constexpr uint32_t idx = ePropertySeparator;
|
|
|
|
|
bool ret = SetPropertyAtIndex(idx, s);
|
2025-09-23 14:18:11 -07:00
|
|
|
RedrawStatusline(std::nullopt);
|
2025-04-22 12:59:46 -07:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
[lldb] Display autosuggestion part in gray if there is one possible suggestion
This is relanding D81001. The patch originally failed as on newer editline
versions it seems CC_REFRESH will move the cursor to the start of the line via
\r and then back to the original position. On older editline versions like
the one used by default on macOS, CC_REFRESH doesn't move the cursor at all.
As the patch changed the way we handle tab completion (previously we did
REDISPLAY but now we're doing CC_REFRESH), this caused a few completion tests
to receive this unexpected cursor movement in the output stream.
This patch updates those tests to also accept output that contains the specific
cursor movement commands (\r and then \x1b[XC). lldbpexpect.py received an
utility method for generating the cursor movement escape sequence.
Original summary:
I implemented autosuggestion if there is one possible suggestion.
I set the keybinds for every character. When a character is typed, Editline::TypedCharacter is called.
Then, autosuggestion part is displayed in gray, and you can actually input by typing C-k.
Editline::Autosuggest is a function for finding completion, and it is like Editline::TabCommand now, but I will add more features to it.
Testing does not work well in my environment, so I can't confirm that it goes well, sorry. I am dealing with it now.
Reviewed By: teemperor, JDevlieghere, #lldb
Differential Revision: https://reviews.llvm.org/D81001
2020-08-12 12:54:28 +02:00
|
|
|
bool Debugger::GetUseAutosuggestion() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowAutosuggestion;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
[lldb] Display autosuggestion part in gray if there is one possible suggestion
This is relanding D81001. The patch originally failed as on newer editline
versions it seems CC_REFRESH will move the cursor to the start of the line via
\r and then back to the original position. On older editline versions like
the one used by default on macOS, CC_REFRESH doesn't move the cursor at all.
As the patch changed the way we handle tab completion (previously we did
REDISPLAY but now we're doing CC_REFRESH), this caused a few completion tests
to receive this unexpected cursor movement in the output stream.
This patch updates those tests to also accept output that contains the specific
cursor movement commands (\r and then \x1b[XC). lldbpexpect.py received an
utility method for generating the cursor movement escape sequence.
Original summary:
I implemented autosuggestion if there is one possible suggestion.
I set the keybinds for every character. When a character is typed, Editline::TypedCharacter is called.
Then, autosuggestion part is displayed in gray, and you can actually input by typing C-k.
Editline::Autosuggest is a function for finding completion, and it is like Editline::TabCommand now, but I will add more features to it.
Testing does not work well in my environment, so I can't confirm that it goes well, sorry. I am dealing with it now.
Reviewed By: teemperor, JDevlieghere, #lldb
Differential Revision: https://reviews.llvm.org/D81001
2020-08-12 12:54:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-07 08:37:42 -08:00
|
|
|
llvm::StringRef Debugger::GetAutosuggestionAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowAutosuggestionAnsiPrefix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2022-03-07 08:37:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowAutosuggestionAnsiSuffix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2022-03-07 08:37:42 -08:00
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:09:04 +05:00
|
|
|
llvm::StringRef Debugger::GetRegexMatchAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowRegexMatchAnsiPrefix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetRegexMatchAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowRegexMatchAnsiSuffix;
|
|
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 16:34:26 -07:00
|
|
|
bool Debugger::GetShowDontUsePoHint() const {
|
2023-09-13 09:14:50 -07:00
|
|
|
const uint32_t idx = ePropertyShowDontUsePoHint;
|
2023-06-28 16:34:26 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 16:17:17 +02:00
|
|
|
bool Debugger::GetUseSourceCache() const {
|
|
|
|
|
const uint32_t idx = ePropertyUseSourceCache;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2020-04-20 16:17:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetUseSourceCache(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyUseSourceCache;
|
2023-05-04 09:26:58 -07:00
|
|
|
bool ret = SetPropertyAtIndex(idx, b);
|
2020-04-20 16:17:17 +02:00
|
|
|
if (!ret) {
|
|
|
|
|
m_source_file_cache.Clear();
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2018-08-02 00:30:15 +00:00
|
|
|
bool Debugger::GetHighlightSource() const {
|
|
|
|
|
const uint32_t idx = ePropertyHighlightSource;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2018-08-02 00:30:15 +00:00
|
|
|
}
|
|
|
|
|
|
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-21 20:13:14 +00:00
|
|
|
StopShowColumn Debugger::GetStopShowColumn() const {
|
|
|
|
|
const uint32_t idx = ePropertyStopShowColumn;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<lldb::StopShowColumn>(
|
|
|
|
|
idx, static_cast<lldb::StopShowColumn>(
|
|
|
|
|
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-21 20:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 00:09:21 +00: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-21 20:13:14 +00:00
|
|
|
const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_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-21 20:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 00:09:21 +00: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-21 20:13:14 +00:00
|
|
|
const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_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-21 20:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
2020-02-24 15:34:58 -08:00
|
|
|
llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const {
|
|
|
|
|
const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2020-02-24 15:34:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const {
|
|
|
|
|
const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<llvm::StringRef>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_cstr_value);
|
2020-02-24 15:34:58 -08:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 09:26:58 -07:00
|
|
|
uint64_t Debugger::GetStopSourceLineCount(bool before) const {
|
2012-08-22 17:17:09 +00:00
|
|
|
const uint32_t idx =
|
|
|
|
|
before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
2012-08-22 17:17:09 +00:00
|
|
|
}
|
2011-11-21 21:44:34 +00:00
|
|
|
|
2025-04-25 23:35:20 +02:00
|
|
|
lldb::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const {
|
2012-08-22 17:17:09 +00:00
|
|
|
const uint32_t idx = ePropertyStopDisassemblyDisplay;
|
2025-04-25 23:35:20 +02:00
|
|
|
return GetPropertyAtIndexAs<lldb::StopDisassemblyType>(
|
|
|
|
|
idx, static_cast<lldb::StopDisassemblyType>(
|
2023-05-04 09:26:58 -07:00
|
|
|
g_debugger_properties[idx].default_uint_value));
|
2012-08-22 17:17:09 +00:00
|
|
|
}
|
2011-11-21 21:44:34 +00:00
|
|
|
|
2023-05-04 09:26:58 -07:00
|
|
|
uint64_t Debugger::GetDisassemblyLineCount() const {
|
2012-08-22 17:17:09 +00:00
|
|
|
const uint32_t idx = ePropertyStopDisassemblyCount;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
2012-08-22 17:17:09 +00:00
|
|
|
}
|
2011-11-21 21:44:34 +00:00
|
|
|
|
2013-10-31 21:01:07 +00:00
|
|
|
bool Debugger::GetAutoOneLineSummaries() const {
|
|
|
|
|
const uint32_t idx = ePropertyAutoOneLineSummaries;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2014-11-05 21:20:48 +00:00
|
|
|
}
|
2013-10-25 23:09:40 +00:00
|
|
|
|
2014-11-05 21:20:48 +00:00
|
|
|
bool Debugger::GetEscapeNonPrintables() const {
|
|
|
|
|
const uint32_t idx = ePropertyEscapeNonPrintables;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2013-10-25 23:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
bool Debugger::GetAutoIndent() const {
|
|
|
|
|
const uint32_t idx = ePropertyAutoIndent;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetAutoIndent(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyAutoIndent;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, b);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::GetPrintDecls() const {
|
|
|
|
|
const uint32_t idx = ePropertyPrintDecls;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value != 0);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetPrintDecls(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyPrintDecls;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, b);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 09:26:58 -07:00
|
|
|
uint64_t Debugger::GetTabSize() const {
|
2015-10-19 23:11:07 +00:00
|
|
|
const uint32_t idx = ePropertyTabSize;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<uint64_t>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-14 19:58:16 -07:00
|
|
|
bool Debugger::SetTabSize(uint64_t tab_size) {
|
2015-10-19 23:11:07 +00:00
|
|
|
const uint32_t idx = ePropertyTabSize;
|
2023-05-04 09:26:58 -07:00
|
|
|
return SetPropertyAtIndex(idx, tab_size);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
[lldb] Introduce dwim-print command
Implements `dwim-print`, a printing command that chooses the most direct,
efficient, and resilient means of printing a given expression.
DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
> attempt to anticipate what users intend to do, correcting trivial errors
> automatically rather than blindly executing users' explicit but
> potentially incorrect input
The `dwim-print` command serves as a single print command for users who don't
yet know, or prefer not to know, the various lldb commands that can be used to
print, and when to use them.
This initial implementation is the base foundation for `dwim-print`. It accepts
no flags, only an expression. If the expression is the name of a variable in
the frame, then effectively `frame variable` is used to get, and print, its
value. Otherwise, printing falls back to using `expression` evaluation. In this
initial version, frame variable paths will be handled with `expression`.
Following this, there are a number of improvements that can be made. Some
improvements include supporting `frame variable` expressions or registers.
To provide transparency, especially as the `dwim-print` command evolves, a new
setting is also introduced: `dwim-print-verbosity`. This setting instructs
`dwim-print` to optionally print a message showing the effective command being
run. For example `dwim-print var.meth()` can print a message such as: "note:
ran `expression var.meth()`".
See https://discourse.llvm.org/t/dwim-print-command/66078 for the proposal and
discussion.
Differential Revision: https://reviews.llvm.org/D138315
2022-11-17 17:11:30 -08:00
|
|
|
lldb::DWIMPrintVerbosity Debugger::GetDWIMPrintVerbosity() const {
|
|
|
|
|
const uint32_t idx = ePropertyDWIMPrintVerbosity;
|
2023-05-04 09:26:58 -07:00
|
|
|
return GetPropertyAtIndexAs<lldb::DWIMPrintVerbosity>(
|
|
|
|
|
idx, static_cast<lldb::DWIMPrintVerbosity>(
|
2024-09-27 16:32:35 -07:00
|
|
|
g_debugger_properties[idx].default_uint_value != 0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::GetShowInlineDiagnostics() const {
|
|
|
|
|
const uint32_t idx = ePropertyShowInlineDiagnostics;
|
|
|
|
|
return GetPropertyAtIndexAs<bool>(
|
|
|
|
|
idx, g_debugger_properties[idx].default_uint_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::SetShowInlineDiagnostics(bool b) {
|
|
|
|
|
const uint32_t idx = ePropertyShowInlineDiagnostics;
|
|
|
|
|
return SetPropertyAtIndex(idx, b);
|
[lldb] Introduce dwim-print command
Implements `dwim-print`, a printing command that chooses the most direct,
efficient, and resilient means of printing a given expression.
DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
> attempt to anticipate what users intend to do, correcting trivial errors
> automatically rather than blindly executing users' explicit but
> potentially incorrect input
The `dwim-print` command serves as a single print command for users who don't
yet know, or prefer not to know, the various lldb commands that can be used to
print, and when to use them.
This initial implementation is the base foundation for `dwim-print`. It accepts
no flags, only an expression. If the expression is the name of a variable in
the frame, then effectively `frame variable` is used to get, and print, its
value. Otherwise, printing falls back to using `expression` evaluation. In this
initial version, frame variable paths will be handled with `expression`.
Following this, there are a number of improvements that can be made. Some
improvements include supporting `frame variable` expressions or registers.
To provide transparency, especially as the `dwim-print` command evolves, a new
setting is also introduced: `dwim-print-verbosity`. This setting instructs
`dwim-print` to optionally print a message showing the effective command being
run. For example `dwim-print var.meth()` can print a message such as: "note:
ran `expression var.meth()`".
See https://discourse.llvm.org/t/dwim-print-command/66078 for the proposal and
discussion.
Differential Revision: https://reviews.llvm.org/D138315
2022-11-17 17:11:30 -08:00
|
|
|
}
|
|
|
|
|
|
2010-09-19 02:33:57 +00:00
|
|
|
#pragma mark Debugger
|
|
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
// const DebuggerPropertiesSP &
|
|
|
|
|
// Debugger::GetSettings() const
|
|
|
|
|
//{
|
|
|
|
|
// return m_properties_sp;
|
|
|
|
|
//}
|
|
|
|
|
//
|
2010-11-18 23:32:35 +00:00
|
|
|
|
2015-03-19 22:00:21 +00:00
|
|
|
void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {
|
2016-05-26 16:51:23 +00:00
|
|
|
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();
|
2024-03-05 18:00:46 -08:00
|
|
|
g_thread_pool = new llvm::DefaultThreadPool(llvm::optimal_concurrency());
|
2013-12-02 19:35:49 +00:00
|
|
|
g_load_plugin_callback = load_plugin_callback;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::Terminate() {
|
2016-05-26 16:51:23 +00:00
|
|
|
assert(g_debugger_list_ptr &&
|
|
|
|
|
"Debugger::Terminate called without a matching Debugger::Initialize!");
|
2015-03-31 21:03:22 +00:00
|
|
|
|
2023-02-03 17:09:09 -08:00
|
|
|
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
|
|
|
|
for (const auto &debugger : *g_debugger_list_ptr)
|
|
|
|
|
debugger->HandleDestroyCallback();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-15 17:22:14 -07:00
|
|
|
if (g_thread_pool) {
|
|
|
|
|
// The destructor will wait for all the threads to complete.
|
|
|
|
|
delete g_thread_pool;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
2021-11-17 16:23:19 -06:00
|
|
|
// Clear our global list of debugger objects
|
2016-05-26 16:51:23 +00:00
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-10 22:14:10 +00:00
|
|
|
void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }
|
|
|
|
|
|
|
|
|
|
void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {
|
2013-12-02 19:35:49 +00:00
|
|
|
if (g_load_plugin_callback) {
|
2014-08-27 20:15:09 +00:00
|
|
|
llvm::sys::DynamicLibrary dynlib =
|
|
|
|
|
g_load_plugin_callback(shared_from_this(), spec, error);
|
|
|
|
|
if (dynlib.isValid()) {
|
|
|
|
|
m_loaded_plugins.push_back(dynlib);
|
2013-12-02 19:35:49 +00:00
|
|
|
return true;
|
2012-09-28 23:57:51 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2024-08-27 10:59:31 -07:00
|
|
|
error = Status::FromErrorString("Public API layer is not available");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-09-28 23:57:51 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 00:33:27 +00:00
|
|
|
static FileSystem::EnumerateDirectoryResult
|
2017-03-08 17:56:08 +00:00
|
|
|
LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
|
2018-11-01 00:33:27 +00:00
|
|
|
llvm::StringRef path) {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2023-04-26 15:01:12 -07:00
|
|
|
static constexpr llvm::StringLiteral g_dylibext(".dylib");
|
|
|
|
|
static constexpr llvm::StringLiteral g_solibext(".so");
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-09-28 23:57:51 +00:00
|
|
|
if (!baton)
|
2018-11-01 00:33:27 +00:00
|
|
|
return FileSystem::eEnumerateDirectoryResultQuit;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-09-28 23:57:51 +00:00
|
|
|
Debugger *debugger = (Debugger *)baton;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-03-08 17:56:08 +00:00
|
|
|
namespace fs = llvm::sys::fs;
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2012-09-28 23:57:51 +00:00
|
|
|
// enumeration might be enumerating a file system that doesn't have correct
|
|
|
|
|
// file type information.
|
2017-03-08 17:56:08 +00:00
|
|
|
if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
|
|
|
|
|
ft == fs::file_type::type_unknown) {
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec plugin_file_spec(path);
|
|
|
|
|
FileSystem::Instance().Resolve(plugin_file_spec);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-06-27 02:42:12 +00:00
|
|
|
if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
|
2012-09-28 23:57:51 +00:00
|
|
|
plugin_file_spec.GetFileNameExtension() != g_solibext) {
|
2018-11-01 00:33:27 +00:00
|
|
|
return FileSystem::eEnumerateDirectoryResultNext;
|
2012-09-28 23:57:51 +00:00
|
|
|
}
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status plugin_load_error;
|
2012-09-28 23:57:51 +00:00
|
|
|
debugger->LoadPlugin(plugin_file_spec, plugin_load_error);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-11-01 00:33:27 +00:00
|
|
|
return FileSystem::eEnumerateDirectoryResultNext;
|
2017-03-08 17:56:08 +00:00
|
|
|
} else if (ft == fs::file_type::directory_file ||
|
|
|
|
|
ft == fs::file_type::symlink_file ||
|
|
|
|
|
ft == fs::file_type::type_unknown) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2012-09-28 23:57:51 +00:00
|
|
|
// information.
|
2018-11-01 00:33:27 +00:00
|
|
|
return FileSystem::eEnumerateDirectoryResultEnter;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 00:33:27 +00:00
|
|
|
return FileSystem::eEnumerateDirectoryResultNext;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2012-09-28 23:57:51 +00:00
|
|
|
void Debugger::InstanceInitialize() {
|
|
|
|
|
const bool find_directories = true;
|
|
|
|
|
const bool find_files = true;
|
|
|
|
|
const bool find_other = true;
|
|
|
|
|
char dir_path[PATH_MAX];
|
2018-06-19 15:09:07 +00:00
|
|
|
if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) {
|
2018-11-01 17:09:25 +00:00
|
|
|
if (FileSystem::Instance().Exists(dir_spec) &&
|
|
|
|
|
dir_spec.GetPath(dir_path, sizeof(dir_path))) {
|
2018-11-01 00:33:27 +00:00
|
|
|
FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
|
|
|
|
|
find_files, find_other,
|
|
|
|
|
LoadPluginCallback, this);
|
2012-09-28 23:57:51 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-08-21 17:29:12 +00:00
|
|
|
|
2018-06-19 15:09:07 +00:00
|
|
|
if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) {
|
2018-11-01 17:09:25 +00:00
|
|
|
if (FileSystem::Instance().Exists(dir_spec) &&
|
|
|
|
|
dir_spec.GetPath(dir_path, sizeof(dir_path))) {
|
2018-11-01 00:33:27 +00:00
|
|
|
FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
|
|
|
|
|
find_files, find_other,
|
|
|
|
|
LoadPluginCallback, this);
|
2012-09-28 23:57:51 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2012-10-19 18:02:49 +00:00
|
|
|
PluginManager::DebuggerInitialize(*this);
|
2012-09-28 23:57:51 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-21 02:23:08 +00:00
|
|
|
DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,
|
|
|
|
|
void *baton) {
|
2025-03-03 10:07:54 -05:00
|
|
|
lldb_private::telemetry::ScopedDispatcher<
|
|
|
|
|
lldb_private::telemetry::DebuggerInfo>
|
|
|
|
|
helper([](lldb_private::telemetry::DebuggerInfo *entry) {
|
|
|
|
|
entry->lldb_version = lldb_private::GetVersion();
|
|
|
|
|
});
|
2012-02-21 02:23:08 +00:00
|
|
|
DebuggerSP debugger_sp(new Debugger(log_callback, baton));
|
2025-03-03 10:07:54 -05:00
|
|
|
helper.SetDebugger(debugger_sp.get());
|
|
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
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);
|
2010-06-23 01:19:29 +00:00
|
|
|
}
|
2012-09-28 23:57:51 +00:00
|
|
|
debugger_sp->InstanceInitialize();
|
2010-06-23 01:19:29 +00:00
|
|
|
return debugger_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-25 20:19:29 -04:00
|
|
|
void Debugger::DispatchClientTelemetry(
|
|
|
|
|
const lldb_private::StructuredDataImpl &entry) {
|
|
|
|
|
lldb_private::telemetry::TelemetryManager::GetInstance()
|
|
|
|
|
->DispatchClientTelemetry(entry, this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-03 17:09:09 -08:00
|
|
|
void Debugger::HandleDestroyCallback() {
|
SBDebugger: Add new APIs `AddDestroyCallback` and `RemoveDestroyCallback` (#89868)
# Motivation
Individual callers of `SBDebugger::SetDestroyCallback()` might think
that they have registered their callback and expect it to be called when
the debugger is destroyed. In reality, only the last caller survives,
and all previous callers are forgotten, which might be a surprise to
them. Worse, if this is called in a race condition, which callback
survives is less predictable, which may case confusing behavior
elsewhere.
# This PR
Allows multiple destroy callbacks to be registered and all called when
the debugger is destroyed.
**EDIT**: Adds two new APIs: `AddDestroyCallback()` and
`ClearDestroyCallback()`. `SetDestroyCallback()` will first clear then
add the given callback. Tests are added for the new APIs.
## Tests
```
bin/llvm-lit -sv ../external/llvm-project/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
```
## (out-dated, see comments below) Semantic change to
`SetDestroyCallback()`
~~Currently, the method overwrites the old callback with the new one.
With this PR, it will NOT overwrite. Instead, it will hold on to both.
Both callbacks get called during destroy.~~
~~**Risk**: Although the documentation of `SetDestroyCallback()` (see
[C++](https://lldb.llvm.org/cpp_reference/classlldb_1_1SBDebugger.html#afa1649d9453a376b5c95888b5a0cb4ec)
and
[python](https://lldb.llvm.org/python_api/lldb.SBDebugger.html#lldb.SBDebugger.SetDestroyCallback))
doesn't really specify the behavior, there is a risk: if existing call
sites rely on the "overwrite" behavior, they will be surprised because
now the old callback will get called. But as the above said, the current
behavior of "overwrite" itself might be unintended, so I don't
anticipate users to rely on this behavior. In short, this risk might be
less of a problem if we correct it sooner rather than later (which is
what this PR is trying to do).~~
## (out-dated, see comments below) Implementation
~~The implementation holds a `std::vector<std::pair<callback, baton>>`.
When `SetDestroyCallback()` is called, callbacks and batons are appended
to the `std::vector`. When destroy event happen, the `(callback, baton)`
pairs are invoked FIFO. Finally, the `std::vector` is cleared.~~
# (out-dated, see comments below) Alternatives considered
~~Instead of changing `SetDestroyCallback()`, a new method
`AddDestroyCallback()` can be added, which use the same
`std::vector<std::pair<>>` implementation. Together with
`ClearDestroyCallback()` (see below), they will replace and deprecate
`SetDestroyCallback()`. Meanwhile, in order to be backward compatible,
`SetDestroyCallback()` need to be updated to clear the `std::vector` and
then add the new callback. Pros: The end state is semantically more
correct. Cons: More steps to take; potentially maintaining an
"incorrect" behavior (of "overwrite").~~
~~A new method `ClearDestroyCallback()` can be added. Might be
unnecessary at this point, because workflows which need to set then
clear callbacks may exist but shouldn't be too common at least for now.
Such method can be added later when needed.~~
~~The `std::vector` may bring slight performance drawback if its
implementation doesn't handle small size efficiently. However, even if
that's the case, this path should be very cold (only used during init
and destroy). Such performance drawback should be negligible.~~
~~A different implementation was also considered. Instead of using
`std::vector`, the current `m_destroy_callback` field can be kept
unchanged. When `SetDestroyCallback()` is called, a lambda function can
be stored into `m_destroy_callback`. This lambda function will first
call the old callback, then the new one. This way, `std::vector` is
avoided. However, this implementation is more complex, thus less
readable, with not much perf to gain.~~
---------
Co-authored-by: Roy Shi <royshi@meta.com>
2024-05-20 15:51:42 -07:00
|
|
|
const lldb::user_id_t user_id = GetID();
|
|
|
|
|
// Invoke and remove all the callbacks in an FIFO order. Callbacks which are
|
|
|
|
|
// added during this loop will be appended, invoked and then removed last.
|
|
|
|
|
// Callbacks which are removed during this loop will not be invoked.
|
|
|
|
|
while (true) {
|
|
|
|
|
DestroyCallbackInfo callback_info;
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
|
|
|
|
|
if (m_destroy_callbacks.empty())
|
|
|
|
|
break;
|
|
|
|
|
// Pop the first item in the list
|
|
|
|
|
callback_info = m_destroy_callbacks.front();
|
|
|
|
|
m_destroy_callbacks.erase(m_destroy_callbacks.begin());
|
|
|
|
|
}
|
|
|
|
|
// Call the destroy callback with user id and baton
|
|
|
|
|
callback_info.callback(user_id, callback_info.baton);
|
2023-02-03 17:09:09 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-17 08:33:22 +00:00
|
|
|
void Debugger::Destroy(DebuggerSP &debugger_sp) {
|
2016-03-02 02:18:18 +00:00
|
|
|
if (!debugger_sp)
|
2011-01-22 01:02:07 +00:00
|
|
|
return;
|
2011-09-15 21:36:42 +00:00
|
|
|
|
2023-02-03 17:09:09 -08:00
|
|
|
debugger_sp->HandleDestroyCallback();
|
2021-06-28 19:27:55 +00:00
|
|
|
CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();
|
|
|
|
|
|
|
|
|
|
if (cmd_interpreter.GetSaveSessionOnQuit()) {
|
|
|
|
|
CommandReturnObject result(debugger_sp->GetUseColor());
|
|
|
|
|
cmd_interpreter.SaveTranscript(result);
|
|
|
|
|
if (result.Succeeded())
|
2024-10-12 13:36:33 -07:00
|
|
|
(*debugger_sp->GetAsyncOutputStream())
|
|
|
|
|
<< result.GetOutputString() << '\n';
|
2021-06-28 19:27:55 +00:00
|
|
|
else
|
2024-10-12 13:36:33 -07:00
|
|
|
(*debugger_sp->GetAsyncErrorStream()) << result.GetErrorString() << '\n';
|
2021-06-28 19:27:55 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-15 21:36:42 +00:00
|
|
|
debugger_sp->Clear();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
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) {
|
2012-03-30 20:53:46 +00:00
|
|
|
if ((*pos).get() == debugger_sp.get()) {
|
2016-05-26 16:51:23 +00:00
|
|
|
g_debugger_list_ptr->erase(pos);
|
2012-03-30 20:53:46 +00:00
|
|
|
return;
|
2011-01-22 01:02:07 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2011-01-22 01:02:07 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-25 18:19:46 -07:00
|
|
|
DebuggerSP
|
|
|
|
|
Debugger::FindDebuggerWithInstanceName(llvm::StringRef instance_name) {
|
|
|
|
|
if (!g_debugger_list_ptr || !g_debugger_list_mutex_ptr)
|
|
|
|
|
return DebuggerSP();
|
|
|
|
|
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
|
|
|
|
for (const DebuggerSP &debugger_sp : *g_debugger_list_ptr) {
|
|
|
|
|
if (!debugger_sp)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (llvm::StringRef(debugger_sp->GetInstanceName()) == instance_name)
|
|
|
|
|
return debugger_sp;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2023-05-25 18:19:46 -07:00
|
|
|
return DebuggerSP();
|
2010-09-04 00:03:46 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-23 01:19:29 +00:00
|
|
|
TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) {
|
2011-09-17 08:33:22 +00:00
|
|
|
TargetSP target_sp;
|
2016-05-26 16:51:23 +00:00
|
|
|
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) {
|
2012-03-30 20:53:46 +00:00
|
|
|
target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid);
|
|
|
|
|
if (target_sp)
|
|
|
|
|
break;
|
2010-06-23 01:19:29 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-23 01:19:29 +00:00
|
|
|
return target_sp;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2011-11-16 05:37:56 +00:00
|
|
|
TargetSP Debugger::FindTargetWithProcess(Process *process) {
|
|
|
|
|
TargetSP target_sp;
|
2016-05-26 16:51:23 +00:00
|
|
|
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) {
|
2012-03-30 20:53:46 +00:00
|
|
|
target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process);
|
|
|
|
|
if (target_sp)
|
|
|
|
|
break;
|
2011-11-16 05:37:56 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2011-11-16 05:37:56 +00:00
|
|
|
return target_sp;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2024-04-24 12:13:18 -07:00
|
|
|
llvm::StringRef Debugger::GetStaticBroadcasterClass() {
|
|
|
|
|
static constexpr llvm::StringLiteral class_name("lldb.debugger");
|
2021-03-01 15:26:35 -08:00
|
|
|
return class_name;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-12 01:50:46 +00:00
|
|
|
Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
|
|
|
|
|
: UserID(g_unique_id++),
|
2017-04-06 21:28:29 +00:00
|
|
|
Properties(std::make_shared<OptionValueProperties>()),
|
2025-11-17 10:51:13 -08:00
|
|
|
m_input_file_sp(std::make_shared<NativeFile>(
|
|
|
|
|
stdin, File::eOpenOptionReadOnly, NativeFile::Unowned)),
|
2025-02-19 20:32:00 -08:00
|
|
|
m_output_stream_sp(std::make_shared<LockableStreamFile>(
|
|
|
|
|
stdout, NativeFile::Unowned, m_output_mutex)),
|
|
|
|
|
m_error_stream_sp(std::make_shared<LockableStreamFile>(
|
|
|
|
|
stderr, NativeFile::Unowned, m_output_mutex)),
|
2016-03-07 21:50:25 +00:00
|
|
|
m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
|
2023-01-13 08:51:03 -08:00
|
|
|
m_terminal_state(), m_target_list(*this), m_platform_list(),
|
2016-03-07 21:50:25 +00:00
|
|
|
m_listener_sp(Listener::MakeListener("lldb.Debugger")),
|
2019-02-13 06:25:41 +00:00
|
|
|
m_source_manager_up(), m_source_file_cache(),
|
2019-04-26 20:03:22 +00:00
|
|
|
m_command_interpreter_up(
|
2019-08-14 22:19:23 +00:00
|
|
|
std::make_unique<CommandInterpreter>(*this, false)),
|
2023-05-25 18:19:46 -07:00
|
|
|
m_io_handler_stack(),
|
|
|
|
|
m_instance_name(llvm::formatv("debugger_{0}", GetID()).str()),
|
|
|
|
|
m_loaded_plugins(), m_event_handler_thread(), m_io_handler_thread(),
|
2016-03-02 02:18:18 +00:00
|
|
|
m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
|
2021-03-01 15:26:35 -08:00
|
|
|
m_broadcaster(m_broadcaster_manager_sp,
|
2024-04-24 12:13:18 -07:00
|
|
|
GetStaticBroadcasterClass().str()),
|
2016-03-02 02:18:18 +00:00
|
|
|
m_forward_listener_sp(), m_clear_once() {
|
2023-05-02 12:47:38 -07:00
|
|
|
// Initialize the debugger properties as early as possible as other parts of
|
|
|
|
|
// LLDB will start querying them during construction.
|
|
|
|
|
m_collection_sp->Initialize(g_debugger_properties);
|
2023-05-04 09:26:58 -07:00
|
|
|
m_collection_sp->AppendProperty(
|
2023-06-23 17:27:09 -07:00
|
|
|
"target", "Settings specify to debugging targets.", true,
|
2023-05-04 09:26:58 -07:00
|
|
|
Target::GetGlobalProperties().GetValueProperties());
|
|
|
|
|
m_collection_sp->AppendProperty(
|
2023-06-23 17:27:09 -07:00
|
|
|
"platform", "Platform settings.", true,
|
2023-05-04 09:26:58 -07:00
|
|
|
Platform::GetGlobalPlatformProperties().GetValueProperties());
|
|
|
|
|
m_collection_sp->AppendProperty(
|
2023-06-23 17:27:09 -07:00
|
|
|
"symbols", "Symbol lookup and cache settings.", true,
|
2023-05-04 09:26:58 -07:00
|
|
|
ModuleList::GetGlobalModuleListProperties().GetValueProperties());
|
2024-03-14 09:40:00 -07:00
|
|
|
m_collection_sp->AppendProperty(
|
|
|
|
|
LanguageProperties::GetSettingName(), "Language settings.", true,
|
|
|
|
|
Language::GetGlobalLanguageProperties().GetValueProperties());
|
2023-05-04 09:26:58 -07:00
|
|
|
if (m_command_interpreter_up) {
|
|
|
|
|
m_collection_sp->AppendProperty(
|
2023-06-23 17:27:09 -07:00
|
|
|
"interpreter",
|
2023-05-04 09:26:58 -07:00
|
|
|
"Settings specify to the debugger's command interpreter.", true,
|
|
|
|
|
m_command_interpreter_up->GetValueProperties());
|
|
|
|
|
}
|
2012-02-21 02:23:08 +00:00
|
|
|
if (log_callback)
|
2022-06-16 20:19:12 -07:00
|
|
|
m_callback_handler_sp =
|
|
|
|
|
std::make_shared<CallbackLogHandler>(log_callback, baton);
|
2019-02-13 06:25:41 +00:00
|
|
|
m_command_interpreter_up->Initialize();
|
2016-05-04 22:26:42 +00:00
|
|
|
// Always add our default platform to the platform list
|
|
|
|
|
PlatformSP default_platform_sp(Platform::GetHostPlatform());
|
2016-03-02 02:18:18 +00:00
|
|
|
assert(default_platform_sp);
|
2016-05-04 22:26:42 +00:00
|
|
|
m_platform_list.Append(default_platform_sp, true);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-11-05 11:38:50 -08:00
|
|
|
// Create the dummy target.
|
|
|
|
|
{
|
|
|
|
|
ArchSpec arch(Target::GetDefaultArchitecture());
|
|
|
|
|
if (!arch.IsValid())
|
|
|
|
|
arch = HostInfo::GetArchitecture();
|
|
|
|
|
assert(arch.IsValid() && "No valid default or host archspec");
|
|
|
|
|
const bool is_dummy_target = true;
|
|
|
|
|
m_dummy_target_sp.reset(
|
|
|
|
|
new Target(*this, arch, default_platform_sp, is_dummy_target));
|
|
|
|
|
}
|
2019-08-26 09:20:59 +00:00
|
|
|
assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?");
|
|
|
|
|
|
2024-02-22 21:48:49 -08:00
|
|
|
OptionValueUInt64 *term_width =
|
|
|
|
|
m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(
|
2023-05-02 10:31:21 -07:00
|
|
|
ePropertyTerminalWidth);
|
2012-08-22 17:17:09 +00:00
|
|
|
term_width->SetMinimumValue(10);
|
2024-12-16 11:11:17 -08:00
|
|
|
|
|
|
|
|
OptionValueUInt64 *term_height =
|
|
|
|
|
m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(
|
|
|
|
|
ePropertyTerminalHeight);
|
|
|
|
|
term_height->SetMinimumValue(10);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2013-05-23 20:47:45 +00:00
|
|
|
// Turn off use-color if this is a dumb terminal.
|
2012-08-22 17:17:09 +00:00
|
|
|
const char *term = getenv("TERM");
|
2025-04-22 12:59:46 -07:00
|
|
|
auto disable_color = [&]() {
|
2012-08-22 17:17:09 +00:00
|
|
|
SetUseColor(false);
|
2025-04-22 12:59:46 -07:00
|
|
|
SetSeparator("| ");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (term && !strcmp(term, "dumb"))
|
|
|
|
|
disable_color();
|
2018-08-27 15:16:25 +00:00
|
|
|
// Turn off use-color if we don't write to a terminal with color support.
|
2025-02-19 08:31:40 -08:00
|
|
|
if (!GetOutputFileSP()->GetIsTerminalWithColors())
|
2025-04-22 12:59:46 -07:00
|
|
|
disable_color();
|
2018-09-05 22:06:58 +00:00
|
|
|
|
2023-03-07 15:59:30 -08:00
|
|
|
if (Diagnostics::Enabled()) {
|
|
|
|
|
m_diagnostics_callback_id = Diagnostics::Instance().AddCallback(
|
|
|
|
|
[this](const FileSpec &dir) -> llvm::Error {
|
|
|
|
|
for (auto &entry : m_stream_handlers) {
|
|
|
|
|
llvm::StringRef log_path = entry.first();
|
|
|
|
|
llvm::StringRef file_name = llvm::sys::path::filename(log_path);
|
|
|
|
|
FileSpec destination = dir.CopyByAppendingPathComponent(file_name);
|
|
|
|
|
std::error_code ec =
|
|
|
|
|
llvm::sys::fs::copy_file(log_path, destination.GetPath());
|
|
|
|
|
if (ec)
|
|
|
|
|
return llvm::errorCodeToError(ec);
|
|
|
|
|
}
|
|
|
|
|
return llvm::Error::success();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-05 22:06:58 +00:00
|
|
|
#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
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 22:26:42 +00:00
|
|
|
Debugger::~Debugger() { Clear(); }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-08-22 17:17:09 +00:00
|
|
|
void Debugger::Clear() {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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.
|
2016-09-06 20:57:50 +00:00
|
|
|
//
|
2012-08-23 00:22:02 +00:00
|
|
|
// The following functions call Debugger::Clear():
|
2016-05-04 22:26:42 +00:00
|
|
|
// Debugger::~Debugger();
|
2012-08-23 00:22:02 +00:00
|
|
|
// static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
|
|
|
|
|
// static void Debugger::Terminate();
|
2017-02-06 17:55:02 +00:00
|
|
|
llvm::call_once(m_clear_once, [this]() {
|
2025-03-03 10:07:54 -05:00
|
|
|
telemetry::ScopedDispatcher<telemetry::DebuggerInfo> helper(
|
|
|
|
|
[this](lldb_private::telemetry::DebuggerInfo *info) {
|
|
|
|
|
assert(this == info->debugger);
|
2025-03-03 07:38:09 -08:00
|
|
|
(void)this;
|
2025-03-03 10:07:54 -05:00
|
|
|
info->is_exit_entry = true;
|
|
|
|
|
},
|
|
|
|
|
this);
|
2012-08-23 00:22:02 +00:00
|
|
|
ClearIOHandlers();
|
2016-05-04 22:26:42 +00:00
|
|
|
StopIOHandlerThread();
|
2012-08-23 00:22:02 +00:00
|
|
|
StopEventHandlerThread();
|
2016-05-04 22:26:42 +00:00
|
|
|
m_listener_sp->Clear();
|
2021-07-13 10:34:27 -07:00
|
|
|
for (TargetSP target_sp : m_target_list.Targets()) {
|
2012-08-23 00:22:02 +00:00
|
|
|
if (target_sp) {
|
2021-07-13 10:34:27 -07:00
|
|
|
if (ProcessSP process_sp = target_sp->GetProcessSP())
|
2023-12-07 14:36:27 -08:00
|
|
|
process_sp->Finalize(false /* not destructing */);
|
2016-05-04 22:26:42 +00:00
|
|
|
target_sp->Destroy();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-08-23 00:22:02 +00:00
|
|
|
}
|
2016-03-02 02:18:18 +00:00
|
|
|
m_broadcaster_manager_sp->Clear();
|
2013-05-23 20:47:45 +00:00
|
|
|
|
|
|
|
|
// Close the input file _before_ we close the input read communications
|
2018-04-30 16:49:04 +00:00
|
|
|
// class as it does NOT own the input file, our m_input_file does.
|
2013-05-23 20:47:45 +00:00
|
|
|
m_terminal_state.Clear();
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
GetInputFile().Close();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2019-02-13 06:25:41 +00:00
|
|
|
m_command_interpreter_up->Clear();
|
2023-03-07 15:59:30 -08:00
|
|
|
|
|
|
|
|
if (Diagnostics::Enabled())
|
|
|
|
|
Diagnostics::Instance().RemoveCallback(m_diagnostics_callback_id);
|
2013-05-23 20:47:45 +00:00
|
|
|
});
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2011-05-29 04:06:55 +00:00
|
|
|
bool Debugger::GetAsyncExecution() {
|
2019-02-13 06:25:41 +00:00
|
|
|
return !m_command_interpreter_up->GetSynchronous();
|
2011-05-29 04:06:55 +00:00
|
|
|
}
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
void Debugger::SetAsyncExecution(bool async_execution) {
|
2019-02-13 06:25:41 +00:00
|
|
|
m_command_interpreter_up->SetSynchronous(!async_execution);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-24 16:13:48 +00:00
|
|
|
static inline int OpenPipe(int fds[2], std::size_t size) {
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
return _pipe(fds, size, O_BINARY);
|
|
|
|
|
#else
|
|
|
|
|
(void)size;
|
|
|
|
|
return pipe(fds);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status Debugger::SetInputString(const char *data) {
|
|
|
|
|
Status result;
|
|
|
|
|
enum PIPES { READ, WRITE }; // Indexes for the read and write fds
|
|
|
|
|
int fds[2] = {-1, -1};
|
|
|
|
|
|
|
|
|
|
if (data == nullptr) {
|
2024-08-27 10:59:31 -07:00
|
|
|
result = Status::FromErrorString("String data is null");
|
2021-11-24 16:13:48 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t size = strlen(data);
|
|
|
|
|
if (size == 0) {
|
2024-08-27 10:59:31 -07:00
|
|
|
result = Status::FromErrorString("String data is empty");
|
2021-11-24 16:13:48 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OpenPipe(fds, size) != 0) {
|
2024-08-27 10:59:31 -07:00
|
|
|
result = Status::FromErrorString(
|
2021-11-24 16:13:48 +00:00
|
|
|
"can't create pipe file descriptors for LLDB commands");
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 14:11:49 +03:00
|
|
|
int r = write(fds[WRITE], data, size);
|
|
|
|
|
(void)r;
|
2021-11-24 16:13:48 +00:00
|
|
|
// Close the write end of the pipe, so that the command interpreter will exit
|
|
|
|
|
// when it consumes all the data.
|
|
|
|
|
llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
|
|
|
|
|
|
|
|
|
|
// Open the read file descriptor as a FILE * that we can return as an input
|
|
|
|
|
// handle.
|
|
|
|
|
FILE *commands_file = fdopen(fds[READ], "rb");
|
|
|
|
|
if (commands_file == nullptr) {
|
2024-08-27 10:59:31 -07:00
|
|
|
result = Status::FromErrorStringWithFormat(
|
|
|
|
|
"fdopen(%i, \"rb\") failed (errno = %i) "
|
|
|
|
|
"when trying to open LLDB commands pipe",
|
|
|
|
|
fds[READ], errno);
|
2021-11-24 16:13:48 +00:00
|
|
|
llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 10:51:13 -08:00
|
|
|
SetInputFile((FileSP)std::make_shared<NativeFile>(
|
|
|
|
|
commands_file, File::eOpenOptionReadOnly, true));
|
2022-09-19 10:47:09 -07:00
|
|
|
return result;
|
2021-11-24 16:13:48 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-19 10:47:09 -07:00
|
|
|
void Debugger::SetInputFile(FileSP file_sp) {
|
2019-10-03 04:04:48 +00:00
|
|
|
assert(file_sp && file_sp->IsValid());
|
2020-08-10 21:01:23 -07:00
|
|
|
m_input_file_sp = std::move(file_sp);
|
2018-04-30 16:49:04 +00:00
|
|
|
// Save away the terminal state if that is relevant, so that we can restore
|
|
|
|
|
// it in RestoreInputState.
|
2012-11-30 20:23:19 +00:00
|
|
|
SaveInputTerminalState();
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-03 04:04:48 +00:00
|
|
|
void Debugger::SetOutputFile(FileSP file_sp) {
|
|
|
|
|
assert(file_sp && file_sp->IsValid());
|
2025-02-19 20:32:00 -08:00
|
|
|
m_output_stream_sp =
|
|
|
|
|
std::make_shared<LockableStreamFile>(file_sp, m_output_mutex);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-03 04:04:48 +00:00
|
|
|
void Debugger::SetErrorFile(FileSP file_sp) {
|
|
|
|
|
assert(file_sp && file_sp->IsValid());
|
2025-02-19 20:32:00 -08:00
|
|
|
m_error_stream_sp =
|
|
|
|
|
std::make_shared<LockableStreamFile>(file_sp, m_output_mutex);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-30 20:23:19 +00:00
|
|
|
void Debugger::SaveInputTerminalState() {
|
2025-04-11 08:53:49 -07:00
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
|
|
|
|
if (m_statusline)
|
|
|
|
|
m_statusline->Disable();
|
|
|
|
|
}
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
int fd = GetInputFile().GetDescriptor();
|
|
|
|
|
if (fd != File::kInvalidDescriptor)
|
|
|
|
|
m_terminal_state.Save(fd, true);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
void Debugger::RestoreInputTerminalState() {
|
|
|
|
|
m_terminal_state.Restore();
|
2025-04-11 08:53:49 -07:00
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
|
|
|
|
if (m_statusline)
|
2025-09-23 14:18:11 -07:00
|
|
|
m_statusline->Enable(GetSelectedExecutionContext());
|
2025-04-11 08:53:49 -07:00
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:18:11 -07:00
|
|
|
void Debugger::RedrawStatusline(
|
|
|
|
|
std::optional<ExecutionContextRef> exe_ctx_ref) {
|
2025-04-11 08:53:49 -07:00
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
2025-09-23 14:18:11 -07:00
|
|
|
|
|
|
|
|
if (!m_statusline)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_statusline->Redraw(exe_ctx_ref);
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-08-26 21:32:51 +00:00
|
|
|
ExecutionContext Debugger::GetSelectedExecutionContext() {
|
2021-02-01 22:24:30 +03:00
|
|
|
bool adopt_selected = true;
|
|
|
|
|
ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected);
|
|
|
|
|
return ExecutionContext(exe_ctx_ref);
|
2012-11-30 20:23:19 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:18:11 -07:00
|
|
|
ExecutionContextRef Debugger::GetSelectedExecutionContextRef() {
|
|
|
|
|
if (TargetSP selected_target_sp = GetSelectedTarget())
|
|
|
|
|
return ExecutionContextRef(selected_target_sp.get(),
|
|
|
|
|
/*adopt_selected=*/true);
|
|
|
|
|
return ExecutionContextRef(m_dummy_target_sp.get(), /*adopt_selected=*/false);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-30 20:23:19 +00:00
|
|
|
void Debugger::DispatchInputInterrupt() {
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
|
|
|
|
IOHandlerSP reader_sp(m_io_handler_stack.Top());
|
2011-02-10 01:15:13 +00:00
|
|
|
if (reader_sp)
|
2014-01-27 23:43:24 +00:00
|
|
|
reader_sp->Interrupt();
|
2012-11-30 20:23:19 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-26 21:32:51 +00:00
|
|
|
void Debugger::DispatchInputEndOfFile() {
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
|
|
|
|
IOHandlerSP reader_sp(m_io_handler_stack.Top());
|
2011-09-22 04:58:26 +00:00
|
|
|
if (reader_sp)
|
|
|
|
|
reader_sp->GotEOF();
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2010-11-19 20:47:54 +00:00
|
|
|
void Debugger::ClearIOHandlers() {
|
2016-05-18 01:59:10 +00:00
|
|
|
// The bottom input reader should be the main debugger input reader. We do
|
|
|
|
|
// not want to close that one here.
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
|
|
|
|
while (m_io_handler_stack.GetSize() > 1) {
|
|
|
|
|
IOHandlerSP reader_sp(m_io_handler_stack.Top());
|
2011-02-10 01:15:13 +00:00
|
|
|
if (reader_sp)
|
2014-01-27 23:43:24 +00:00
|
|
|
PopIOHandler(reader_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-11-19 20:47:54 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-16 16:45:18 -08:00
|
|
|
void Debugger::RunIOHandlers() {
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
IOHandlerSP reader_sp = m_io_handler_stack.Top();
|
2010-11-19 20:47:54 +00:00
|
|
|
while (true) {
|
2011-02-10 01:15:13 +00:00
|
|
|
if (!reader_sp)
|
2014-01-27 23:43:24 +00:00
|
|
|
break;
|
2010-11-19 20:47:54 +00:00
|
|
|
|
2016-05-18 01:59:10 +00:00
|
|
|
reader_sp->Run();
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
{
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(
|
|
|
|
|
m_io_handler_synchronous_mutex);
|
|
|
|
|
|
|
|
|
|
// Remove all input readers that are done from the top of the stack
|
|
|
|
|
while (true) {
|
|
|
|
|
IOHandlerSP top_reader_sp = m_io_handler_stack.Top();
|
|
|
|
|
if (top_reader_sp && top_reader_sp->GetIsDone())
|
|
|
|
|
PopIOHandler(top_reader_sp);
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
reader_sp = m_io_handler_stack.Top();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ClearIOHandlers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex);
|
|
|
|
|
|
|
|
|
|
PushIOHandler(reader_sp);
|
|
|
|
|
IOHandlerSP top_reader_sp = reader_sp;
|
2010-12-20 18:35:50 +00:00
|
|
|
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
while (top_reader_sp) {
|
|
|
|
|
top_reader_sp->Run();
|
|
|
|
|
|
|
|
|
|
// Don't unwind past the starting point.
|
|
|
|
|
if (top_reader_sp.get() == reader_sp.get()) {
|
|
|
|
|
if (PopIOHandler(reader_sp))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we pushed new IO handlers, pop them if they're done or restart the
|
|
|
|
|
// loop to run them if they're not.
|
2016-03-02 02:18:18 +00:00
|
|
|
while (true) {
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
top_reader_sp = m_io_handler_stack.Top();
|
|
|
|
|
if (top_reader_sp && top_reader_sp->GetIsDone()) {
|
2015-05-27 12:40:32 +00:00
|
|
|
PopIOHandler(top_reader_sp);
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
// Don't unwind past the starting point.
|
|
|
|
|
if (top_reader_sp.get() == reader_sp.get())
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
2014-01-27 23:43:24 +00:00
|
|
|
break;
|
[lldb/IOHandler] Improve synchronization between IO handlers.
The way the IO handlers are currently managed by the debugger is wrong. The
implementation lacks proper synchronization between RunIOHandlerSync and
RunIOHandlers. The latter is meant to be run by the "main thread", while the
former is meant to be run synchronously, potentially from a different thread.
Imagine a scenario where RunIOHandlerSync is called from a different thread
than RunIOHandlers. Both functions manipulate the debugger's IOHandlerStack.
Although the push and pop operations are synchronized, the logic to activate,
deactivate and run IO handlers is not.
While investigating PR44352, I noticed some weird behavior in the Editline
implementation. One of its members (m_editor_status) was modified from another
thread. This happened because the main thread, while running RunIOHandlers
ended up execution the IOHandlerEditline created by the breakpoint callback
thread. Even worse, due to the lack of synchronization within the IO handler
implementation, both threads ended up executing the same IO handler.
Most of the time, the IO handlers don't need to run synchronously. The
exception is sourcing commands from external files, like the .lldbinit file.
I've added a (recursive) mutex to prevent another thread from messing with the
IO handlers wile another thread is running one synchronously. It has to be
recursive, because we might have to source another file when encountering a
command source in the original file.
Differential revision: https://reviews.llvm.org/D72748
2020-01-20 11:05:13 -08:00
|
|
|
}
|
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.
As part of this it introduces a new Stream class,
StreamAsynchronousIO. A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast. When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string. When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.
Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.
I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired. I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).
llvm-svn: 130721
2011-05-02 20:41:46 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.
As part of this it introduces a new Stream class,
StreamAsynchronousIO. A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast. When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string. When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.
Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.
I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired. I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).
llvm-svn: 130721
2011-05-02 20:41:46 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {
|
2020-01-15 14:56:28 -08:00
|
|
|
return m_io_handler_stack.IsTop(reader_sp);
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
|
|
|
|
|
IOHandler::Type second_top_type) {
|
2020-01-15 14:56:28 -08:00
|
|
|
return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
|
2022-03-14 09:26:39 -07:00
|
|
|
bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);
|
|
|
|
|
if (!printed) {
|
2025-02-19 20:32:00 -08:00
|
|
|
LockableStreamFileSP stream_sp =
|
2022-03-14 09:26:39 -07:00
|
|
|
is_stdout ? m_output_stream_sp : m_error_stream_sp;
|
2025-02-19 20:32:00 -08:00
|
|
|
LockedStreamFile locked_stream = stream_sp->Lock();
|
|
|
|
|
locked_stream.Write(s, len);
|
2022-03-14 09:26:39 -07:00
|
|
|
}
|
2015-05-27 12:40:32 +00:00
|
|
|
}
|
2011-05-09 23:06:58 +00:00
|
|
|
|
2023-05-26 15:50:26 -07:00
|
|
|
llvm::StringRef Debugger::GetTopIOHandlerControlSequence(char ch) {
|
2020-01-15 14:56:28 -08:00
|
|
|
return m_io_handler_stack.GetTopIOHandlerControlSequence(ch);
|
2011-05-09 23:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 00:52:41 +00:00
|
|
|
const char *Debugger::GetIOHandlerCommandPrefix() {
|
2020-01-15 14:56:28 -08:00
|
|
|
return m_io_handler_stack.GetTopIOHandlerCommandPrefix();
|
2015-01-15 00:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *Debugger::GetIOHandlerHelpPrologue() {
|
2020-01-15 14:56:28 -08:00
|
|
|
return m_io_handler_stack.GetTopIOHandlerHelpPrologue();
|
2015-01-15 00:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) {
|
|
|
|
|
return PopIOHandler(reader_sp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp,
|
|
|
|
|
bool cancel_top_handler) {
|
|
|
|
|
PushIOHandler(reader_sp, cancel_top_handler);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-19 20:32:00 -08:00
|
|
|
void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in,
|
|
|
|
|
LockableStreamFileSP &out,
|
|
|
|
|
LockableStreamFileSP &err) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
|
|
|
|
IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
|
2014-01-27 23:43:24 +00:00
|
|
|
// If no STDIN has been set, then set it appropriately
|
2019-10-16 01:58:15 +00:00
|
|
|
if (!in || !in->IsValid()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
if (top_reader_sp)
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
in = top_reader_sp->GetInputFileSP();
|
2016-09-06 20:57:50 +00:00
|
|
|
else
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
in = GetInputFileSP();
|
2016-03-02 02:18:18 +00:00
|
|
|
// If there is nothing, use stdin
|
2014-01-27 23:43:24 +00:00
|
|
|
if (!in)
|
2025-11-17 10:51:13 -08:00
|
|
|
in = std::make_shared<NativeFile>(stdin, File::eOpenOptionReadOnly,
|
|
|
|
|
NativeFile::Unowned);
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
// If no STDOUT has been set, then set it appropriately
|
2025-02-19 20:32:00 -08:00
|
|
|
if (!out || !out->GetUnlockedFile().IsValid()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
if (top_reader_sp)
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
out = top_reader_sp->GetOutputStreamFileSP();
|
2016-09-06 20:57:50 +00:00
|
|
|
else
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
out = GetOutputStreamSP();
|
2014-01-27 23:43:24 +00:00
|
|
|
// If there is nothing, use stdout
|
|
|
|
|
if (!out)
|
2025-02-19 20:32:00 -08:00
|
|
|
out = std::make_shared<LockableStreamFile>(stdout, NativeFile::Unowned,
|
|
|
|
|
m_output_mutex);
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
// If no STDERR has been set, then set it appropriately
|
2025-02-19 20:32:00 -08:00
|
|
|
if (!err || !err->GetUnlockedFile().IsValid()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
if (top_reader_sp)
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
err = top_reader_sp->GetErrorStreamFileSP();
|
2016-09-06 20:57:50 +00:00
|
|
|
else
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
err = GetErrorStreamSP();
|
2014-01-27 23:43:24 +00:00
|
|
|
// If there is nothing, use stderr
|
|
|
|
|
if (!err)
|
2025-02-19 20:32:00 -08:00
|
|
|
err = std::make_shared<LockableStreamFile>(stderr, NativeFile::Unowned,
|
|
|
|
|
m_output_mutex);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-29 22:50:54 +00:00
|
|
|
void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,
|
|
|
|
|
bool cancel_top_handler) {
|
2010-06-08 16:52:24 +00:00
|
|
|
if (!reader_sp)
|
|
|
|
|
return;
|
2016-05-18 01:59:10 +00:00
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
2015-05-27 12:40:32 +00:00
|
|
|
|
|
|
|
|
// Get the current top input reader...
|
2020-01-15 14:56:28 -08:00
|
|
|
IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
|
2016-05-18 01:59:10 +00:00
|
|
|
|
2014-02-28 18:22:24 +00:00
|
|
|
// Don't push the same IO handler twice...
|
2015-05-27 12:40:32 +00:00
|
|
|
if (reader_sp == top_reader_sp)
|
|
|
|
|
return;
|
2014-01-27 23:43:24 +00:00
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
// Push our new input reader
|
2020-01-15 14:56:28 -08:00
|
|
|
m_io_handler_stack.Push(reader_sp);
|
2015-05-27 12:40:32 +00:00
|
|
|
reader_sp->Activate();
|
|
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// Interrupt the top input reader to it will exit its Run() function and let
|
|
|
|
|
// this new input reader take over
|
2015-05-27 12:40:32 +00:00
|
|
|
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-29 22:50:54 +00:00
|
|
|
if (cancel_top_handler)
|
|
|
|
|
top_reader_sp->Cancel();
|
2014-02-28 18:22:24 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-18 01:59:10 +00:00
|
|
|
bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {
|
|
|
|
|
if (!pop_reader_sp)
|
2015-05-27 12:40:32 +00:00
|
|
|
return false;
|
|
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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...
|
2020-01-15 14:56:28 -08:00
|
|
|
if (m_io_handler_stack.IsEmpty())
|
2015-05-27 12:40:32 +00:00
|
|
|
return false;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
IOHandlerSP reader_sp(m_io_handler_stack.Top());
|
2015-05-27 12:40:32 +00:00
|
|
|
|
|
|
|
|
if (pop_reader_sp != reader_sp)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
reader_sp->Deactivate();
|
|
|
|
|
reader_sp->Cancel();
|
2020-01-15 14:56:28 -08:00
|
|
|
m_io_handler_stack.Pop();
|
2015-05-27 12:40:32 +00:00
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
reader_sp = m_io_handler_stack.Top();
|
2014-01-27 23:43:24 +00:00
|
|
|
if (reader_sp)
|
2015-05-27 12:40:32 +00:00
|
|
|
reader_sp->Activate();
|
2010-06-23 01:19:29 +00:00
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
|
2025-06-30 14:34:35 -07:00
|
|
|
void Debugger::RefreshIOHandler() {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
|
|
|
|
|
IOHandlerSP reader_sp(m_io_handler_stack.Top());
|
|
|
|
|
if (reader_sp)
|
|
|
|
|
reader_sp->Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 11:13:46 -08:00
|
|
|
StreamUP Debugger::GetAsyncOutputStream() {
|
|
|
|
|
return std::make_unique<StreamAsynchronousIO>(*this,
|
2025-02-19 08:34:15 -08:00
|
|
|
StreamAsynchronousIO::STDOUT);
|
2011-06-02 23:58:26 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 11:13:46 -08:00
|
|
|
StreamUP Debugger::GetAsyncErrorStream() {
|
|
|
|
|
return std::make_unique<StreamAsynchronousIO>(*this,
|
2025-02-19 08:34:15 -08:00
|
|
|
StreamAsynchronousIO::STDERR);
|
2011-06-02 23:58:26 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-15 11:20:20 -07:00
|
|
|
void Debugger::RequestInterrupt() {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_interrupt_mutex);
|
|
|
|
|
m_interrupt_requested++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::CancelInterruptRequest() {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_interrupt_mutex);
|
|
|
|
|
if (m_interrupt_requested > 0)
|
|
|
|
|
m_interrupt_requested--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::InterruptRequested() {
|
|
|
|
|
// This is the one we should call internally. This will return true either
|
2023-05-02 10:31:21 -07:00
|
|
|
// if there's a debugger interrupt and we aren't on the IOHandler thread,
|
2023-03-15 11:20:20 -07:00
|
|
|
// or if we are on the IOHandler thread and there's a CommandInterpreter
|
|
|
|
|
// interrupt.
|
|
|
|
|
if (!IsIOHandlerThreadCurrentThread()) {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_interrupt_mutex);
|
|
|
|
|
return m_interrupt_requested != 0;
|
|
|
|
|
}
|
|
|
|
|
return GetCommandInterpreter().WasInterrupted();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-13 09:14:50 -07:00
|
|
|
Debugger::InterruptionReport::InterruptionReport(
|
|
|
|
|
std::string function_name, const llvm::formatv_object_base &payload)
|
|
|
|
|
: m_function_name(std::move(function_name)),
|
|
|
|
|
m_interrupt_time(std::chrono::system_clock::now()),
|
|
|
|
|
m_thread_id(llvm::get_threadid()) {
|
2023-05-23 11:13:36 -07:00
|
|
|
llvm::raw_string_ostream desc(m_description);
|
|
|
|
|
desc << payload << "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::ReportInterruption(const InterruptionReport &report) {
|
2023-09-13 09:14:50 -07:00
|
|
|
// For now, just log the description:
|
2023-05-23 11:13:36 -07:00
|
|
|
Log *log = GetLog(LLDBLog::Host);
|
|
|
|
|
LLDB_LOG(log, "Interruption: {0}", report.m_description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debugger::DebuggerList Debugger::DebuggersRequestingInterruption() {
|
|
|
|
|
DebuggerList result;
|
|
|
|
|
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
|
|
|
|
for (auto debugger_sp : *g_debugger_list_ptr) {
|
|
|
|
|
if (debugger_sp->InterruptRequested())
|
|
|
|
|
result.push_back(debugger_sp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
size_t Debugger::GetNumDebuggers() {
|
2016-05-26 16:51:23 +00:00
|
|
|
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();
|
2012-03-30 20:53:46 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
2012-02-15 02:34:21 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-25 18:06:21 +00:00
|
|
|
lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) {
|
2012-02-15 02:34:21 +00:00
|
|
|
DebuggerSP debugger_sp;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
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);
|
2012-03-30 20:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
return debugger_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-30 16:22:25 +00:00
|
|
|
DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) {
|
2011-09-17 08:33:22 +00:00
|
|
|
DebuggerSP debugger_sp;
|
2010-06-30 16:22:25 +00:00
|
|
|
|
2016-05-26 16:51:23 +00:00
|
|
|
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) {
|
2016-03-02 02:18:18 +00:00
|
|
|
if ((*pos)->GetID() == id) {
|
2012-03-30 20:53:46 +00:00
|
|
|
debugger_sp = *pos;
|
|
|
|
|
break;
|
2010-06-30 16:22:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-30 16:22:25 +00:00
|
|
|
return debugger_sp;
|
|
|
|
|
}
|
2010-09-04 00:03:46 +00:00
|
|
|
|
2015-02-04 22:00:53 +00:00
|
|
|
bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,
|
2014-10-10 23:07:36 +00:00
|
|
|
const SymbolContext *sc,
|
|
|
|
|
const SymbolContext *prev_sc,
|
|
|
|
|
const ExecutionContext *exe_ctx,
|
|
|
|
|
const Address *addr, Stream &s) {
|
2015-02-04 22:00:53 +00:00
|
|
|
FormatEntity::Entry format_entry;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-03-02 02:18:18 +00:00
|
|
|
if (format == nullptr) {
|
2025-06-03 19:12:30 -07:00
|
|
|
if (exe_ctx != nullptr && exe_ctx->HasTargetScope()) {
|
|
|
|
|
format_entry =
|
|
|
|
|
exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
|
|
|
|
|
format = &format_entry;
|
|
|
|
|
}
|
2016-03-02 02:18:18 +00:00
|
|
|
if (format == nullptr) {
|
2015-02-04 22:00:53 +00:00
|
|
|
FormatEntity::Parse("${addr}: ", format_entry);
|
|
|
|
|
format = &format_entry;
|
2014-10-10 23:07:36 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-10-10 23:07:36 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-10-10 23:07:36 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2014-10-10 23:07:36 +00:00
|
|
|
// would return false. But we do get a prev_sc pointer.
|
|
|
|
|
if ((sc && (sc->function || sc->symbol)) && prev_sc &&
|
2016-03-02 02:18:18 +00:00
|
|
|
(prev_sc->function == nullptr && prev_sc->symbol == nullptr)) {
|
2014-10-10 23:07:36 +00:00
|
|
|
initial_function = true;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2016-03-02 02:18:18 +00:00
|
|
|
return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr,
|
|
|
|
|
function_changed, initial_function);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 20:24:18 -07:00
|
|
|
void Debugger::AssertCallback(llvm::StringRef message,
|
|
|
|
|
llvm::StringRef backtrace,
|
|
|
|
|
llvm::StringRef prompt) {
|
2025-03-31 09:40:33 -07:00
|
|
|
Debugger::ReportError(llvm::formatv("{0}\n{1}{2}\n{3}", message, backtrace,
|
|
|
|
|
GetVersion(), prompt)
|
|
|
|
|
.str());
|
2023-06-13 20:24:18 -07:00
|
|
|
}
|
|
|
|
|
|
2012-02-21 02:23:08 +00:00
|
|
|
void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
|
|
|
|
|
void *baton) {
|
2012-02-22 22:49:20 +00:00
|
|
|
// 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.
|
2022-06-16 20:19:12 -07:00
|
|
|
m_callback_handler_sp =
|
|
|
|
|
std::make_shared<CallbackLogHandler>(log_callback, baton);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-03 17:09:09 -08:00
|
|
|
void Debugger::SetDestroyCallback(
|
|
|
|
|
lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) {
|
SBDebugger: Add new APIs `AddDestroyCallback` and `RemoveDestroyCallback` (#89868)
# Motivation
Individual callers of `SBDebugger::SetDestroyCallback()` might think
that they have registered their callback and expect it to be called when
the debugger is destroyed. In reality, only the last caller survives,
and all previous callers are forgotten, which might be a surprise to
them. Worse, if this is called in a race condition, which callback
survives is less predictable, which may case confusing behavior
elsewhere.
# This PR
Allows multiple destroy callbacks to be registered and all called when
the debugger is destroyed.
**EDIT**: Adds two new APIs: `AddDestroyCallback()` and
`ClearDestroyCallback()`. `SetDestroyCallback()` will first clear then
add the given callback. Tests are added for the new APIs.
## Tests
```
bin/llvm-lit -sv ../external/llvm-project/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
```
## (out-dated, see comments below) Semantic change to
`SetDestroyCallback()`
~~Currently, the method overwrites the old callback with the new one.
With this PR, it will NOT overwrite. Instead, it will hold on to both.
Both callbacks get called during destroy.~~
~~**Risk**: Although the documentation of `SetDestroyCallback()` (see
[C++](https://lldb.llvm.org/cpp_reference/classlldb_1_1SBDebugger.html#afa1649d9453a376b5c95888b5a0cb4ec)
and
[python](https://lldb.llvm.org/python_api/lldb.SBDebugger.html#lldb.SBDebugger.SetDestroyCallback))
doesn't really specify the behavior, there is a risk: if existing call
sites rely on the "overwrite" behavior, they will be surprised because
now the old callback will get called. But as the above said, the current
behavior of "overwrite" itself might be unintended, so I don't
anticipate users to rely on this behavior. In short, this risk might be
less of a problem if we correct it sooner rather than later (which is
what this PR is trying to do).~~
## (out-dated, see comments below) Implementation
~~The implementation holds a `std::vector<std::pair<callback, baton>>`.
When `SetDestroyCallback()` is called, callbacks and batons are appended
to the `std::vector`. When destroy event happen, the `(callback, baton)`
pairs are invoked FIFO. Finally, the `std::vector` is cleared.~~
# (out-dated, see comments below) Alternatives considered
~~Instead of changing `SetDestroyCallback()`, a new method
`AddDestroyCallback()` can be added, which use the same
`std::vector<std::pair<>>` implementation. Together with
`ClearDestroyCallback()` (see below), they will replace and deprecate
`SetDestroyCallback()`. Meanwhile, in order to be backward compatible,
`SetDestroyCallback()` need to be updated to clear the `std::vector` and
then add the new callback. Pros: The end state is semantically more
correct. Cons: More steps to take; potentially maintaining an
"incorrect" behavior (of "overwrite").~~
~~A new method `ClearDestroyCallback()` can be added. Might be
unnecessary at this point, because workflows which need to set then
clear callbacks may exist but shouldn't be too common at least for now.
Such method can be added later when needed.~~
~~The `std::vector` may bring slight performance drawback if its
implementation doesn't handle small size efficiently. However, even if
that's the case, this path should be very cold (only used during init
and destroy). Such performance drawback should be negligible.~~
~~A different implementation was also considered. Instead of using
`std::vector`, the current `m_destroy_callback` field can be kept
unchanged. When `SetDestroyCallback()` is called, a lambda function can
be stored into `m_destroy_callback`. This lambda function will first
call the old callback, then the new one. This way, `std::vector` is
avoided. However, this implementation is more complex, thus less
readable, with not much perf to gain.~~
---------
Co-authored-by: Roy Shi <royshi@meta.com>
2024-05-20 15:51:42 -07:00
|
|
|
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
|
|
|
|
|
m_destroy_callbacks.clear();
|
|
|
|
|
const lldb::callback_token_t token = m_destroy_callback_next_token++;
|
|
|
|
|
m_destroy_callbacks.emplace_back(token, destroy_callback, baton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lldb::callback_token_t Debugger::AddDestroyCallback(
|
|
|
|
|
lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
|
|
|
|
|
const lldb::callback_token_t token = m_destroy_callback_next_token++;
|
|
|
|
|
m_destroy_callbacks.emplace_back(token, destroy_callback, baton);
|
|
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Debugger::RemoveDestroyCallback(lldb::callback_token_t token) {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
|
|
|
|
|
for (auto it = m_destroy_callbacks.begin(); it != m_destroy_callbacks.end();
|
|
|
|
|
++it) {
|
|
|
|
|
if (it->token == token) {
|
|
|
|
|
m_destroy_callbacks.erase(it);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2023-02-03 17:09:09 -08:00
|
|
|
}
|
|
|
|
|
|
2021-03-01 15:26:35 -08:00
|
|
|
static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
|
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:
1. As 3 separate progress instances. In this case you create a progress
instance with the message "Loading symbols: libFoo", "Loading
symbols: libBar", and "Loading symbols: libBaz" respectively. Each
progress event gets a unique ID and therefore cannot be correlated
by the consumer.
2. As 1 progress instance with 3 units of work. The title would be
"Loading symbols" and you call Progress::Increment for each of the
libraries. The 3 progress events share the same ID and can easily be
correlated, however, in the current design, there's no way to
include the name of the libraries.
The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.
This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:
[1/3] Loading symbols: libFoo
[2/3] Loading symbols: libBar
[3/3] Loading symbols: libBaz
Differential revision: https://reviews.llvm.org/D143690
2023-02-12 10:55:39 -08:00
|
|
|
std::string title, std::string details,
|
2021-03-01 15:26:35 -08:00
|
|
|
uint64_t completed, uint64_t total,
|
2024-03-01 10:56:45 -08:00
|
|
|
bool is_debugger_specific,
|
|
|
|
|
uint32_t progress_broadcast_bit) {
|
2021-03-01 15:26:35 -08:00
|
|
|
// Only deliver progress events if we have any progress listeners.
|
2024-03-01 10:56:45 -08:00
|
|
|
if (!debugger.GetBroadcaster().EventTypeHasListeners(progress_broadcast_bit))
|
2021-03-01 15:26:35 -08:00
|
|
|
return;
|
2024-03-01 10:56:45 -08:00
|
|
|
|
2022-03-14 09:01:53 -07:00
|
|
|
EventSP event_sp(new Event(
|
2024-03-01 10:56:45 -08:00
|
|
|
progress_broadcast_bit,
|
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:
1. As 3 separate progress instances. In this case you create a progress
instance with the message "Loading symbols: libFoo", "Loading
symbols: libBar", and "Loading symbols: libBaz" respectively. Each
progress event gets a unique ID and therefore cannot be correlated
by the consumer.
2. As 1 progress instance with 3 units of work. The title would be
"Loading symbols" and you call Progress::Increment for each of the
libraries. The 3 progress events share the same ID and can easily be
correlated, however, in the current design, there's no way to
include the name of the libraries.
The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.
This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:
[1/3] Loading symbols: libFoo
[2/3] Loading symbols: libBar
[3/3] Loading symbols: libBaz
Differential revision: https://reviews.llvm.org/D143690
2023-02-12 10:55:39 -08:00
|
|
|
new ProgressEventData(progress_id, std::move(title), std::move(details),
|
|
|
|
|
completed, total, is_debugger_specific)));
|
2021-03-01 15:26:35 -08:00
|
|
|
debugger.GetBroadcaster().BroadcastEvent(event_sp);
|
|
|
|
|
}
|
|
|
|
|
|
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:
1. As 3 separate progress instances. In this case you create a progress
instance with the message "Loading symbols: libFoo", "Loading
symbols: libBar", and "Loading symbols: libBaz" respectively. Each
progress event gets a unique ID and therefore cannot be correlated
by the consumer.
2. As 1 progress instance with 3 units of work. The title would be
"Loading symbols" and you call Progress::Increment for each of the
libraries. The 3 progress events share the same ID and can easily be
correlated, however, in the current design, there's no way to
include the name of the libraries.
The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.
This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:
[1/3] Loading symbols: libFoo
[2/3] Loading symbols: libBar
[3/3] Loading symbols: libBaz
Differential revision: https://reviews.llvm.org/D143690
2023-02-12 10:55:39 -08:00
|
|
|
void Debugger::ReportProgress(uint64_t progress_id, std::string title,
|
|
|
|
|
std::string details, uint64_t completed,
|
|
|
|
|
uint64_t total,
|
2024-03-01 10:56:45 -08:00
|
|
|
std::optional<lldb::user_id_t> debugger_id,
|
2025-03-08 11:10:46 -06:00
|
|
|
uint32_t progress_broadcast_bit) {
|
2021-03-01 15:26:35 -08:00
|
|
|
// Check if this progress is for a specific debugger.
|
2022-06-20 11:33:56 -07:00
|
|
|
if (debugger_id) {
|
2021-03-01 15:26:35 -08:00
|
|
|
// It is debugger specific, grab it and deliver the event if the debugger
|
|
|
|
|
// still exists.
|
|
|
|
|
DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
|
|
|
|
|
if (debugger_sp)
|
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:
1. As 3 separate progress instances. In this case you create a progress
instance with the message "Loading symbols: libFoo", "Loading
symbols: libBar", and "Loading symbols: libBaz" respectively. Each
progress event gets a unique ID and therefore cannot be correlated
by the consumer.
2. As 1 progress instance with 3 units of work. The title would be
"Loading symbols" and you call Progress::Increment for each of the
libraries. The 3 progress events share the same ID and can easily be
correlated, however, in the current design, there's no way to
include the name of the libraries.
The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.
This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:
[1/3] Loading symbols: libFoo
[2/3] Loading symbols: libBar
[3/3] Loading symbols: libBaz
Differential revision: https://reviews.llvm.org/D143690
2023-02-12 10:55:39 -08:00
|
|
|
PrivateReportProgress(*debugger_sp, progress_id, std::move(title),
|
|
|
|
|
std::move(details), completed, total,
|
2024-03-01 10:56:45 -08:00
|
|
|
/*is_debugger_specific*/ true,
|
2025-03-08 11:10:46 -06:00
|
|
|
progress_broadcast_bit);
|
2021-03-01 15:26:35 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// The progress event is not debugger specific, iterate over all debuggers
|
|
|
|
|
// and deliver a progress event to each one.
|
|
|
|
|
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)
|
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:
1. As 3 separate progress instances. In this case you create a progress
instance with the message "Loading symbols: libFoo", "Loading
symbols: libBar", and "Loading symbols: libBaz" respectively. Each
progress event gets a unique ID and therefore cannot be correlated
by the consumer.
2. As 1 progress instance with 3 units of work. The title would be
"Loading symbols" and you call Progress::Increment for each of the
libraries. The 3 progress events share the same ID and can easily be
correlated, however, in the current design, there's no way to
include the name of the libraries.
The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.
This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:
[1/3] Loading symbols: libFoo
[2/3] Loading symbols: libBar
[3/3] Loading symbols: libBaz
Differential revision: https://reviews.llvm.org/D143690
2023-02-12 10:55:39 -08:00
|
|
|
PrivateReportProgress(*(*pos), progress_id, title, details, completed,
|
2024-03-01 10:56:45 -08:00
|
|
|
total, /*is_debugger_specific*/ false,
|
2025-03-08 11:10:46 -06:00
|
|
|
progress_broadcast_bit);
|
2021-03-01 15:26:35 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 09:25:38 -07:00
|
|
|
static void PrivateReportDiagnostic(Debugger &debugger, Severity severity,
|
2022-03-16 08:30:26 -07:00
|
|
|
std::string message,
|
|
|
|
|
bool debugger_specific) {
|
|
|
|
|
uint32_t event_type = 0;
|
2024-05-03 09:25:38 -07:00
|
|
|
switch (severity) {
|
|
|
|
|
case eSeverityInfo:
|
|
|
|
|
assert(false && "eSeverityInfo should not be broadcast");
|
2022-10-31 10:16:32 -07:00
|
|
|
return;
|
2024-05-03 09:25:38 -07:00
|
|
|
case eSeverityWarning:
|
2024-05-09 10:28:23 -07:00
|
|
|
event_type = lldb::eBroadcastBitWarning;
|
2022-03-16 08:30:26 -07:00
|
|
|
break;
|
2024-05-03 09:25:38 -07:00
|
|
|
case eSeverityError:
|
2024-05-09 10:28:23 -07:00
|
|
|
event_type = lldb::eBroadcastBitError;
|
2022-03-16 08:30:26 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Broadcaster &broadcaster = debugger.GetBroadcaster();
|
|
|
|
|
if (!broadcaster.EventTypeHasListeners(event_type)) {
|
|
|
|
|
// Diagnostics are too important to drop. If nobody is listening, print the
|
|
|
|
|
// diagnostic directly to the debugger's error stream.
|
2024-05-03 09:25:38 -07:00
|
|
|
DiagnosticEventData event_data(severity, std::move(message),
|
|
|
|
|
debugger_specific);
|
2025-02-20 11:13:46 -08:00
|
|
|
event_data.Dump(debugger.GetAsyncErrorStream().get());
|
2022-03-16 08:30:26 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
EventSP event_sp = std::make_shared<Event>(
|
|
|
|
|
event_type,
|
2024-05-03 09:25:38 -07:00
|
|
|
new DiagnosticEventData(severity, std::move(message), debugger_specific));
|
2022-03-16 08:30:26 -07:00
|
|
|
broadcaster.BroadcastEvent(event_sp);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 09:25:38 -07:00
|
|
|
void Debugger::ReportDiagnosticImpl(Severity severity, std::string message,
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<lldb::user_id_t> debugger_id,
|
2022-03-16 08:30:26 -07:00
|
|
|
std::once_flag *once) {
|
|
|
|
|
auto ReportDiagnosticLambda = [&]() {
|
2024-05-03 09:45:16 -07:00
|
|
|
// Always log diagnostics to the system log.
|
|
|
|
|
Host::SystemLog(severity, message);
|
|
|
|
|
|
2022-10-31 10:16:32 -07:00
|
|
|
// The diagnostic subsystem is optional but we still want to broadcast
|
|
|
|
|
// events when it's disabled.
|
|
|
|
|
if (Diagnostics::Enabled())
|
|
|
|
|
Diagnostics::Instance().Report(message);
|
|
|
|
|
|
|
|
|
|
// We don't broadcast info events.
|
2024-05-03 09:25:38 -07:00
|
|
|
if (severity == lldb::eSeverityInfo)
|
2022-10-31 10:16:32 -07:00
|
|
|
return;
|
|
|
|
|
|
2022-10-24 11:13:51 -07:00
|
|
|
// Check if this diagnostic is for a specific debugger.
|
2022-03-16 08:30:26 -07:00
|
|
|
if (debugger_id) {
|
|
|
|
|
// It is debugger specific, grab it and deliver the event if the debugger
|
|
|
|
|
// still exists.
|
|
|
|
|
DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
|
|
|
|
|
if (debugger_sp)
|
2024-05-03 09:25:38 -07:00
|
|
|
PrivateReportDiagnostic(*debugger_sp, severity, std::move(message),
|
|
|
|
|
true);
|
2022-03-16 08:30:26 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-24 11:13:51 -07:00
|
|
|
// The diagnostic event is not debugger specific, iterate over all debuggers
|
|
|
|
|
// and deliver a diagnostic event to each one.
|
2022-03-16 08:30:26 -07:00
|
|
|
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
|
|
|
|
for (const auto &debugger : *g_debugger_list_ptr)
|
2024-05-03 09:25:38 -07:00
|
|
|
PrivateReportDiagnostic(*debugger, severity, message, false);
|
2022-03-16 08:30:26 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (once)
|
|
|
|
|
std::call_once(*once, ReportDiagnosticLambda);
|
|
|
|
|
else
|
|
|
|
|
ReportDiagnosticLambda();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::ReportWarning(std::string message,
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<lldb::user_id_t> debugger_id,
|
2022-03-16 08:30:26 -07:00
|
|
|
std::once_flag *once) {
|
2024-05-03 09:25:38 -07:00
|
|
|
ReportDiagnosticImpl(eSeverityWarning, std::move(message), debugger_id, once);
|
2022-03-16 08:30:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::ReportError(std::string message,
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<lldb::user_id_t> debugger_id,
|
2022-03-16 08:30:26 -07:00
|
|
|
std::once_flag *once) {
|
2024-05-03 09:25:38 -07:00
|
|
|
ReportDiagnosticImpl(eSeverityError, std::move(message), debugger_id, once);
|
2022-03-16 08:30:26 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-31 10:16:32 -07:00
|
|
|
void Debugger::ReportInfo(std::string message,
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<lldb::user_id_t> debugger_id,
|
2022-10-31 10:16:32 -07:00
|
|
|
std::once_flag *once) {
|
2024-05-03 09:25:38 -07:00
|
|
|
ReportDiagnosticImpl(eSeverityInfo, std::move(message), debugger_id, once);
|
2022-10-31 10:16:32 -07:00
|
|
|
}
|
|
|
|
|
|
[lldb] Fetching symbols in the background with dsymForUUID
On macOS, LLDB uses the DebugSymbols.framework to locate symbol rich
dSYM bundles. [1] The framework uses a variety of methods, one of them
calling into a binary or shell script to locate (and download) dSYMs.
Internally at Apple, that tool is called dsymForUUID and for simplicity
I'm just going to refer to it that way here too, even though it can be
be an arbitrary executable.
The most common use case for dsymForUUID is to fetch symbols from the
network. This can take a long time, and because the calls to the
DebugSymbols.framework are blocking, it takes a while to launch the
process. This is expected and therefore many people don't use this
functionality, but instead use add-dsym when they want symbols for a
given frame, backtrace or module. This is a little faster because you're
only fetching symbols for the module you care about, but it's still a
slow, blocking operation.
This patch introduces a hybrid approach between the two. When
symbols.enable-background-lookup is enabled, lldb will do the equivalent
of add-dsym in the background for every module that shows up in the
backtrace but doesn't have symbols for. From the user's perspective
there is no slowdown, because the process launches immediately, with
whatever symbols are available. Meanwhile, more symbol information is
added over time as the background fetching completes.
[1] https://lldb.llvm.org/use/symbols.html
rdar://76241471
Differential revision: https://reviews.llvm.org/D131328
2022-08-15 17:37:34 -07:00
|
|
|
void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {
|
|
|
|
|
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
|
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
|
|
|
|
|
for (DebuggerSP debugger_sp : *g_debugger_list_ptr) {
|
|
|
|
|
EventSP event_sp = std::make_shared<Event>(
|
2024-05-09 10:28:23 -07:00
|
|
|
lldb::eBroadcastSymbolChange,
|
[lldb] Fetching symbols in the background with dsymForUUID
On macOS, LLDB uses the DebugSymbols.framework to locate symbol rich
dSYM bundles. [1] The framework uses a variety of methods, one of them
calling into a binary or shell script to locate (and download) dSYMs.
Internally at Apple, that tool is called dsymForUUID and for simplicity
I'm just going to refer to it that way here too, even though it can be
be an arbitrary executable.
The most common use case for dsymForUUID is to fetch symbols from the
network. This can take a long time, and because the calls to the
DebugSymbols.framework are blocking, it takes a while to launch the
process. This is expected and therefore many people don't use this
functionality, but instead use add-dsym when they want symbols for a
given frame, backtrace or module. This is a little faster because you're
only fetching symbols for the module you care about, but it's still a
slow, blocking operation.
This patch introduces a hybrid approach between the two. When
symbols.enable-background-lookup is enabled, lldb will do the equivalent
of add-dsym in the background for every module that shows up in the
backtrace but doesn't have symbols for. From the user's perspective
there is no slowdown, because the process launches immediately, with
whatever symbols are available. Meanwhile, more symbol information is
added over time as the background fetching completes.
[1] https://lldb.llvm.org/use/symbols.html
rdar://76241471
Differential revision: https://reviews.llvm.org/D131328
2022-08-15 17:37:34 -07:00
|
|
|
new SymbolChangeEventData(debugger_sp, module_spec));
|
|
|
|
|
debugger_sp->GetBroadcaster().BroadcastEvent(event_sp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 12:53:10 -07:00
|
|
|
static std::shared_ptr<LogHandler>
|
|
|
|
|
CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
|
|
|
|
|
size_t buffer_size) {
|
|
|
|
|
switch (log_handler_kind) {
|
|
|
|
|
case eLogHandlerStream:
|
|
|
|
|
return std::make_shared<StreamLogHandler>(fd, should_close, buffer_size);
|
|
|
|
|
case eLogHandlerCircular:
|
|
|
|
|
return std::make_shared<RotatingLogHandler>(buffer_size);
|
|
|
|
|
case eLogHandlerSystem:
|
|
|
|
|
return std::make_shared<SystemLogHandler>();
|
|
|
|
|
case eLogHandlerCallback:
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-01 10:08:40 +00:00
|
|
|
bool Debugger::EnableLog(llvm::StringRef channel,
|
|
|
|
|
llvm::ArrayRef<const char *> categories,
|
|
|
|
|
llvm::StringRef log_file, uint32_t log_options,
|
2022-06-24 12:53:10 -07:00
|
|
|
size_t buffer_size, LogHandlerKind log_handler_kind,
|
|
|
|
|
llvm::raw_ostream &error_stream) {
|
2017-02-10 11:49:21 +00:00
|
|
|
|
2022-06-15 17:32:14 -07:00
|
|
|
std::shared_ptr<LogHandler> log_handler_sp;
|
|
|
|
|
if (m_callback_handler_sp) {
|
|
|
|
|
log_handler_sp = m_callback_handler_sp;
|
2012-02-21 02:23:08 +00:00
|
|
|
// 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;
|
2017-03-01 10:08:40 +00:00
|
|
|
} else if (log_file.empty()) {
|
2022-06-24 12:53:10 -07:00
|
|
|
log_handler_sp =
|
2025-02-19 08:31:40 -08:00
|
|
|
CreateLogHandler(log_handler_kind, GetOutputFileSP()->GetDescriptor(),
|
2022-06-24 12:53:10 -07:00
|
|
|
/*should_close=*/false, buffer_size);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2022-06-15 17:32:14 -07:00
|
|
|
auto pos = m_stream_handlers.find(log_file);
|
|
|
|
|
if (pos != m_stream_handlers.end())
|
|
|
|
|
log_handler_sp = pos->second.lock();
|
|
|
|
|
if (!log_handler_sp) {
|
2020-06-10 18:12:59 -07:00
|
|
|
File::OpenOptions flags =
|
2021-07-28 20:07:03 +02:00
|
|
|
File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
|
2017-02-10 11:49:21 +00:00
|
|
|
if (log_options & LLDB_LOG_OPTION_APPEND)
|
2020-06-10 18:12:59 -07:00
|
|
|
flags |= File::eOpenOptionAppend;
|
|
|
|
|
else
|
|
|
|
|
flags |= File::eOpenOptionTruncate;
|
2020-08-17 10:30:23 +02:00
|
|
|
llvm::Expected<FileUP> file = FileSystem::Instance().Open(
|
2020-06-10 18:12:59 -07:00
|
|
|
FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false);
|
|
|
|
|
if (!file) {
|
2020-08-17 10:30:23 +02:00
|
|
|
error_stream << "Unable to open log file '" << log_file
|
|
|
|
|
<< "': " << llvm::toString(file.takeError()) << "\n";
|
2017-02-10 11:49:21 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2020-06-10 18:12:59 -07:00
|
|
|
|
2022-06-24 12:53:10 -07:00
|
|
|
log_handler_sp =
|
|
|
|
|
CreateLogHandler(log_handler_kind, (*file)->GetDescriptor(),
|
|
|
|
|
/*should_close=*/true, buffer_size);
|
2022-06-15 17:32:14 -07:00
|
|
|
m_stream_handlers[log_file] = log_handler_sp;
|
2014-10-10 23:07:36 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2022-06-15 17:32:14 -07:00
|
|
|
assert(log_handler_sp);
|
2013-05-23 20:47:45 +00:00
|
|
|
|
2012-02-21 02:23:08 +00:00
|
|
|
if (log_options == 0)
|
2022-06-23 08:08:36 -07:00
|
|
|
log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
|
2012-02-21 02:23:08 +00:00
|
|
|
|
2022-06-15 17:32:14 -07:00
|
|
|
return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,
|
2015-05-27 13:34:04 +00:00
|
|
|
error_stream);
|
2012-02-21 02:23:08 +00:00
|
|
|
}
|
|
|
|
|
|
2019-12-21 17:11:12 -08:00
|
|
|
ScriptInterpreter *
|
|
|
|
|
Debugger::GetScriptInterpreter(bool can_create,
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<lldb::ScriptLanguage> language) {
|
2019-04-26 22:43:16 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);
|
2019-12-21 17:11:12 -08:00
|
|
|
lldb::ScriptLanguage script_language =
|
|
|
|
|
language ? *language : GetScriptLanguage();
|
2019-04-26 22:43:16 +00:00
|
|
|
|
2019-12-21 17:11:12 -08:00
|
|
|
if (!m_script_interpreters[script_language]) {
|
2019-04-26 22:43:16 +00:00
|
|
|
if (!can_create)
|
|
|
|
|
return nullptr;
|
2019-12-21 17:11:12 -08:00
|
|
|
m_script_interpreters[script_language] =
|
|
|
|
|
PluginManager::GetScriptInterpreterForLanguage(script_language, *this);
|
2019-04-26 22:43:16 +00:00
|
|
|
}
|
|
|
|
|
|
2019-12-21 17:11:12 -08:00
|
|
|
return m_script_interpreters[script_language].get();
|
2019-04-26 22:43:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-19 00:20:55 +00:00
|
|
|
SourceManager &Debugger::GetSourceManager() {
|
2019-02-13 06:25:41 +00:00
|
|
|
if (!m_source_manager_up)
|
2019-08-14 22:19:23 +00:00
|
|
|
m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
|
2019-02-13 06:25:41 +00:00
|
|
|
return *m_source_manager_up;
|
2013-03-19 00:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
// 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);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
// 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);
|
2025-02-20 11:13:46 -08:00
|
|
|
if (StreamUP output_up = GetAsyncOutputStream()) {
|
|
|
|
|
output_up->Printf("%d location%s added to breakpoint %d\n",
|
2014-01-27 23:43:24 +00:00
|
|
|
num_new_locations, num_new_locations == 1 ? "" : "s",
|
|
|
|
|
breakpoint->GetID());
|
2025-02-20 11:13:46 -08:00
|
|
|
output_up->Flush();
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
// 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.
|
|
|
|
|
// }
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2019-07-31 12:06:50 +00:00
|
|
|
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);
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function handles events that were broadcast by the process.
|
2025-09-23 14:18:11 -07:00
|
|
|
ProcessSP Debugger::HandleProcessEvent(const EventSP &event_sp) {
|
2014-01-27 23:43:24 +00:00
|
|
|
const uint32_t event_type = event_sp->GetType();
|
2016-08-19 04:21:48 +00:00
|
|
|
ProcessSP process_sp =
|
|
|
|
|
(event_type == Process::eBroadcastBitStructuredData)
|
|
|
|
|
? EventDataStructuredData::GetProcessFromEvent(event_sp.get())
|
|
|
|
|
: Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2025-02-20 11:13:46 -08:00
|
|
|
StreamUP output_stream_up = GetAsyncOutputStream();
|
|
|
|
|
StreamUP error_stream_up = GetAsyncErrorStream();
|
2014-01-27 23:43:24 +00:00
|
|
|
const bool gui_enabled = IsForwardingEvents();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-02-28 18:22:24 +00:00
|
|
|
if (!gui_enabled) {
|
|
|
|
|
bool pop_process_io_handler = false;
|
|
|
|
|
assert(process_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
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;
|
2016-08-19 04:21:48 +00:00
|
|
|
const bool got_structured_data =
|
|
|
|
|
(event_type & Process::eBroadcastBitStructuredData) != 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
if (got_state_changed) {
|
|
|
|
|
StateType event_state =
|
|
|
|
|
Process::ProcessEventData::GetStateFromEvent(event_sp.get());
|
|
|
|
|
state_is_stopped = StateIsStoppedState(event_state, false);
|
2014-02-28 18:22:24 +00:00
|
|
|
}
|
2014-10-21 01:00:42 +00:00
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
// Display running state changes first before any STDIO
|
|
|
|
|
if (got_state_changed && !state_is_stopped) {
|
2023-06-13 20:48:05 -07:00
|
|
|
// This is a public stop which we are going to announce to the user, so
|
2023-05-10 15:40:40 -07:00
|
|
|
// we should force the most relevant frame selection here.
|
2025-02-20 11:13:46 -08:00
|
|
|
Process::HandleProcessStateChangedEvent(event_sp, output_stream_up.get(),
|
2023-05-10 15:40:40 -07:00
|
|
|
SelectMostRelevantFrame,
|
2015-05-27 12:40:32 +00:00
|
|
|
pop_process_io_handler);
|
2014-02-28 18:22:24 +00:00
|
|
|
}
|
2014-10-21 01:00:42 +00:00
|
|
|
|
2019-07-31 12:06:50 +00:00
|
|
|
// Now display STDOUT and STDERR
|
|
|
|
|
FlushProcessOutput(*process_sp, got_stdout || got_state_changed,
|
|
|
|
|
got_stderr || got_state_changed);
|
2014-02-28 18:22:24 +00:00
|
|
|
|
2016-08-19 04:21:48 +00:00
|
|
|
// 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());
|
2025-02-20 11:13:46 -08:00
|
|
|
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_up->PutCString(content_stream.GetString());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2025-02-20 11:13:46 -08:00
|
|
|
} else {
|
|
|
|
|
error_stream_up->Format("Failed to print structured "
|
|
|
|
|
"data with plugin {0}: {1}",
|
|
|
|
|
plugin_sp->GetPluginName(), error);
|
2016-08-19 04:21:48 +00:00
|
|
|
}
|
2014-02-28 18:22:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
|
|
|
|
|
// Now display any stopped state changes after any STDIO
|
|
|
|
|
if (got_state_changed && state_is_stopped) {
|
2025-02-20 11:13:46 -08:00
|
|
|
Process::HandleProcessStateChangedEvent(event_sp, output_stream_up.get(),
|
2023-05-10 15:40:40 -07:00
|
|
|
SelectMostRelevantFrame,
|
2015-05-27 12:40:32 +00:00
|
|
|
pop_process_io_handler);
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 11:13:46 -08:00
|
|
|
output_stream_up->Flush();
|
|
|
|
|
error_stream_up->Flush();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
if (pop_process_io_handler)
|
2014-02-28 18:22:24 +00:00
|
|
|
process_sp->PopProcessIOHandler();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2025-09-23 14:18:11 -07:00
|
|
|
return process_sp;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:18:11 -07:00
|
|
|
ThreadSP Debugger::HandleThreadEvent(const EventSP &event_sp) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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.
|
2014-01-27 23:43:24 +00:00
|
|
|
const uint32_t event_type = event_sp->GetType();
|
2016-11-08 20:36:40 +00:00
|
|
|
const bool stop_format = true;
|
2025-09-23 14:18:11 -07:00
|
|
|
ThreadSP thread_sp;
|
2014-01-27 23:43:24 +00:00
|
|
|
if (event_type == Thread::eBroadcastBitStackChanged ||
|
|
|
|
|
event_type == Thread::eBroadcastBitThreadSelected) {
|
2025-09-23 14:18:11 -07:00
|
|
|
thread_sp = Thread::ThreadEventData::GetThreadFromEvent(event_sp.get());
|
2014-01-27 23:43:24 +00:00
|
|
|
if (thread_sp) {
|
2024-08-23 09:55:47 -07:00
|
|
|
thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format,
|
|
|
|
|
/*show_hidden*/ true);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-23 14:18:11 -07:00
|
|
|
return thread_sp;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-07 21:50:25 +00:00
|
|
|
bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-03-07 21:50:25 +00:00
|
|
|
void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) {
|
2014-01-27 23:43:24 +00:00
|
|
|
m_forward_listener_sp = listener_sp;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-07 21:50:25 +00:00
|
|
|
void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {
|
2014-01-27 23:43:24 +00:00
|
|
|
m_forward_listener_sp.reset();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-13 13:48:41 -07:00
|
|
|
bool Debugger::IsEscapeCodeCapableTTY() {
|
|
|
|
|
if (lldb::LockableStreamFileSP stream_sp = GetOutputStreamSP()) {
|
|
|
|
|
File &file = stream_sp->GetUnlockedFile();
|
|
|
|
|
return file.GetIsInteractive() && file.GetIsRealTerminal() &&
|
|
|
|
|
file.GetIsTerminalWithColors();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
bool Debugger::StatuslineSupported() {
|
2025-05-01 16:40:47 +01:00
|
|
|
// We have trouble with the contol codes on Windows, see
|
|
|
|
|
// https://github.com/llvm/llvm-project/issues/134846.
|
|
|
|
|
#ifndef _WIN32
|
2025-10-13 13:48:41 -07:00
|
|
|
return GetShowStatusline() && IsEscapeCodeCapableTTY();
|
|
|
|
|
#else
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
return false;
|
2025-10-13 13:48:41 -07:00
|
|
|
#endif
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:18:11 -07:00
|
|
|
static bool RequiresFollowChildWorkaround(const Process &process) {
|
|
|
|
|
// FIXME: https://github.com/llvm/llvm-project/issues/160216
|
|
|
|
|
return process.GetFollowForkMode() == eFollowChild;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 11:07:38 +01:00
|
|
|
lldb::thread_result_t Debugger::DefaultEventHandler() {
|
2016-03-07 21:50:25 +00:00
|
|
|
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,
|
2014-01-27 23:43:24 +00:00
|
|
|
Target::eBroadcastBitBreakpointChanged);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-12-01 22:41:27 +00:00
|
|
|
BroadcastEventSpec process_event_spec(
|
2014-01-27 23:43:24 +00:00
|
|
|
broadcaster_class_process,
|
2014-12-01 22:41:27 +00:00
|
|
|
Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT |
|
|
|
|
|
Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-12-01 22:41:27 +00:00
|
|
|
BroadcastEventSpec thread_event_spec(broadcaster_class_thread,
|
2016-07-28 17:32:20 +00:00
|
|
|
Thread::eBroadcastBitStackChanged |
|
|
|
|
|
Thread::eBroadcastBitThreadSelected);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-07-28 17:32:20 +00:00
|
|
|
listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
|
2014-01-27 23:43:24 +00:00
|
|
|
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(
|
2019-02-13 06:25:41 +00:00
|
|
|
m_command_interpreter_up.get(),
|
2014-01-27 23:43:24 +00:00
|
|
|
CommandInterpreter::eBroadcastBitQuitCommandReceived |
|
|
|
|
|
CommandInterpreter::eBroadcastBitAsynchronousOutputData |
|
|
|
|
|
CommandInterpreter::eBroadcastBitAsynchronousErrorData);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2022-03-16 08:30:26 -07:00
|
|
|
listener_sp->StartListeningForEvents(
|
2024-05-09 10:28:23 -07:00
|
|
|
&m_broadcaster, lldb::eBroadcastBitProgress | lldb::eBroadcastBitWarning |
|
|
|
|
|
lldb::eBroadcastBitError |
|
2025-01-17 12:00:31 -08:00
|
|
|
lldb::eBroadcastSymbolChange |
|
|
|
|
|
lldb::eBroadcastBitExternalProgress);
|
2022-03-05 15:45:52 -08:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2014-01-27 23:43:24 +00:00
|
|
|
m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2025-04-11 08:53:49 -07:00
|
|
|
if (StatuslineSupported()) {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
2025-09-23 14:18:11 -07:00
|
|
|
if (!m_statusline) {
|
2025-04-11 08:53:49 -07:00
|
|
|
m_statusline.emplace(*this);
|
2025-09-23 14:18:11 -07:00
|
|
|
m_statusline->Enable(GetSelectedExecutionContextRef());
|
|
|
|
|
}
|
2025-04-11 08:53:49 -07:00
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
bool done = false;
|
|
|
|
|
while (!done) {
|
|
|
|
|
EventSP event_sp;
|
2022-12-04 16:51:25 -08:00
|
|
|
if (listener_sp->GetEvent(event_sp, std::nullopt)) {
|
2025-09-23 14:18:11 -07:00
|
|
|
std::optional<ExecutionContextRef> exe_ctx_ref = std::nullopt;
|
2014-01-27 23:43:24 +00:00
|
|
|
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) {
|
2025-09-23 14:18:11 -07:00
|
|
|
if (ProcessSP process_sp = HandleProcessEvent(event_sp))
|
|
|
|
|
if (!RequiresFollowChildWorkaround(*process_sp))
|
|
|
|
|
exe_ctx_ref = ExecutionContextRef(process_sp.get(),
|
|
|
|
|
/*adopt_selected=*/true);
|
2014-01-27 23:43:24 +00:00
|
|
|
} else if (broadcaster_class == broadcaster_class_target) {
|
|
|
|
|
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
|
|
|
|
|
event_sp.get())) {
|
|
|
|
|
HandleBreakpointEvent(event_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
} else if (broadcaster_class == broadcaster_class_thread) {
|
2025-09-23 14:18:11 -07:00
|
|
|
if (ThreadSP thread_sp = HandleThreadEvent(event_sp))
|
|
|
|
|
if (!RequiresFollowChildWorkaround(*thread_sp->GetProcess()))
|
|
|
|
|
exe_ctx_ref = ExecutionContextRef(thread_sp.get(),
|
|
|
|
|
/*adopt_selected=*/true);
|
2019-02-13 06:25:41 +00:00
|
|
|
} else if (broadcaster == m_command_interpreter_up.get()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
if (event_type &
|
|
|
|
|
CommandInterpreter::eBroadcastBitQuitCommandReceived) {
|
|
|
|
|
done = true;
|
|
|
|
|
} else if (event_type &
|
|
|
|
|
CommandInterpreter::eBroadcastBitAsynchronousErrorData) {
|
2020-01-07 12:13:03 +01:00
|
|
|
const char *data = static_cast<const char *>(
|
2014-01-27 23:43:24 +00:00
|
|
|
EventDataBytes::GetBytesFromEvent(event_sp.get()));
|
|
|
|
|
if (data && data[0]) {
|
2025-02-20 11:13:46 -08:00
|
|
|
StreamUP error_up = GetAsyncErrorStream();
|
|
|
|
|
error_up->PutCString(data);
|
|
|
|
|
error_up->Flush();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
} else if (event_type & CommandInterpreter::
|
|
|
|
|
eBroadcastBitAsynchronousOutputData) {
|
2020-01-07 12:13:03 +01:00
|
|
|
const char *data = static_cast<const char *>(
|
2014-01-27 23:43:24 +00:00
|
|
|
EventDataBytes::GetBytesFromEvent(event_sp.get()));
|
|
|
|
|
if (data && data[0]) {
|
2025-02-20 11:13:46 -08:00
|
|
|
StreamUP output_up = GetAsyncOutputStream();
|
|
|
|
|
output_up->PutCString(data);
|
|
|
|
|
output_up->Flush();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
2022-03-05 15:45:52 -08:00
|
|
|
} else if (broadcaster == &m_broadcaster) {
|
2025-03-27 14:20:43 -07:00
|
|
|
if (event_type & lldb::eBroadcastBitProgress ||
|
|
|
|
|
event_type & lldb::eBroadcastBitExternalProgress)
|
2022-03-05 15:45:52 -08:00
|
|
|
HandleProgressEvent(event_sp);
|
2024-05-09 10:28:23 -07:00
|
|
|
else if (event_type & lldb::eBroadcastBitWarning)
|
2022-03-16 08:30:26 -07:00
|
|
|
HandleDiagnosticEvent(event_sp);
|
2024-05-09 10:28:23 -07:00
|
|
|
else if (event_type & lldb::eBroadcastBitError)
|
2022-03-16 08:30:26 -07:00
|
|
|
HandleDiagnosticEvent(event_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
2014-09-23 18:32:09 +00:00
|
|
|
if (m_forward_listener_sp)
|
2016-03-07 21:50:25 +00:00
|
|
|
m_forward_listener_sp->AddEvent(event_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2025-09-23 14:18:11 -07:00
|
|
|
RedrawStatusline(exe_ctx_ref);
|
2014-10-15 18:03:59 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
|
2025-04-11 08:53:49 -07:00
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_statusline_mutex);
|
|
|
|
|
if (m_statusline)
|
|
|
|
|
m_statusline.reset();
|
|
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
|
[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 15:17:39 +00:00
|
|
|
return {};
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
bool Debugger::StartEventHandlerThread() {
|
2014-09-23 18:32:09 +00:00
|
|
|
if (!m_event_handler_thread.IsJoinable()) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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
|
2014-12-01 22:41:27 +00:00
|
|
|
// eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
|
2018-07-13 11:21:06 +00:00
|
|
|
ConstString full_name("lldb.debugger.event-handler");
|
|
|
|
|
ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString()));
|
2016-03-07 21:50:25 +00:00
|
|
|
listener_sp->StartListeningForEvents(&m_sync_broadcaster,
|
2014-12-01 22:41:27 +00:00
|
|
|
eBroadcastBitEventThreadIsListening);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-02-11 09:05:37 +01:00
|
|
|
llvm::StringRef thread_name =
|
2019-08-02 00:18:44 +00:00
|
|
|
full_name.GetLength() < llvm::get_max_thread_name_length()
|
2020-02-11 09:05:37 +01:00
|
|
|
? full_name.GetStringRef()
|
2019-08-02 00:18:44 +00:00
|
|
|
: "dbg.evt-handler";
|
2018-07-13 11:21:06 +00:00
|
|
|
|
2014-10-24 22:06:29 +00:00
|
|
|
// Use larger 8MB stack for this thread
|
2019-07-05 17:42:08 +00:00
|
|
|
llvm::Expected<HostThread> event_handler_thread =
|
2022-02-21 11:07:38 +01:00
|
|
|
ThreadLauncher::LaunchThread(
|
|
|
|
|
thread_name, [this] { return DefaultEventHandler(); },
|
|
|
|
|
g_debugger_event_thread_stack_bytes);
|
2019-07-05 17:42:08 +00:00
|
|
|
|
|
|
|
|
if (event_handler_thread) {
|
|
|
|
|
m_event_handler_thread = *event_handler_thread;
|
|
|
|
|
} else {
|
2023-07-05 11:26:25 -07:00
|
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Host), event_handler_thread.takeError(),
|
|
|
|
|
"failed to launch host thread: {0}");
|
2019-07-05 17:42:08 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// 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)
|
2014-12-01 22:41:27 +00:00
|
|
|
lldb::EventSP event_sp;
|
2022-12-04 16:51:25 -08:00
|
|
|
listener_sp->GetEvent(event_sp, std::nullopt);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-09-23 18:32:09 +00:00
|
|
|
return m_event_handler_thread.IsJoinable();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
void Debugger::StopEventHandlerThread() {
|
2014-09-23 18:32:09 +00:00
|
|
|
if (m_event_handler_thread.IsJoinable()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
GetCommandInterpreter().BroadcastEvent(
|
|
|
|
|
CommandInterpreter::eBroadcastBitQuitCommandReceived);
|
2014-09-09 20:54:56 +00:00
|
|
|
m_event_handler_thread.Join(nullptr);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 11:07:38 +01:00
|
|
|
lldb::thread_result_t Debugger::IOHandlerThread() {
|
|
|
|
|
RunIOHandlers();
|
|
|
|
|
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 15:17:39 +00:00
|
|
|
return {};
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2022-03-05 15:45:52 -08:00
|
|
|
void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
|
2022-03-14 09:01:53 -07:00
|
|
|
auto *data = ProgressEventData::GetEventDataFromEvent(event_sp.get());
|
2022-03-05 15:45:52 -08:00
|
|
|
if (!data)
|
|
|
|
|
return;
|
|
|
|
|
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
// Make a local copy of the incoming progress report that we'll store.
|
|
|
|
|
ProgressReport progress_report{data->GetID(), data->GetCompleted(),
|
|
|
|
|
data->GetTotal(), data->GetMessage()};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_progress_reports_mutex);
|
2025-10-13 13:48:41 -07:00
|
|
|
|
|
|
|
|
// Do some bookkeeping regardless of whether we're going to display
|
|
|
|
|
// progress reports.
|
2025-05-25 08:21:30 -07:00
|
|
|
auto it = llvm::find_if(m_progress_reports, [&](const auto &report) {
|
|
|
|
|
return report.id == progress_report.id;
|
|
|
|
|
});
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
if (it != m_progress_reports.end()) {
|
|
|
|
|
const bool complete = data->GetCompleted() == data->GetTotal();
|
|
|
|
|
if (complete)
|
|
|
|
|
m_progress_reports.erase(it);
|
|
|
|
|
else
|
|
|
|
|
*it = progress_report;
|
|
|
|
|
} else {
|
|
|
|
|
m_progress_reports.push_back(progress_report);
|
2022-07-05 16:25:23 -07:00
|
|
|
}
|
2025-10-13 13:48:41 -07:00
|
|
|
|
|
|
|
|
// Show progress using Operating System Command (OSC) sequences.
|
|
|
|
|
if (GetShowProgress() && IsEscapeCodeCapableTTY()) {
|
|
|
|
|
if (lldb::LockableStreamFileSP stream_sp = GetOutputStreamSP()) {
|
|
|
|
|
|
|
|
|
|
// Clear progress if this was the last progress event.
|
|
|
|
|
if (m_progress_reports.empty()) {
|
|
|
|
|
stream_sp->Lock() << OSC_PROGRESS_REMOVE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ProgressReport &report = m_progress_reports.back();
|
|
|
|
|
|
|
|
|
|
// Show indeterminate progress.
|
|
|
|
|
if (report.total == UINT64_MAX) {
|
|
|
|
|
stream_sp->Lock() << OSC_PROGRESS_INDETERMINATE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute and show the progress value (0-100).
|
|
|
|
|
const unsigned value = (report.completed / report.total) * 100;
|
|
|
|
|
stream_sp->Lock().Printf(OSC_PROGRESS_SHOW, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-05 15:45:52 -08:00
|
|
|
}
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
}
|
2022-03-05 15:45:52 -08:00
|
|
|
|
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
2025-03-26 14:41:05 -07:00
|
|
|
std::optional<Debugger::ProgressReport>
|
|
|
|
|
Debugger::GetCurrentProgressReport() const {
|
|
|
|
|
std::lock_guard<std::mutex> guard(m_progress_reports_mutex);
|
|
|
|
|
if (m_progress_reports.empty())
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return m_progress_reports.back();
|
2022-03-05 15:45:52 -08:00
|
|
|
}
|
|
|
|
|
|
2022-03-16 08:30:26 -07:00
|
|
|
void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) {
|
|
|
|
|
auto *data = DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
|
|
|
|
|
if (!data)
|
|
|
|
|
return;
|
|
|
|
|
|
2025-02-20 11:13:46 -08:00
|
|
|
data->Dump(GetAsyncErrorStream().get());
|
2022-03-16 08:30:26 -07:00
|
|
|
}
|
|
|
|
|
|
2023-03-15 11:20:20 -07:00
|
|
|
bool Debugger::HasIOHandlerThread() const {
|
2023-05-02 10:31:21 -07:00
|
|
|
return m_io_handler_thread.IsJoinable();
|
2023-03-15 11:20:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HostThread Debugger::SetIOHandlerThread(HostThread &new_thread) {
|
|
|
|
|
HostThread old_host = m_io_handler_thread;
|
|
|
|
|
m_io_handler_thread = new_thread;
|
|
|
|
|
return old_host;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
bool Debugger::StartIOHandlerThread() {
|
2019-07-05 17:42:08 +00:00
|
|
|
if (!m_io_handler_thread.IsJoinable()) {
|
|
|
|
|
llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread(
|
2022-02-21 11:07:38 +01:00
|
|
|
"lldb.debugger.io-handler", [this] { return IOHandlerThread(); },
|
2016-03-02 02:18:18 +00:00
|
|
|
8 * 1024 * 1024); // Use larger 8MB stack for this thread
|
2019-07-05 17:42:08 +00:00
|
|
|
if (io_handler_thread) {
|
|
|
|
|
m_io_handler_thread = *io_handler_thread;
|
|
|
|
|
} else {
|
2023-07-05 11:26:25 -07:00
|
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Host), io_handler_thread.takeError(),
|
|
|
|
|
"failed to launch host thread: {0}");
|
2019-07-05 17:42:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
return m_io_handler_thread.IsJoinable();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-27 23:43:24 +00:00
|
|
|
void Debugger::StopIOHandlerThread() {
|
2014-09-23 18:32:09 +00:00
|
|
|
if (m_io_handler_thread.IsJoinable()) {
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
GetInputFile().Close();
|
2014-09-09 20:54:56 +00:00
|
|
|
m_io_handler_thread.Join(nullptr);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Debugger::JoinIOHandlerThread() {
|
2014-09-23 18:32:09 +00:00
|
|
|
if (HasIOHandlerThread()) {
|
2014-01-27 23:43:24 +00:00
|
|
|
thread_result_t result;
|
2014-09-09 20:54:56 +00:00
|
|
|
m_io_handler_thread.Join(&result);
|
|
|
|
|
m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-15 11:20:20 -07:00
|
|
|
bool Debugger::IsIOHandlerThreadCurrentThread() const {
|
|
|
|
|
if (!HasIOHandlerThread())
|
|
|
|
|
return false;
|
|
|
|
|
return m_io_handler_thread.EqualsThread(Host::GetCurrentThread());
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-09 15:25:59 -08:00
|
|
|
Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!prefer_dummy) {
|
2020-11-09 15:25:59 -08:00
|
|
|
if (TargetSP target = m_target_list.GetSelectedTarget())
|
|
|
|
|
return *target;
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2014-09-23 18:32:09 +00:00
|
|
|
return GetDummyTarget();
|
2014-01-27 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
|
|
|
|
|
Status err;
|
2014-01-27 23:43:24 +00:00
|
|
|
FileSpec repl_executable;
|
|
|
|
|
|
2022-01-05 14:42:21 -08:00
|
|
|
if (language == eLanguageTypeUnknown)
|
|
|
|
|
language = GetREPLLanguage();
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (language == eLanguageTypeUnknown) {
|
2019-08-22 21:45:58 +00:00
|
|
|
LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
|
2015-10-19 23:11:07 +00:00
|
|
|
|
2019-08-22 21:45:58 +00:00
|
|
|
if (auto single_lang = repl_languages.GetSingularLanguage()) {
|
|
|
|
|
language = *single_lang;
|
|
|
|
|
} else if (repl_languages.Empty()) {
|
2024-08-27 10:59:31 -07:00
|
|
|
err = Status::FromErrorString(
|
2014-12-06 01:28:03 +00:00
|
|
|
"LLDB isn't configured with REPL support for any languages.");
|
|
|
|
|
return err;
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2024-08-27 10:59:31 -07:00
|
|
|
err = Status::FromErrorString(
|
2014-12-06 01:28:03 +00:00
|
|
|
"Multiple possible REPL languages. Please specify a language.");
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2014-11-22 01:42:44 +00:00
|
|
|
}
|
2014-01-27 23:43:24 +00:00
|
|
|
|
2015-10-20 00:23:46 +00:00
|
|
|
Target *const target =
|
2015-10-21 19:31:17 +00:00
|
|
|
nullptr; // passing in an empty target means the REPL must create one
|
|
|
|
|
|
2015-10-21 00:28:44 +00:00
|
|
|
REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options));
|
2015-10-20 00:23:46 +00:00
|
|
|
|
|
|
|
|
if (!err.Success()) {
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-20 00:23:46 +00:00
|
|
|
if (!repl_sp) {
|
2024-08-27 10:59:31 -07:00
|
|
|
err = Status::FromErrorStringWithFormat(
|
|
|
|
|
"couldn't find a REPL for %s",
|
|
|
|
|
Language::GetNameForLanguageType(language));
|
2015-10-20 00:23:46 +00:00
|
|
|
return err;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-20 00:23:46 +00:00
|
|
|
repl_sp->SetCompilerOptions(repl_options);
|
|
|
|
|
repl_sp->RunLoop();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-21 19:31:17 +00:00
|
|
|
return err;
|
2015-10-20 00:23:46 +00:00
|
|
|
}
|
2022-04-06 15:48:22 +02:00
|
|
|
|
2024-03-02 19:30:33 -08:00
|
|
|
llvm::ThreadPoolInterface &Debugger::GetThreadPool() {
|
2022-08-15 17:22:14 -07:00
|
|
|
assert(g_thread_pool &&
|
|
|
|
|
"Debugger::GetThreadPool called before Debugger::Initialize");
|
2022-04-06 15:48:22 +02:00
|
|
|
return *g_thread_pool;
|
|
|
|
|
}
|