diff options
author | David Spickett <david.spickett@linaro.org> | 2025-01-30 14:03:01 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-30 14:03:01 +0000 |
commit | 0caba6c8dc2f6f0da61f30c169f59d40591cddbc (patch) | |
tree | 13f435118e3d8168f98c9b98e8059e039e2501ac /lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | |
parent | fe1f6b4855ea5cb164524e137ecd891cf0734838 (diff) | |
download | llvm-0caba6c8dc2f6f0da61f30c169f59d40591cddbc.zip llvm-0caba6c8dc2f6f0da61f30c169f59d40591cddbc.tar.gz llvm-0caba6c8dc2f6f0da61f30c169f59d40591cddbc.tar.bz2 |
Reland "[lldb] Implement basic support for reverse-continue" (#123906)" (#123945)
This reverts commit 22561cfb443267905d4190f0e2a738e6b412457f and fixes
b7b9ccf44988edf49886743ae5c3cf4184db211f (#112079).
The problem is that x86_64 and Arm 32-bit have memory regions above the
stack that are readable but not writeable. First Arm:
```
(lldb) memory region --all
<...>
[0x00000000fffcf000-0x00000000ffff0000) rw- [stack]
[0x00000000ffff0000-0x00000000ffff1000) r-x [vectors]
[0x00000000ffff1000-0xffffffffffffffff) ---
```
Then x86_64:
```
$ cat /proc/self/maps
<...>
7ffdcd148000-7ffdcd16a000 rw-p 00000000 00:00 0 [stack]
7ffdcd193000-7ffdcd196000 r--p 00000000 00:00 0 [vvar]
7ffdcd196000-7ffdcd197000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
```
Compare this to AArch64 where the test did pass:
```
$ cat /proc/self/maps
<...>
ffffb87dc000-ffffb87dd000 r--p 00000000 00:00 0 [vvar]
ffffb87dd000-ffffb87de000 r-xp 00000000 00:00 0 [vdso]
ffffb87de000-ffffb87e0000 r--p 0002a000 00:3c 76927217 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
ffffb87e0000-ffffb87e2000 rw-p 0002c000 00:3c 76927217 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
fffff4216000-fffff4237000 rw-p 00000000 00:00 0 [stack]
```
To solve this, look up the memory region of the stack pointer (using
https://lldb.llvm.org/resources/lldbgdbremote.html#qmemoryregioninfo-addr)
and constrain the read to within that region. Since we know the stack is
all readable and writeable.
I have also added skipIfRemote to the tests, since getting them working
in that context is too complex to be worth it.
Memory write failures now display the range they tried to write, and
register write errors will show the name of the register where possible.
The patch also includes a workaround for a an issue where the test code
could mistake an `x` response that happens to begin with an `O` for an
output packet (stdout). This workaround will not be necessary one we
start using the [new
implementation](https://discourse.llvm.org/t/rfc-fixing-incompatibilties-of-the-x-packet-w-r-t-gdb/84288)
of the `x` packet.
---------
Co-authored-by: Pavel Labath <pavel@labath.sk>
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 98 |
1 files changed, 85 insertions, 13 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 538c868..fa511af 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -169,6 +169,8 @@ public: } }; +std::chrono::seconds ResumeTimeout() { return std::chrono::seconds(5); } + } // namespace static PluginProperties &GetGlobalPluginProperties() { @@ -1180,10 +1182,16 @@ Status ProcessGDBRemote::WillResume() { return Status(); } -Status ProcessGDBRemote::DoResume() { +bool ProcessGDBRemote::SupportsReverseDirection() { + return m_gdb_comm.GetReverseStepSupported() || + m_gdb_comm.GetReverseContinueSupported(); +} + +Status ProcessGDBRemote::DoResume(RunDirection direction) { Status error; Log *log = GetLog(GDBRLog::Process); - LLDB_LOGF(log, "ProcessGDBRemote::Resume()"); + LLDB_LOGF(log, "ProcessGDBRemote::Resume(%s)", + direction == RunDirection::eRunForward ? "" : "reverse"); ListenerSP listener_sp( Listener::MakeListener("gdb-remote.resume-packet-sent")); @@ -1197,12 +1205,24 @@ Status ProcessGDBRemote::DoResume() { StreamString continue_packet; bool continue_packet_error = false; - if (m_gdb_comm.HasAnyVContSupport()) { + // Number of threads continuing with "c", i.e. continuing without a signal + // to deliver. + const size_t num_continue_c_tids = m_continue_c_tids.size(); + // Number of threads continuing with "C", i.e. continuing with a signal to + // deliver. + const size_t num_continue_C_tids = m_continue_C_tids.size(); + // Number of threads continuing with "s", i.e. single-stepping. + const size_t num_continue_s_tids = m_continue_s_tids.size(); + // Number of threads continuing with "S", i.e. single-stepping with a signal + // to deliver. + const size_t num_continue_S_tids = m_continue_S_tids.size(); + if (direction == RunDirection::eRunForward && + m_gdb_comm.HasAnyVContSupport()) { std::string pid_prefix; if (m_gdb_comm.GetMultiprocessSupported()) pid_prefix = llvm::formatv("p{0:x-}.", GetID()); - if (m_continue_c_tids.size() == num_threads || + if (num_continue_c_tids == num_threads || (m_continue_c_tids.empty() && m_continue_C_tids.empty() && m_continue_s_tids.empty() && m_continue_S_tids.empty())) { // All threads are continuing @@ -1265,14 +1285,10 @@ Status ProcessGDBRemote::DoResume() { } else continue_packet_error = true; - if (continue_packet_error) { + if (direction == RunDirection::eRunForward && continue_packet_error) { // Either no vCont support, or we tried to use part of the vCont packet // that wasn't supported by the remote GDB server. We need to try and - // make a simple packet that can do our continue - const size_t num_continue_c_tids = m_continue_c_tids.size(); - const size_t num_continue_C_tids = m_continue_C_tids.size(); - const size_t num_continue_s_tids = m_continue_s_tids.size(); - const size_t num_continue_S_tids = m_continue_S_tids.size(); + // make a simple packet that can do our continue. if (num_continue_c_tids > 0) { if (num_continue_c_tids == num_threads) { // All threads are resuming... @@ -1363,9 +1379,59 @@ Status ProcessGDBRemote::DoResume() { } } + if (direction == RunDirection::eRunReverse) { + if (num_continue_s_tids > 0 || num_continue_S_tids > 0) { + if (!m_gdb_comm.GetReverseStepSupported()) { + LLDB_LOGF(log, "ProcessGDBRemote::DoResume: target does not " + "support reverse-stepping"); + return Status::FromErrorString( + "target does not support reverse-stepping"); + } + + if (num_continue_S_tids > 0) { + LLDB_LOGF( + log, + "ProcessGDBRemote::DoResume: Signals not supported in reverse"); + return Status::FromErrorString( + "can't deliver signals while running in reverse"); + } + + if (num_continue_s_tids > 1) { + LLDB_LOGF(log, "ProcessGDBRemote::DoResume: can't step multiple " + "threads in reverse"); + return Status::FromErrorString( + "can't step multiple threads while reverse-stepping"); + } + + m_gdb_comm.SetCurrentThreadForRun(m_continue_s_tids.front()); + continue_packet.PutCString("bs"); + } else { + if (!m_gdb_comm.GetReverseContinueSupported()) { + LLDB_LOGF(log, "ProcessGDBRemote::DoResume: target does not " + "support reverse-continue"); + return Status::FromErrorString( + "target does not support reverse-continue"); + } + + if (num_continue_C_tids > 0) { + LLDB_LOGF( + log, + "ProcessGDBRemote::DoResume: Signals not supported in reverse"); + return Status::FromErrorString( + "can't deliver signals while running in reverse"); + } + + // All threads continue whether requested or not --- + // we can't change how threads ran in the past. + continue_packet.PutCString("bc"); + } + + continue_packet_error = false; + } + if (continue_packet_error) { - error = - Status::FromErrorString("can't make continue packet for this resume"); + return Status::FromErrorString( + "can't make continue packet for this resume"); } else { EventSP event_sp; if (!m_async_thread.IsJoinable()) { @@ -1380,7 +1446,7 @@ Status ProcessGDBRemote::DoResume() { std::make_shared<EventDataBytes>(continue_packet.GetString()); m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp); - if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) { + if (!listener_sp->GetEvent(event_sp, ResumeTimeout())) { error = Status::FromErrorString("Resume timed out."); LLDB_LOGF(log, "ProcessGDBRemote::DoResume: Resume timed out."); } else if (event_sp->BroadcasterIs(&m_async_broadcaster)) { @@ -1863,6 +1929,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( *thread_sp, description.c_str())); handled = true; + } else if (reason == "history boundary") { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonHistoryBoundary( + *thread_sp, description.c_str())); + handled = true; } else if (reason == "exec") { did_exec = true; thread_sp->SetStopInfo( @@ -2318,6 +2388,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { description = std::string(ostr.GetString()); } else if (key.compare("swbreak") == 0 || key.compare("hwbreak") == 0) { reason = "breakpoint"; + } else if (key.compare("replaylog") == 0) { + reason = "history boundary"; } else if (key.compare("library") == 0) { auto error = LoadModules(); if (error) { |