[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 15:23:27 +08:00
|
|
|
//===-- GDBRemoteCommunicationServerLLGS.cpp ------------------------------===//
|
2015-02-11 18:29:30 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08: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
|
2015-02-11 18:29:30 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-05-26 18:19:37 +08:00
|
|
|
#include <cerrno>
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
#include "lldb/Host/Config.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
#include <cstring>
|
2021-02-19 23:57:59 +08:00
|
|
|
#include <limits>
|
2015-02-11 18:29:30 +08:00
|
|
|
#include <thread>
|
|
|
|
|
2020-10-09 17:23:17 +08:00
|
|
|
#include "GDBRemoteCommunicationServerLLGS.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
#include "lldb/Host/ConnectionFileDescriptor.h"
|
|
|
|
#include "lldb/Host/Debug.h"
|
|
|
|
#include "lldb/Host/File.h"
|
Move FileAction, ProcessInfo and ProcessLaunchInfo from Target to Host
Summary:
These classes describe the details of the process we are about to
launch, and so they are naturally used by the launching code in the Host
module. Previously they were present in Target because that is the most
important (but by far not the only) user of the launching code.
Since the launching code has other customers, must of which do not care
about Targets, it makes sense to move these classes to the Host layer,
next to the launching code.
This move reduces the number of times that Target is included from host
to 8 (it used to be 14).
Reviewers: zturner, clayborg, jingham, davide, teemperor
Subscribers: emaste, mgorny, lldb-commits
Differential Revision: https://reviews.llvm.org/D56602
llvm-svn: 353047
2019-02-04 22:28:08 +08:00
|
|
|
#include "lldb/Host/FileAction.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
#include "lldb/Host/FileSystem.h"
|
|
|
|
#include "lldb/Host/Host.h"
|
|
|
|
#include "lldb/Host/HostInfo.h"
|
2017-07-18 21:14:01 +08:00
|
|
|
#include "lldb/Host/PosixApi.h"
|
2021-10-22 23:42:23 +08:00
|
|
|
#include "lldb/Host/Socket.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
#include "lldb/Host/common/NativeProcessProtocol.h"
|
2016-08-08 20:54:36 +08:00
|
|
|
#include "lldb/Host/common/NativeRegisterContext.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
#include "lldb/Host/common/NativeThreadProtocol.h"
|
2016-08-08 20:54:36 +08:00
|
|
|
#include "lldb/Target/MemoryRegionInfo.h"
|
2018-04-18 02:53:35 +08:00
|
|
|
#include "lldb/Utility/Args.h"
|
2017-03-04 09:30:05 +08:00
|
|
|
#include "lldb/Utility/DataBuffer.h"
|
2017-02-15 03:06:07 +08:00
|
|
|
#include "lldb/Utility/Endian.h"
|
2020-10-09 17:23:17 +08:00
|
|
|
#include "lldb/Utility/GDBRemote.h"
|
2015-11-27 21:33:29 +08:00
|
|
|
#include "lldb/Utility/LLDBAssert.h"
|
2022-02-03 20:26:10 +08:00
|
|
|
#include "lldb/Utility/LLDBLog.h"
|
2017-03-04 04:56:28 +08:00
|
|
|
#include "lldb/Utility/Log.h"
|
2018-08-07 19:07:21 +08:00
|
|
|
#include "lldb/Utility/RegisterValue.h"
|
|
|
|
#include "lldb/Utility/State.h"
|
2017-02-03 05:39:50 +08:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
2020-10-09 17:23:17 +08:00
|
|
|
#include "lldb/Utility/UnimplementedError.h"
|
2021-10-22 23:42:23 +08:00
|
|
|
#include "lldb/Utility/UriParser.h"
|
2016-08-08 20:54:36 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2019-10-03 02:02:23 +08:00
|
|
|
#include "llvm/Support/JSON.h"
|
2016-08-08 20:54:36 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
#include "ProcessGDBRemote.h"
|
|
|
|
#include "ProcessGDBRemoteLog.h"
|
2018-03-21 00:14:00 +08:00
|
|
|
#include "lldb/Utility/StringExtractorGDBRemote.h"
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
2015-03-31 17:52:22 +08:00
|
|
|
using namespace lldb_private::process_gdb_remote;
|
2015-06-19 04:43:56 +08:00
|
|
|
using namespace llvm;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// GDBRemote Errors
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
enum GDBRemoteServerError {
|
|
|
|
// Set to the first unused error number in literal form below
|
|
|
|
eErrorFirst = 29,
|
|
|
|
eErrorNoProcess = eErrorFirst,
|
|
|
|
eErrorResume,
|
|
|
|
eErrorExitStatus
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// GDBRemoteCommunicationServerLLGS constructor
|
2016-06-29 21:58:27 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
|
2017-07-07 19:02:19 +08:00
|
|
|
MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory)
|
2022-09-07 23:13:57 +08:00
|
|
|
: GDBRemoteCommunicationServerCommon(), m_mainloop(mainloop),
|
|
|
|
m_process_factory(process_factory), m_current_process(nullptr),
|
|
|
|
m_continue_process(nullptr), m_stdio_communication() {
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterPacketHandlers();
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_C);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_c);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_D);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_H);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_I);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_interrupt,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_interrupt);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_m,
|
2015-10-14 20:59:37 +08:00
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_M);
|
2020-10-09 19:59:50 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle__M);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle__m);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_p);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_P);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qC);
|
2022-06-20 17:34:23 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_T,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_T);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qfThreadInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo);
|
2015-06-19 04:43:56 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir);
|
2021-04-13 22:07:28 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qRegisterInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir);
|
2015-10-14 20:59:37 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qsThreadInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo);
|
2015-07-16 22:14:35 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_jThreadsInfo,
|
2015-02-11 18:29:30 +08:00
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
|
|
|
|
RegisterMemberFunctionHandler(
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_qXfer,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qXfer);
|
2015-03-31 17:52:22 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s,
|
2015-02-11 18:29:30 +08:00
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_s);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_stop_reason,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ?
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vAttach,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vAttach);
|
2021-01-14 16:24:31 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vAttachWait,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
|
2021-01-25 04:29:59 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vCont,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vCont);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vCont_actions,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vCont_actions);
|
2021-08-12 04:58:11 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vRun,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vRun);
|
2015-03-31 17:52:22 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_x,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
|
2016-07-21 22:54:03 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_Z);
|
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_z);
|
2017-02-24 17:29:14 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QPassSignals,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-05-26 19:46:27 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
2020-11-10 05:36:26 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported);
|
2017-05-26 19:46:27 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
2020-11-10 05:36:26 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStart,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart);
|
2017-05-26 19:46:27 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
2020-11-10 05:36:26 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStop,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop);
|
2017-05-26 19:46:27 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
2020-11-10 05:36:26 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetState,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState);
|
2017-05-26 19:46:27 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
2020-11-10 05:36:26 +08:00
|
|
|
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData);
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2019-05-30 15:25:22 +08:00
|
|
|
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_g);
|
|
|
|
|
2021-02-19 23:57:59 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qMemTags,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qMemTags);
|
|
|
|
|
2021-03-31 21:02:34 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QMemTags,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QMemTags);
|
|
|
|
|
2016-07-21 22:54:03 +08:00
|
|
|
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
|
2017-05-12 12:51:55 +08:00
|
|
|
[this](StringExtractorGDBRemote packet, Status &error,
|
2016-07-21 22:54:03 +08:00
|
|
|
bool &interrupt, bool &quit) {
|
|
|
|
quit = true;
|
2016-05-18 09:59:10 +08:00
|
|
|
return this->Handle_k(packet);
|
[NFC] Darwin llgs support from Week of Code
This code represents the Week of Code work I did on bringing up
lldb-server LLGS support for Darwin. It does not include the
Xcode project changes needed, as we don't want to throw that switch
until more support is implemented (i.e. this change is inert, no
build systems use it yet. I've verified on Ubuntu 16.04, macOS
Xcode and macOS cmake builds).
This change does some minimal refactoring of code that is shared
with the Linux LLGS portion, moving it from NativeProcessLinux into
NativeProcessProtocol. That code is also used by NativeProcessDarwin.
Current state on Darwin:
* Process launching is implemented. (Attach is not).
Launching on devices has not yet been tested (FBS/BKS might
need a bit of work).
* Inferior waitpid monitoring and communication of exit status
via MainLoop callback is implemented.
* Memory read/write, breakpoints, thread register context, etc.
are not yet implemented. This impacts process stop/resume, as
the initial launch suspended immediately starts the process
up and running because it doesn't know it is supposed to remain
stopped.
* I implemented the equivalent of MachThreadList as
NativeThreadListDarwin, in anticipation that we might want to
factor out common parts into NativeThreadList{Protocol} and share
some code here. After writing it, though, the fallout from merging
Mach Task/Process into a single concept plus some other minor
changes makes the whole NativeThreadListDarwin concept nothing more
than dead weight. I am likely going to get rid of this class and
just manage it directly in NativeProcessDarwin, much like I did
for NativeProcessLinux.
* There is a stub-out call for starting a STDIO thread. That will
go away and adopt the MainLoop pselect-based IOObject reading.
I am developing the fully-integrated changes in the following repo,
which contains the necessary Xcode bits and the glue that enables
lldb-debugserver on a macOS system:
https://github.com/tfiala/lldb/tree/llgs-darwin
This change also breaks out a few of the lldb-server tests into
their own directory, and adds some $qHostInfo tests (not sure why
I didn't write those tests back when I initially implemented that
on the Linux side).
llvm-svn: 280604
2016-09-04 08:18:56 +08:00
|
|
|
});
|
2021-04-26 19:47:02 +08:00
|
|
|
|
2022-06-12 14:55:41 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vKill,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vKill);
|
|
|
|
|
2021-04-26 19:47:02 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
|
2022-04-12 22:21:09 +08:00
|
|
|
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_QNonStop,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_QNonStop);
|
2022-06-30 03:48:10 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vStdio,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vStdio);
|
2022-04-12 22:21:09 +08:00
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vStopped,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vStopped);
|
|
|
|
RegisterMemberFunctionHandler(
|
|
|
|
StringExtractorGDBRemote::eServerPacketType_vCtrlC,
|
|
|
|
&GDBRemoteCommunicationServerLLGS::Handle_vCtrlC);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2017-12-18 22:31:39 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &info) {
|
|
|
|
m_process_launch_info = info;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!m_process_launch_info.GetArguments().GetArgumentCount())
|
2017-05-12 12:51:55 +08:00
|
|
|
return Status("%s: no process command line specified to launch",
|
|
|
|
__FUNCTION__);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const bool should_forward_stdio =
|
|
|
|
m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr ||
|
|
|
|
m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
|
|
|
|
m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr;
|
|
|
|
m_process_launch_info.SetLaunchInSeparateProcessGroup(true);
|
|
|
|
m_process_launch_info.GetFlags().Set(eLaunchFlagDebug);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2019-01-08 19:55:19 +08:00
|
|
|
if (should_forward_stdio) {
|
2019-08-14 07:50:54 +08:00
|
|
|
// Temporarily relax the following for Windows until we can take advantage
|
2019-08-21 12:55:56 +08:00
|
|
|
// of the recently added pty support. This doesn't really affect the use of
|
2019-08-14 07:50:54 +08:00
|
|
|
// lldb-server on Windows.
|
|
|
|
#if !defined(_WIN32)
|
2019-01-08 19:55:19 +08:00
|
|
|
if (llvm::Error Err = m_process_launch_info.SetUpPtyRedirection())
|
|
|
|
return Status(std::move(Err));
|
2019-08-14 07:50:54 +08:00
|
|
|
#endif
|
2019-01-08 19:55:19 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex);
|
2021-04-13 23:32:23 +08:00
|
|
|
assert(m_debugged_processes.empty() && "lldb-server creating debugged "
|
|
|
|
"process but one already exists");
|
2017-07-07 19:02:19 +08:00
|
|
|
auto process_or =
|
|
|
|
m_process_factory.Launch(m_process_launch_info, *this, m_mainloop);
|
2017-12-14 22:56:29 +08:00
|
|
|
if (!process_or)
|
|
|
|
return Status(process_or.takeError());
|
2021-04-13 23:32:23 +08:00
|
|
|
m_continue_process = m_current_process = process_or->get();
|
2022-07-13 23:33:28 +08:00
|
|
|
m_debugged_processes.emplace(
|
|
|
|
m_current_process->GetID(),
|
|
|
|
DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}});
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2021-04-09 06:59:22 +08:00
|
|
|
SetEnabledExtensions(*m_current_process);
|
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as
|
|
|
|
// needed. llgs local-process debugging may specify PTY paths, which will
|
|
|
|
// make these file actions non-null process launch -i/e/o will also make
|
|
|
|
// these file actions non-null nullptr means that the traffic is expected to
|
|
|
|
// flow over gdb-remote protocol
|
2015-02-11 18:29:30 +08:00
|
|
|
if (should_forward_stdio) {
|
|
|
|
// nullptr means it's not redirected to file or pty (in case of LLGS local)
|
2018-05-01 00:49:04 +08:00
|
|
|
// at least one of stdio will be transferred pty<->gdb-remote we need to
|
2021-11-10 22:50:14 +08:00
|
|
|
// give the pty primary handle to this object to read and/or write
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log,
|
|
|
|
"pid = {0}: setting up stdout/stderr redirection via $O "
|
|
|
|
"gdb-remote commands",
|
2021-04-13 23:32:23 +08:00
|
|
|
m_current_process->GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-29 20:33:31 +08:00
|
|
|
// Setup stdout/stderr mapping from inferior to $O
|
2021-04-13 23:32:23 +08:00
|
|
|
auto terminal_fd = m_current_process->GetTerminalFileDescriptor();
|
2015-07-29 20:33:31 +08:00
|
|
|
if (terminal_fd >= 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"ProcessGDBRemoteCommunicationServerLLGS::%s setting "
|
|
|
|
"inferior STDIO fd to %d",
|
|
|
|
__FUNCTION__, terminal_fd);
|
2017-07-07 19:02:19 +08:00
|
|
|
Status status = SetSTDIOFileDescriptor(terminal_fd);
|
|
|
|
if (status.Fail())
|
|
|
|
return status;
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
|
|
|
|
"inferior STDIO since terminal fd reported as %d",
|
|
|
|
__FUNCTION__, terminal_fd);
|
2015-07-29 20:33:31 +08:00
|
|
|
}
|
|
|
|
} else {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log,
|
|
|
|
"pid = {0} skipping stdout/stderr redirection via $O: inferior "
|
|
|
|
"will communicate over client-provided file descriptors",
|
2021-04-13 23:32:23 +08:00
|
|
|
m_current_process->GetID());
|
2015-07-29 20:33:31 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-29 20:33:31 +08:00
|
|
|
printf("Launched '%s' as process %" PRIu64 "...\n",
|
|
|
|
m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
|
2021-04-13 23:32:23 +08:00
|
|
|
m_current_process->GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-07-07 19:02:19 +08:00
|
|
|
return Status();
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64,
|
|
|
|
__FUNCTION__, pid);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-29 20:33:31 +08:00
|
|
|
// Before we try to attach, make sure we aren't already monitoring something
|
2016-09-07 04:57:50 +08:00
|
|
|
// else.
|
2021-04-13 23:32:23 +08:00
|
|
|
if (!m_debugged_processes.empty())
|
2018-04-11 21:30:54 +08:00
|
|
|
return Status("cannot attach to process %" PRIu64
|
2017-05-12 12:51:55 +08:00
|
|
|
" when another process with pid %" PRIu64
|
|
|
|
" is being debugged.",
|
2021-04-13 23:32:23 +08:00
|
|
|
pid, m_current_process->GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-29 20:33:31 +08:00
|
|
|
// Try to attach.
|
2017-07-07 19:02:19 +08:00
|
|
|
auto process_or = m_process_factory.Attach(pid, *this, m_mainloop);
|
|
|
|
if (!process_or) {
|
|
|
|
Status status(process_or.takeError());
|
2021-09-07 23:48:35 +08:00
|
|
|
llvm::errs() << llvm::formatv("failed to attach to process {0}: {1}\n", pid,
|
2017-07-07 19:02:19 +08:00
|
|
|
status);
|
|
|
|
return status;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2021-04-13 23:32:23 +08:00
|
|
|
m_continue_process = m_current_process = process_or->get();
|
2022-07-13 23:33:28 +08:00
|
|
|
m_debugged_processes.emplace(
|
|
|
|
m_current_process->GetID(),
|
|
|
|
DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}});
|
2021-04-09 06:59:22 +08:00
|
|
|
SetEnabledExtensions(*m_current_process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2015-03-31 17:52:22 +08:00
|
|
|
// Setup stdout/stderr mapping from inferior.
|
2021-04-13 23:32:23 +08:00
|
|
|
auto terminal_fd = m_current_process->GetTerminalFileDescriptor();
|
2015-02-11 18:29:30 +08:00
|
|
|
if (terminal_fd >= 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"ProcessGDBRemoteCommunicationServerLLGS::%s setting "
|
|
|
|
"inferior STDIO fd to %d",
|
|
|
|
__FUNCTION__, terminal_fd);
|
2017-07-07 19:02:19 +08:00
|
|
|
Status status = SetSTDIOFileDescriptor(terminal_fd);
|
|
|
|
if (status.Fail())
|
|
|
|
return status;
|
2015-02-11 18:29:30 +08:00
|
|
|
} else {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
|
|
|
|
"inferior STDIO since terminal fd reported as %d",
|
|
|
|
__FUNCTION__, terminal_fd);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
printf("Attached to process %" PRIu64 "...\n", pid);
|
2017-07-07 19:02:19 +08:00
|
|
|
return Status();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2021-01-14 16:24:31 +08:00
|
|
|
Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
|
2021-01-25 04:29:59 +08:00
|
|
|
llvm::StringRef process_name, bool include_existing) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-01-14 16:24:31 +08:00
|
|
|
|
|
|
|
std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
|
|
|
|
|
|
|
|
// Create the matcher used to search the process list.
|
|
|
|
ProcessInstanceInfoList exclusion_list;
|
|
|
|
ProcessInstanceInfoMatch match_info;
|
|
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile(
|
2021-01-25 04:29:59 +08:00
|
|
|
process_name, llvm::sys::path::Style::native);
|
|
|
|
match_info.SetNameMatchType(NameMatch::Equals);
|
2021-01-14 16:24:31 +08:00
|
|
|
|
2021-01-25 04:29:59 +08:00
|
|
|
if (include_existing) {
|
|
|
|
LLDB_LOG(log, "including existing processes in search");
|
|
|
|
} else {
|
|
|
|
// Create the excluded process list before polling begins.
|
|
|
|
Host::FindProcesses(match_info, exclusion_list);
|
|
|
|
LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
|
|
|
|
exclusion_list.size());
|
|
|
|
}
|
2021-01-14 16:24:31 +08:00
|
|
|
|
|
|
|
LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
|
|
|
|
|
|
|
|
auto is_in_exclusion_list =
|
|
|
|
[&exclusion_list](const ProcessInstanceInfo &info) {
|
|
|
|
for (auto &excluded : exclusion_list) {
|
|
|
|
if (excluded.GetProcessID() == info.GetProcessID())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
ProcessInstanceInfoList loop_process_list;
|
|
|
|
while (true) {
|
|
|
|
loop_process_list.clear();
|
|
|
|
if (Host::FindProcesses(match_info, loop_process_list)) {
|
|
|
|
// Remove all the elements that are in the exclusion list.
|
|
|
|
llvm::erase_if(loop_process_list, is_in_exclusion_list);
|
|
|
|
|
|
|
|
// One match! We found the desired process.
|
|
|
|
if (loop_process_list.size() == 1) {
|
|
|
|
auto matching_process_pid = loop_process_list[0].GetProcessID();
|
|
|
|
LLDB_LOG(log, "found pid {0}", matching_process_pid);
|
|
|
|
return AttachToProcess(matching_process_pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Multiple matches! Return an error reporting the PIDs we found.
|
|
|
|
if (loop_process_list.size() > 1) {
|
|
|
|
StreamString error_stream;
|
|
|
|
error_stream.Format(
|
|
|
|
"Multiple executables with name: '{0}' found. Pids: ",
|
|
|
|
process_name);
|
|
|
|
for (size_t i = 0; i < loop_process_list.size() - 1; ++i) {
|
|
|
|
error_stream.Format("{0}, ", loop_process_list[i].GetProcessID());
|
|
|
|
}
|
|
|
|
error_stream.Format("{0}.", loop_process_list.back().GetProcessID());
|
|
|
|
|
|
|
|
Status error;
|
|
|
|
error.SetErrorString(error_stream.GetString());
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// No matches, we have not found the process. Sleep until next poll.
|
|
|
|
LLDB_LOG(log, "sleep {0} seconds", polling_interval);
|
|
|
|
std::this_thread::sleep_for(polling_interval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
|
|
|
|
NativeProcessProtocol *process) {
|
|
|
|
assert(process && "process cannot be NULL");
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (log) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s called with "
|
|
|
|
"NativeProcessProtocol pid %" PRIu64 ", current state: %s",
|
|
|
|
__FUNCTION__, process->GetID(),
|
|
|
|
StateAsCString(process->GetState()));
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::SendWResponse(
|
2015-03-31 17:52:22 +08:00
|
|
|
NativeProcessProtocol *process) {
|
2015-02-11 18:29:30 +08:00
|
|
|
assert(process && "process cannot be NULL");
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// send W notification
|
2017-06-19 20:47:50 +08:00
|
|
|
auto wait_status = process->GetExitStatus();
|
|
|
|
if (!wait_status) {
|
|
|
|
LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status",
|
|
|
|
process->GetID());
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
StreamGDBRemote response;
|
|
|
|
response.PutChar('E');
|
|
|
|
response.PutHex8(GDBRemoteServerError::eErrorExitStatus);
|
|
|
|
return SendPacketNoLock(response.GetString());
|
2017-06-19 20:47:50 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-06-19 20:47:50 +08:00
|
|
|
LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
|
|
|
|
*wait_status);
|
2015-07-16 22:14:35 +08:00
|
|
|
|
2022-06-12 14:55:41 +08:00
|
|
|
// If the process was killed through vKill, return "OK".
|
2022-07-13 23:33:28 +08:00
|
|
|
if (bool(m_debugged_processes.at(process->GetID()).flags &
|
|
|
|
DebuggedProcess::Flag::vkilled))
|
2022-06-12 14:55:41 +08:00
|
|
|
return SendOKResponse();
|
|
|
|
|
2017-06-19 20:47:50 +08:00
|
|
|
StreamGDBRemote response;
|
|
|
|
response.Format("{0:g}", *wait_status);
|
2022-07-13 23:33:28 +08:00
|
|
|
if (bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::multiprocess))
|
2022-06-06 21:21:12 +08:00
|
|
|
response.Format(";process:{0:x-}", process->GetID());
|
2022-04-12 22:21:09 +08:00
|
|
|
if (m_non_stop)
|
|
|
|
return SendNotificationPacketNoLock("Stop", m_stop_notification_queue,
|
|
|
|
response.GetString());
|
2017-06-19 20:47:50 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
static void AppendHexValue(StreamString &response, const uint8_t *buf,
|
|
|
|
uint32_t buf_size, bool swap) {
|
|
|
|
int64_t i;
|
|
|
|
if (swap) {
|
|
|
|
for (i = buf_size - 1; i >= 0; i--)
|
2015-10-14 20:59:37 +08:00
|
|
|
response.PutHex8(buf[i]);
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2015-02-11 18:29:30 +08:00
|
|
|
for (i = 0; i < buf_size; i++)
|
2015-10-14 20:59:37 +08:00
|
|
|
response.PutHex8(buf[i]);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
static llvm::StringRef GetEncodingNameOrEmpty(const RegisterInfo ®_info) {
|
|
|
|
switch (reg_info.encoding) {
|
|
|
|
case eEncodingUint:
|
|
|
|
return "uint";
|
|
|
|
case eEncodingSint:
|
|
|
|
return "sint";
|
|
|
|
case eEncodingIEEE754:
|
|
|
|
return "ieee754";
|
|
|
|
case eEncodingVector:
|
|
|
|
return "vector";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static llvm::StringRef GetFormatNameOrEmpty(const RegisterInfo ®_info) {
|
|
|
|
switch (reg_info.format) {
|
|
|
|
case eFormatBinary:
|
|
|
|
return "binary";
|
|
|
|
case eFormatDecimal:
|
|
|
|
return "decimal";
|
|
|
|
case eFormatHex:
|
|
|
|
return "hex";
|
|
|
|
case eFormatFloat:
|
|
|
|
return "float";
|
|
|
|
case eFormatVectorOfSInt8:
|
|
|
|
return "vector-sint8";
|
|
|
|
case eFormatVectorOfUInt8:
|
|
|
|
return "vector-uint8";
|
|
|
|
case eFormatVectorOfSInt16:
|
|
|
|
return "vector-sint16";
|
|
|
|
case eFormatVectorOfUInt16:
|
|
|
|
return "vector-uint16";
|
|
|
|
case eFormatVectorOfSInt32:
|
|
|
|
return "vector-sint32";
|
|
|
|
case eFormatVectorOfUInt32:
|
|
|
|
return "vector-uint32";
|
|
|
|
case eFormatVectorOfFloat32:
|
|
|
|
return "vector-float32";
|
|
|
|
case eFormatVectorOfUInt64:
|
|
|
|
return "vector-uint64";
|
|
|
|
case eFormatVectorOfUInt128:
|
|
|
|
return "vector-uint128";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo ®_info) {
|
|
|
|
switch (reg_info.kinds[RegisterKind::eRegisterKindGeneric]) {
|
|
|
|
case LLDB_REGNUM_GENERIC_PC:
|
|
|
|
return "pc";
|
|
|
|
case LLDB_REGNUM_GENERIC_SP:
|
|
|
|
return "sp";
|
|
|
|
case LLDB_REGNUM_GENERIC_FP:
|
|
|
|
return "fp";
|
|
|
|
case LLDB_REGNUM_GENERIC_RA:
|
|
|
|
return "ra";
|
|
|
|
case LLDB_REGNUM_GENERIC_FLAGS:
|
|
|
|
return "flags";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG1:
|
|
|
|
return "arg1";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG2:
|
|
|
|
return "arg2";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG3:
|
|
|
|
return "arg3";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG4:
|
|
|
|
return "arg4";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG5:
|
|
|
|
return "arg5";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG6:
|
|
|
|
return "arg6";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG7:
|
|
|
|
return "arg7";
|
|
|
|
case LLDB_REGNUM_GENERIC_ARG8:
|
|
|
|
return "arg8";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CollectRegNums(const uint32_t *reg_num, StreamString &response,
|
|
|
|
bool usehex) {
|
|
|
|
for (int i = 0; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) {
|
|
|
|
if (i > 0)
|
|
|
|
response.PutChar(',');
|
|
|
|
if (usehex)
|
|
|
|
response.Printf("%" PRIx32, *reg_num);
|
|
|
|
else
|
|
|
|
response.Printf("%" PRIu32, *reg_num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-16 22:14:35 +08:00
|
|
|
static void WriteRegisterValueInHexFixedWidth(
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
StreamString &response, NativeRegisterContext ®_ctx,
|
2017-01-20 22:17:16 +08:00
|
|
|
const RegisterInfo ®_info, const RegisterValue *reg_value_p,
|
|
|
|
lldb::ByteOrder byte_order) {
|
2015-02-11 18:29:30 +08:00
|
|
|
RegisterValue reg_value;
|
|
|
|
if (!reg_value_p) {
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_ctx.ReadRegister(®_info, reg_value);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Success())
|
|
|
|
reg_value_p = ®_value;
|
|
|
|
// else log.
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reg_value_p) {
|
2015-07-16 22:14:35 +08:00
|
|
|
AppendHexValue(response, (const uint8_t *)reg_value_p->GetBytes(),
|
2017-01-20 22:17:16 +08:00
|
|
|
reg_value_p->GetByteSize(),
|
|
|
|
byte_order == lldb::eByteOrderLittle);
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Zero-out any unreadable values.
|
|
|
|
if (reg_info.byte_size > 0) {
|
|
|
|
std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0');
|
|
|
|
AppendHexValue(response, zeros.data(), zeros.size(), false);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-26 15:55:28 +08:00
|
|
|
static llvm::Optional<json::Object>
|
2019-10-03 02:02:23 +08:00
|
|
|
GetRegistersAsJSON(NativeThreadProtocol &thread) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext& reg_ctx = thread.GetRegisterContext();
|
2015-07-16 22:14:35 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
json::Object register_object;
|
2015-07-17 18:27:42 +08:00
|
|
|
|
|
|
|
#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
|
2020-11-26 15:55:28 +08:00
|
|
|
const auto expedited_regs =
|
|
|
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
|
2015-07-17 18:27:42 +08:00
|
|
|
#else
|
2020-11-26 15:55:28 +08:00
|
|
|
const auto expedited_regs =
|
|
|
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal);
|
2015-07-17 18:27:42 +08:00
|
|
|
#endif
|
2020-11-26 15:55:28 +08:00
|
|
|
if (expedited_regs.empty())
|
|
|
|
return llvm::None;
|
2015-07-17 18:27:42 +08:00
|
|
|
|
2020-11-26 15:55:28 +08:00
|
|
|
for (auto ®_num : expedited_regs) {
|
2015-07-17 18:27:42 +08:00
|
|
|
const RegisterInfo *const reg_info_p =
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
2015-07-16 22:14:35 +08:00
|
|
|
if (reg_info_p == nullptr) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"%s failed to get register info for register index %" PRIu32,
|
|
|
|
__FUNCTION__, reg_num);
|
2015-07-16 22:14:35 +08:00
|
|
|
continue;
|
|
|
|
}
|
2015-07-23 17:09:29 +08:00
|
|
|
|
|
|
|
if (reg_info_p->value_regs != nullptr)
|
|
|
|
continue; // Only expedite registers that are not contained in other
|
2015-07-16 22:14:35 +08:00
|
|
|
// registers.
|
2015-07-23 17:09:29 +08:00
|
|
|
|
|
|
|
RegisterValue reg_value;
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
|
2015-07-23 17:09:29 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
|
|
|
|
__FUNCTION__,
|
|
|
|
reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
|
|
|
|
reg_num, error.AsCString());
|
2015-07-23 17:09:29 +08:00
|
|
|
continue;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-07-16 22:14:35 +08:00
|
|
|
StreamString stream;
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
WriteRegisterValueInHexFixedWidth(stream, reg_ctx, *reg_info_p,
|
2017-01-20 22:17:16 +08:00
|
|
|
®_value, lldb::eByteOrderBig);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2019-10-03 15:59:26 +08:00
|
|
|
register_object.try_emplace(llvm::to_string(reg_num),
|
|
|
|
stream.GetString().str());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
return register_object;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-07-23 17:09:29 +08:00
|
|
|
static const char *GetStopReasonString(StopReason stop_reason) {
|
2015-07-16 22:14:35 +08:00
|
|
|
switch (stop_reason) {
|
|
|
|
case eStopReasonTrace:
|
|
|
|
return "trace";
|
|
|
|
case eStopReasonBreakpoint:
|
|
|
|
return "breakpoint";
|
2015-07-23 17:09:29 +08:00
|
|
|
case eStopReasonWatchpoint:
|
2015-07-16 22:14:35 +08:00
|
|
|
return "watchpoint";
|
|
|
|
case eStopReasonSignal:
|
|
|
|
return "signal";
|
|
|
|
case eStopReasonException:
|
|
|
|
return "exception";
|
|
|
|
case eStopReasonExec:
|
|
|
|
return "exec";
|
2020-11-10 05:36:26 +08:00
|
|
|
case eStopReasonProcessorTrace:
|
|
|
|
return "processor trace";
|
2021-03-29 23:05:30 +08:00
|
|
|
case eStopReasonFork:
|
|
|
|
return "fork";
|
|
|
|
case eStopReasonVFork:
|
|
|
|
return "vfork";
|
|
|
|
case eStopReasonVForkDone:
|
|
|
|
return "vforkdone";
|
2015-07-16 22:14:35 +08:00
|
|
|
case eStopReasonInstrumentation:
|
|
|
|
case eStopReasonInvalid:
|
|
|
|
case eStopReasonPlanComplete:
|
|
|
|
case eStopReasonThreadExiting:
|
2015-07-23 17:09:29 +08:00
|
|
|
case eStopReasonNone:
|
|
|
|
break; // ignored
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-07-16 22:14:35 +08:00
|
|
|
return nullptr;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2019-10-04 04:10:56 +08:00
|
|
|
static llvm::Expected<json::Array>
|
2019-10-03 02:02:23 +08:00
|
|
|
GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
json::Array threads_array;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-23 17:09:29 +08:00
|
|
|
// Ensure we can get info on the given thread.
|
2022-06-28 14:24:24 +08:00
|
|
|
for (NativeThreadProtocol &thread : process.Threads()) {
|
|
|
|
lldb::tid_t tid = thread.GetID();
|
2015-07-23 17:09:29 +08:00
|
|
|
// Grab the reason this thread stopped.
|
|
|
|
struct ThreadStopInfo tid_stop_info;
|
|
|
|
std::string description;
|
2022-06-28 14:24:24 +08:00
|
|
|
if (!thread.GetStopReason(tid_stop_info, description))
|
2019-10-03 02:02:23 +08:00
|
|
|
return llvm::make_error<llvm::StringError>(
|
|
|
|
"failed to get stop reason", llvm::inconvertibleErrorCode());
|
2015-07-23 17:09:29 +08:00
|
|
|
|
2022-06-20 22:50:21 +08:00
|
|
|
const int signum = tid_stop_info.signo;
|
2015-07-23 17:09:29 +08:00
|
|
|
if (log) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
|
|
|
|
" tid %" PRIu64
|
|
|
|
" got signal signo = %d, reason = %d, exc_type = %" PRIu64,
|
|
|
|
__FUNCTION__, process.GetID(), tid, signum,
|
|
|
|
tid_stop_info.reason, tid_stop_info.details.exception.type);
|
2015-07-23 17:09:29 +08:00
|
|
|
}
|
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
json::Object thread_obj;
|
2015-07-23 17:09:29 +08:00
|
|
|
|
2017-01-20 22:17:16 +08:00
|
|
|
if (!abridged) {
|
2022-06-28 14:24:24 +08:00
|
|
|
if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(thread))
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("registers", std::move(*registers));
|
2017-01-20 22:17:16 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (signum != 0)
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("signal", signum);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-28 14:24:24 +08:00
|
|
|
const std::string thread_name = thread.GetName();
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!thread_name.empty())
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("name", thread_name);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
const char *stop_reason = GetStopReasonString(tid_stop_info.reason);
|
|
|
|
if (stop_reason)
|
|
|
|
thread_obj.try_emplace("reason", stop_reason);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
if (!description.empty())
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("description", description);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
if ((tid_stop_info.reason == eStopReasonException) &&
|
|
|
|
tid_stop_info.details.exception.type) {
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace(
|
|
|
|
"metype", static_cast<int64_t>(tid_stop_info.details.exception.type));
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
json::Array medata_array;
|
2015-02-11 18:29:30 +08:00
|
|
|
for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count;
|
|
|
|
++i) {
|
2019-10-03 02:02:23 +08:00
|
|
|
medata_array.push_back(
|
|
|
|
static_cast<int64_t>(tid_stop_info.details.exception.data[i]));
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2019-10-03 02:02:23 +08:00
|
|
|
thread_obj.try_emplace("medata", std::move(medata_array));
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2019-10-03 02:02:23 +08:00
|
|
|
threads_array.push_back(std::move(thread_obj));
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2019-10-03 02:02:23 +08:00
|
|
|
return threads_array;
|
2015-07-23 17:09:29 +08:00
|
|
|
}
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
StreamString
|
|
|
|
GDBRemoteCommunicationServerLLGS::PrepareStopReplyPacketForThread(
|
|
|
|
NativeThreadProtocol &thread) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
NativeProcessProtocol &process = thread.GetProcess();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
LLDB_LOG(log, "preparing packet for pid {0} tid {1}", process.GetID(),
|
|
|
|
thread.GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Grab the reason this thread stopped.
|
2022-04-12 22:21:09 +08:00
|
|
|
StreamString response;
|
2015-02-11 18:29:30 +08:00
|
|
|
struct ThreadStopInfo tid_stop_info;
|
2015-07-23 17:09:29 +08:00
|
|
|
std::string description;
|
2022-04-12 22:21:09 +08:00
|
|
|
if (!thread.GetStopReason(tid_stop_info, description))
|
|
|
|
return response;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// FIXME implement register handling for exec'd inferiors.
|
2018-05-01 00:49:04 +08:00
|
|
|
// if (tid_stop_info.reason == eStopReasonExec) {
|
2015-02-11 18:29:30 +08:00
|
|
|
// const bool force = true;
|
|
|
|
// InitializeRegisters(force);
|
2015-07-23 17:09:29 +08:00
|
|
|
// }
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Output the T packet with the thread
|
2015-07-23 17:09:29 +08:00
|
|
|
response.PutChar('T');
|
2022-06-20 22:50:21 +08:00
|
|
|
int signum = tid_stop_info.signo;
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(
|
|
|
|
log,
|
|
|
|
"pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}",
|
2022-04-12 22:21:09 +08:00
|
|
|
process.GetID(), thread.GetID(), signum, int(tid_stop_info.reason),
|
2017-07-18 17:24:48 +08:00
|
|
|
tid_stop_info.details.exception.type);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Print the signal number.
|
|
|
|
response.PutHex8(signum & 0xff);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-07 00:17:59 +08:00
|
|
|
// Include the (pid and) tid.
|
|
|
|
response.PutCString("thread:");
|
2022-06-22 14:32:05 +08:00
|
|
|
AppendThreadIDToResponse(response, process.GetID(), thread.GetID());
|
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Include the thread name if there is one.
|
2022-04-12 22:21:09 +08:00
|
|
|
const std::string thread_name = thread.GetName();
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!thread_name.empty()) {
|
|
|
|
size_t thread_name_len = thread_name.length();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (::strcspn(thread_name.c_str(), "$#+-;:") == thread_name_len) {
|
2016-07-22 20:55:35 +08:00
|
|
|
response.PutCString("name:");
|
2016-11-03 04:34:10 +08:00
|
|
|
response.PutCString(thread_name);
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2015-02-11 18:29:30 +08:00
|
|
|
// The thread name contains special chars, send as hex bytes.
|
|
|
|
response.PutCString("hexname:");
|
2019-02-12 22:28:55 +08:00
|
|
|
response.PutStringAsRawHex8(thread_name);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-07-23 17:09:29 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// If a 'QListThreadsInStopReply' was sent to enable this feature, we will
|
|
|
|
// send all thread IDs back in the "threads" key whose value is a list of hex
|
|
|
|
// thread IDs separated by commas:
|
2015-02-11 18:29:30 +08:00
|
|
|
// "threads:10a,10b,10c;"
|
2018-05-01 00:49:04 +08:00
|
|
|
// This will save the debugger from having to send a pair of qfThreadInfo and
|
|
|
|
// qsThreadInfo packets, but it also might take a lot of room in the stop
|
|
|
|
// reply packet, so it must be enabled only on systems where there are no
|
|
|
|
// limits on packet lengths.
|
2015-02-11 18:29:30 +08:00
|
|
|
if (m_list_threads_in_stop_reply) {
|
|
|
|
response.PutCString("threads:");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-28 14:24:24 +08:00
|
|
|
uint32_t thread_num = 0;
|
|
|
|
for (NativeThreadProtocol &listed_thread : process.Threads()) {
|
|
|
|
if (thread_num > 0)
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutChar(',');
|
2022-06-28 14:24:24 +08:00
|
|
|
response.Printf("%" PRIx64, listed_thread.GetID());
|
|
|
|
++thread_num;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-07-23 17:09:29 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Include JSON info that describes the stop reason for any threads that
|
|
|
|
// actually have stop reasons. We use the new "jstopinfo" key whose values
|
|
|
|
// is hex ascii JSON that contains the thread IDs thread stop info only for
|
|
|
|
// threads that have stop reasons. Only send this if we have more than one
|
|
|
|
// thread otherwise this packet has all the info it needs.
|
2022-06-28 14:24:24 +08:00
|
|
|
if (thread_num > 1) {
|
2015-07-23 17:09:29 +08:00
|
|
|
const bool threads_with_valid_stop_info_only = true;
|
2019-10-04 04:10:56 +08:00
|
|
|
llvm::Expected<json::Array> threads_info = GetJSONThreadsInfo(
|
2021-04-11 17:37:36 +08:00
|
|
|
*m_current_process, threads_with_valid_stop_info_only);
|
2019-10-03 02:02:23 +08:00
|
|
|
if (threads_info) {
|
2015-07-23 17:09:29 +08:00
|
|
|
response.PutCString("jstopinfo:");
|
|
|
|
StreamString unescaped_response;
|
2019-10-04 04:10:56 +08:00
|
|
|
unescaped_response.AsRawOstream() << std::move(*threads_info);
|
2019-02-12 22:28:55 +08:00
|
|
|
response.PutStringAsRawHex8(unescaped_response.GetData());
|
2015-07-23 17:09:29 +08:00
|
|
|
response.PutChar(';');
|
2019-10-03 02:02:23 +08:00
|
|
|
} else {
|
2019-11-18 18:31:33 +08:00
|
|
|
LLDB_LOG_ERROR(log, threads_info.takeError(),
|
|
|
|
"failed to prepare a jstopinfo field for pid {1}: {0}",
|
2022-06-07 23:04:01 +08:00
|
|
|
process.GetID());
|
2019-10-03 02:02:23 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2017-01-20 22:17:16 +08:00
|
|
|
|
|
|
|
response.PutCString("thread-pcs");
|
|
|
|
char delimiter = ':';
|
2022-06-28 14:24:24 +08:00
|
|
|
for (NativeThreadProtocol &thread : process.Threads()) {
|
|
|
|
NativeRegisterContext ®_ctx = thread.GetRegisterContext();
|
2017-01-20 22:17:16 +08:00
|
|
|
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
uint32_t reg_to_read = reg_ctx.ConvertRegisterKindToRegisterNumber(
|
2017-01-20 22:17:16 +08:00
|
|
|
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
|
|
|
|
const RegisterInfo *const reg_info_p =
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
reg_ctx.GetRegisterInfoAtIndex(reg_to_read);
|
2017-01-20 22:17:16 +08:00
|
|
|
|
|
|
|
RegisterValue reg_value;
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
|
2017-01-20 22:17:16 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
|
|
|
|
__FUNCTION__,
|
|
|
|
reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
|
|
|
|
reg_to_read, error.AsCString());
|
2017-01-20 22:17:16 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
response.PutChar(delimiter);
|
|
|
|
delimiter = ',';
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
|
2017-01-20 22:17:16 +08:00
|
|
|
®_value, endian::InlHostByteOrder());
|
|
|
|
}
|
|
|
|
|
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
//
|
|
|
|
// Expedite registers.
|
|
|
|
//
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Grab the register context.
|
2022-04-12 22:21:09 +08:00
|
|
|
NativeRegisterContext ®_ctx = thread.GetRegisterContext();
|
2020-11-26 15:55:28 +08:00
|
|
|
const auto expedited_regs =
|
|
|
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
|
2020-11-26 15:55:28 +08:00
|
|
|
for (auto ®_num : expedited_regs) {
|
|
|
|
const RegisterInfo *const reg_info_p =
|
|
|
|
reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
|
|
|
// Only expediate registers that are not contained in other registers.
|
|
|
|
if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) {
|
|
|
|
RegisterValue reg_value;
|
|
|
|
Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
|
|
|
|
if (error.Success()) {
|
|
|
|
response.Printf("%.02x:", reg_num);
|
|
|
|
WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
|
|
|
|
®_value, lldb::eByteOrderBig);
|
|
|
|
response.PutChar(';');
|
|
|
|
} else {
|
2022-04-12 22:21:09 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed to read "
|
|
|
|
"register '%s' index %" PRIu32 ": %s",
|
2019-07-25 01:56:10 +08:00
|
|
|
__FUNCTION__,
|
2020-11-26 15:55:28 +08:00
|
|
|
reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
|
|
|
|
reg_num, error.AsCString());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2015-07-16 22:14:35 +08:00
|
|
|
const char *reason_str = GetStopReasonString(tid_stop_info.reason);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reason_str != nullptr) {
|
|
|
|
response.Printf("reason:%s;", reason_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!description.empty()) {
|
|
|
|
// Description may contains special chars, send as hex bytes.
|
|
|
|
response.PutCString("description:");
|
2019-02-12 22:28:55 +08:00
|
|
|
response.PutStringAsRawHex8(description);
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutChar(';');
|
|
|
|
} else if ((tid_stop_info.reason == eStopReasonException) &&
|
|
|
|
tid_stop_info.details.exception.type) {
|
|
|
|
response.PutCString("metype:");
|
|
|
|
response.PutHex64(tid_stop_info.details.exception.type);
|
|
|
|
response.PutCString(";mecount:");
|
|
|
|
response.PutHex32(tid_stop_info.details.exception.data_count);
|
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) {
|
|
|
|
response.PutCString("medata:");
|
|
|
|
response.PutHex64(tid_stop_info.details.exception.data[i]);
|
|
|
|
response.PutChar(';');
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2021-03-29 23:05:30 +08:00
|
|
|
// Include child process PID/TID for forks.
|
|
|
|
if (tid_stop_info.reason == eStopReasonFork ||
|
|
|
|
tid_stop_info.reason == eStopReasonVFork) {
|
|
|
|
assert(bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::multiprocess));
|
|
|
|
if (tid_stop_info.reason == eStopReasonFork)
|
|
|
|
assert(bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::fork));
|
|
|
|
if (tid_stop_info.reason == eStopReasonVFork)
|
|
|
|
assert(bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::vfork));
|
|
|
|
response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str,
|
|
|
|
tid_stop_info.details.fork.child_pid,
|
|
|
|
tid_stop_info.details.fork.child_tid);
|
|
|
|
}
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
|
|
|
|
NativeProcessProtocol &process, lldb::tid_t tid, bool force_synchronous) {
|
|
|
|
// Ensure we can get info on the given thread.
|
|
|
|
NativeThreadProtocol *thread = process.GetThreadByID(tid);
|
|
|
|
if (!thread)
|
|
|
|
return SendErrorResponse(51);
|
|
|
|
|
|
|
|
StreamString response = PrepareStopReplyPacketForThread(*thread);
|
|
|
|
if (response.Empty())
|
|
|
|
return SendErrorResponse(42);
|
|
|
|
|
|
|
|
if (m_non_stop && !force_synchronous) {
|
|
|
|
PacketResult ret = SendNotificationPacketNoLock(
|
|
|
|
"Stop", m_stop_notification_queue, response.GetString());
|
|
|
|
// Queue notification events for the remaining threads.
|
|
|
|
EnqueueStopReplyPackets(tid);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::EnqueueStopReplyPackets(
|
|
|
|
lldb::tid_t thread_to_skip) {
|
|
|
|
if (!m_non_stop)
|
|
|
|
return;
|
|
|
|
|
2022-06-28 14:24:24 +08:00
|
|
|
for (NativeThreadProtocol &listed_thread : m_current_process->Threads()) {
|
2022-06-30 13:58:12 +08:00
|
|
|
if (listed_thread.GetID() != thread_to_skip) {
|
|
|
|
StreamString stop_reply = PrepareStopReplyPacketForThread(listed_thread);
|
|
|
|
if (!stop_reply.Empty())
|
|
|
|
m_stop_notification_queue.push_back(stop_reply.GetString().str());
|
|
|
|
}
|
2022-04-12 22:21:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-31 17:52:22 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited(
|
|
|
|
NativeProcessProtocol *process) {
|
2015-02-11 18:29:30 +08:00
|
|
|
assert(process && "process cannot be NULL");
|
|
|
|
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
PacketResult result = SendStopReasonForState(
|
|
|
|
*process, StateType::eStateExited, /*force_synchronous=*/false);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (result != PacketResult::Success) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed to send stop "
|
|
|
|
"notification for PID %" PRIu64 ", state: eStateExited",
|
|
|
|
__FUNCTION__, process->GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-06-10 21:53:11 +08:00
|
|
|
if (m_current_process == process)
|
|
|
|
m_current_process = nullptr;
|
|
|
|
if (m_continue_process == process)
|
|
|
|
m_continue_process = nullptr;
|
|
|
|
|
|
|
|
lldb::pid_t pid = process->GetID();
|
|
|
|
m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) {
|
2022-07-13 23:33:28 +08:00
|
|
|
auto find_it = m_debugged_processes.find(pid);
|
|
|
|
assert(find_it != m_debugged_processes.end());
|
|
|
|
bool vkilled = bool(find_it->second.flags & DebuggedProcess::Flag::vkilled);
|
|
|
|
m_debugged_processes.erase(find_it);
|
2022-06-12 14:55:41 +08:00
|
|
|
// Terminate the main loop only if vKill has not been used.
|
2022-06-10 21:53:11 +08:00
|
|
|
// When running in non-stop mode, wait for the vStopped to clear
|
|
|
|
// the notification queue.
|
2022-07-13 23:33:28 +08:00
|
|
|
if (m_debugged_processes.empty() && !m_non_stop && !vkilled) {
|
2022-06-10 21:53:11 +08:00
|
|
|
// Close the pipe to the inferior terminal i/o if we launched it and set
|
|
|
|
// one up.
|
|
|
|
MaybeCloseInferiorTerminalConnection();
|
|
|
|
|
|
|
|
// We are ready to exit the debug monitor.
|
|
|
|
m_exit_now = true;
|
|
|
|
loop.RequestTermination();
|
|
|
|
}
|
|
|
|
});
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-03-31 17:52:22 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped(
|
2015-02-11 18:29:30 +08:00
|
|
|
NativeProcessProtocol *process) {
|
|
|
|
assert(process && "process cannot be NULL");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-30 13:32:27 +08:00
|
|
|
PacketResult result = SendStopReasonForState(
|
|
|
|
*process, StateType::eStateStopped, /*force_synchronous=*/false);
|
|
|
|
if (result != PacketResult::Success) {
|
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed to send stop "
|
|
|
|
"notification for PID %" PRIu64 ", state: eStateExited",
|
|
|
|
__FUNCTION__, process->GetID());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-31 17:52:22 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::ProcessStateChanged(
|
|
|
|
NativeProcessProtocol *process, lldb::StateType state) {
|
2015-02-11 18:29:30 +08:00
|
|
|
assert(process && "process cannot be NULL");
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
if (log) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s called with "
|
|
|
|
"NativeProcessProtocol pid %" PRIu64 ", state: %s",
|
|
|
|
__FUNCTION__, process->GetID(), StateAsCString(state));
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
switch (state) {
|
2015-11-27 21:33:29 +08:00
|
|
|
case StateType::eStateRunning:
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case StateType::eStateStopped:
|
2018-05-01 00:49:04 +08:00
|
|
|
// Make sure we get all of the pending stdout/stderr from the inferior and
|
|
|
|
// send it to the lldb host before we send the state change notification
|
2015-11-27 21:33:29 +08:00
|
|
|
SendProcessOutput();
|
|
|
|
// Then stop the forwarding, so that any late output (see llvm.org/pr25652)
|
2018-05-01 00:49:04 +08:00
|
|
|
// does not interfere with our protocol.
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2015-02-11 18:29:30 +08:00
|
|
|
HandleInferiorState_Stopped(process);
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
case StateType::eStateExited:
|
2015-11-27 21:33:29 +08:00
|
|
|
// Same as above
|
|
|
|
SendProcessOutput();
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2015-11-27 21:33:29 +08:00
|
|
|
HandleInferiorState_Exited(process);
|
|
|
|
break;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
default:
|
|
|
|
if (log) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s didn't handle state "
|
|
|
|
"change for pid %" PRIu64 ", new state: %s",
|
|
|
|
__FUNCTION__, process->GetID(), StateAsCString(state));
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) {
|
|
|
|
ClearProcessSpecificData();
|
|
|
|
}
|
|
|
|
|
2021-04-13 23:32:23 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::NewSubprocess(
|
|
|
|
NativeProcessProtocol *parent_process,
|
|
|
|
std::unique_ptr<NativeProcessProtocol> child_process) {
|
|
|
|
lldb::pid_t child_pid = child_process->GetID();
|
|
|
|
assert(child_pid != LLDB_INVALID_PROCESS_ID);
|
|
|
|
assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end());
|
2022-07-13 23:33:28 +08:00
|
|
|
m_debugged_processes.emplace(
|
|
|
|
child_pid,
|
|
|
|
DebuggedProcess{std::move(child_process), DebuggedProcess::Flag{}});
|
2021-04-13 23:32:23 +08:00
|
|
|
}
|
|
|
|
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() {
|
2022-01-17 22:56:11 +08:00
|
|
|
Log *log = GetLog(GDBRLog::Comm);
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
|
|
|
|
bool interrupt = false;
|
|
|
|
bool done = false;
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
while (true) {
|
Introduce chrono to more gdb-remote functions
Summary:
This replaces the usage of raw integers with duration classes in the gdb-remote
packet management functions. The values are still converted back to integers once
they go into the generic Communication class -- that I am leaving to a separate
change.
The changes are mostly straight-forward (*), the only tricky part was
representation of infinite timeouts.
Currently, we use UINT32_MAX to denote infinite timeout. This is not well suited
for duration classes, as they tend to do arithmetic on the values, and the
identity of the MAX value can easily get lost (e.g.
microseconds(seconds(UINT32_MAX)).count() != UINT32_MAX). We cannot use zero to
represent infinity (as Listener classes do) because we already use it to do
non-blocking polling reads. For this reason, I chose to have an explicit value
for infinity.
The way I achieved that is via llvm::Optional, and I think it reads quite
natural. Passing llvm::None as "timeout" means "no timeout", while passing zero
means "poll". The only tricky part is this breaks implicit conversions (seconds
are implicitly convertible to microseconds, but Optional<seconds> cannot be
easily converted into Optional<microseconds>). For this reason I added a special
class Timeout, inheriting from Optional, and enabling the necessary conversions
one would normally expect.
(*) The other tricky part was GDBRemoteCommunication::PopPacketFromQueue, which
was needlessly complicated. I've simplified it, but that one is only used in
non-stop mode, and so is untested.
Reviewers: clayborg, zturner, jingham
Subscribers: lldb-commits
Differential Revision: https://reviews.llvm.org/D26971
llvm-svn: 287864
2016-11-24 18:54:49 +08:00
|
|
|
const PacketResult result = GetPacketAndSendResponse(
|
|
|
|
std::chrono::microseconds(0), error, interrupt, done);
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
if (result == PacketResult::ErrorReplyTimeout)
|
|
|
|
break; // No more packets in the queue
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
if ((result != PacketResult::Success)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s processing a packet "
|
|
|
|
"failed: %s",
|
|
|
|
__FUNCTION__, error.AsCString());
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
m_mainloop.RequestTermination();
|
|
|
|
break;
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
}
|
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status GDBRemoteCommunicationServerLLGS::InitializeConnection(
|
2020-04-02 20:40:59 +08:00
|
|
|
std::unique_ptr<Connection> connection) {
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
IOObjectSP read_object_sp = connection->GetReadObject();
|
2020-04-02 20:40:59 +08:00
|
|
|
GDBRemoteCommunicationServer::SetConnection(std::move(connection));
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2015-07-21 21:20:25 +08:00
|
|
|
m_network_handle_up = m_mainloop.RegisterReadObject(
|
Introduce a MainLoop class and switch llgs to use it
Summary:
This is the first part of our effort to make llgs single threaded. Currently, llgs consists of
about three threads and the synchronisation between them is a major source of latency when
debugging linux and android applications.
In order to be able to go single threaded, we must have the ability to listen for events from
multiple sources (primarily, client commands coming over the network and debug events from the
inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop.
A main loop has the ability to register callback's which will be invoked upon receipt of certain
events. MainLoopPosix has the ability to listen for file descriptors and signals.
For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop
instead of waiting on the network socket directly, but the other threads still remain. In the
followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining
threads.
Reviewers: ovyalov, clayborg, amccarth, zturner, emaste
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D11066
llvm-svn: 242018
2015-07-13 18:44:55 +08:00
|
|
|
read_object_sp, [this](MainLoopBase &) { DataAvailableCallback(); },
|
|
|
|
error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer,
|
|
|
|
uint32_t len) {
|
|
|
|
if ((buffer == nullptr) || (len == 0)) {
|
2016-08-27 23:52:29 +08:00
|
|
|
// Nothing to send.
|
|
|
|
return PacketResult::Success;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StreamString response;
|
|
|
|
response.PutChar('O');
|
|
|
|
response.PutBytesAsRawHex8(buffer, len);
|
|
|
|
|
2022-06-30 03:48:10 +08:00
|
|
|
if (m_non_stop)
|
|
|
|
return SendNotificationPacketNoLock("Stdio", m_stdio_notification_queue,
|
|
|
|
response.GetString());
|
2015-11-27 21:33:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) {
|
|
|
|
Status error;
|
2015-11-27 21:33:29 +08:00
|
|
|
|
|
|
|
// Set up the reading/handling of process I/O
|
|
|
|
std::unique_ptr<ConnectionFileDescriptor> conn_up(
|
|
|
|
new ConnectionFileDescriptor(fd, true));
|
|
|
|
if (!conn_up) {
|
|
|
|
error.SetErrorString("failed to create ConnectionFileDescriptor");
|
|
|
|
return error;
|
2015-07-21 21:20:25 +08:00
|
|
|
}
|
|
|
|
|
2015-03-19 22:58:36 +08:00
|
|
|
m_stdio_communication.SetCloseOnEOF(false);
|
2020-04-02 20:40:59 +08:00
|
|
|
m_stdio_communication.SetConnection(std::move(conn_up));
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!m_stdio_communication.IsConnected()) {
|
2015-07-21 21:20:25 +08:00
|
|
|
error.SetErrorString(
|
2015-02-11 18:29:30 +08:00
|
|
|
"failed to set connection for inferior I/O communication");
|
|
|
|
return error;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
return Status();
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-07-21 21:20:25 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
|
|
|
|
// Don't forward if not connected (e.g. when attaching).
|
|
|
|
if (!m_stdio_communication.IsConnected())
|
|
|
|
return;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2022-06-10 21:53:11 +08:00
|
|
|
assert(!m_stdio_handle_up);
|
2015-11-27 21:33:29 +08:00
|
|
|
m_stdio_handle_up = m_mainloop.RegisterReadObject(
|
2015-07-21 21:20:25 +08:00
|
|
|
m_stdio_communication.GetConnection()->GetReadObject(),
|
|
|
|
[this](MainLoopBase &) { SendProcessOutput(); }, error);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-21 21:20:25 +08:00
|
|
|
if (!m_stdio_handle_up) {
|
|
|
|
// Not much we can do about the failure. Log it and continue without
|
2015-11-27 21:33:29 +08:00
|
|
|
// forwarding.
|
2022-01-31 22:57:48 +08:00
|
|
|
if (Log *log = GetLog(LLDBLog::Process))
|
2022-06-10 21:53:11 +08:00
|
|
|
LLDB_LOG(log, "Failed to set up stdio forwarding: {0}", error);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-21 21:20:25 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() {
|
|
|
|
m_stdio_handle_up.reset();
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-07-21 21:20:25 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
|
|
|
|
char buffer[1024];
|
2015-02-11 18:29:30 +08:00
|
|
|
ConnectionStatus status;
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2016-09-07 04:57:50 +08:00
|
|
|
while (true) {
|
2016-11-25 19:58:44 +08:00
|
|
|
size_t bytes_read = m_stdio_communication.Read(
|
|
|
|
buffer, sizeof buffer, std::chrono::microseconds(0), status, &error);
|
2015-07-21 21:20:25 +08:00
|
|
|
switch (status) {
|
|
|
|
case eConnectionStatusSuccess:
|
|
|
|
SendONotification(buffer, bytes_read);
|
|
|
|
break;
|
|
|
|
case eConnectionStatusLostConnection:
|
|
|
|
case eConnectionStatusEndOfFile:
|
|
|
|
case eConnectionStatusError:
|
|
|
|
case eConnectionStatusNoConnection:
|
2022-01-31 22:57:48 +08:00
|
|
|
if (Log *log = GetLog(LLDBLog::Process))
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s Stopping stdio "
|
|
|
|
"forwarding as communication returned status %d (error: "
|
|
|
|
"%s)",
|
|
|
|
__FUNCTION__, status, error.AsCString());
|
2015-07-21 21:20:25 +08:00
|
|
|
m_stdio_handle_up.reset();
|
|
|
|
return;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-21 21:20:25 +08:00
|
|
|
case eConnectionStatusInterrupted:
|
|
|
|
case eConnectionStatusTimedOut:
|
|
|
|
return;
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2017-05-26 19:46:27 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
2020-11-10 05:36:26 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported(
|
2017-05-26 19:46:27 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
2020-11-10 05:36:26 +08:00
|
|
|
|
2017-05-26 19:46:27 +08:00
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(Status("Process not running."));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
return SendJSONResponse(m_current_process->TraceSupported());
|
2017-05-26 19:46:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
2020-11-10 05:36:26 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop(
|
2017-05-26 19:46:27 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(Status("Process not running."));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
packet.ConsumeFront("jLLDBTraceStop:");
|
|
|
|
Expected<TraceStopRequest> stop_request =
|
|
|
|
json::parse<TraceStopRequest>(packet.Peek(), "TraceStopRequest");
|
|
|
|
if (!stop_request)
|
|
|
|
return SendErrorResponse(stop_request.takeError());
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (Error err = m_current_process->TraceStop(*stop_request))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(std::move(err));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
2020-11-10 05:36:26 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart(
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
return SendErrorResponse(Status("Process not running."));
|
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
packet.ConsumeFront("jLLDBTraceStart:");
|
|
|
|
Expected<TraceStartRequest> request =
|
|
|
|
json::parse<TraceStartRequest>(packet.Peek(), "TraceStartRequest");
|
|
|
|
if (!request)
|
|
|
|
return SendErrorResponse(request.takeError());
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (Error err = m_current_process->TraceStart(packet.Peek(), request->type))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(std::move(err));
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendOKResponse();
|
[intel-pt][trace] Implement a "get supported trace type" packet
Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
2020-10-30 03:44:13 +08:00
|
|
|
}
|
|
|
|
|
2017-05-26 19:46:27 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
2020-11-10 05:36:26 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState(
|
2017-05-26 19:46:27 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(Status("Process not running."));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
packet.ConsumeFront("jLLDBTraceGetState:");
|
|
|
|
Expected<TraceGetStateRequest> request =
|
|
|
|
json::parse<TraceGetStateRequest>(packet.Peek(), "TraceGetStateRequest");
|
|
|
|
if (!request)
|
|
|
|
return SendErrorResponse(request.takeError());
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
return SendJSONResponse(m_current_process->TraceGetState(request->type));
|
2017-05-26 19:46:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
2020-11-10 05:36:26 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData(
|
2017-05-26 19:46:27 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2020-11-10 05:36:26 +08:00
|
|
|
return SendErrorResponse(Status("Process not running."));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
packet.ConsumeFront("jLLDBTraceGetBinaryData:");
|
|
|
|
llvm::Expected<TraceGetBinaryDataRequest> request =
|
|
|
|
llvm::json::parse<TraceGetBinaryDataRequest>(packet.Peek(),
|
|
|
|
"TraceGetBinaryDataRequest");
|
|
|
|
if (!request)
|
|
|
|
return SendErrorResponse(Status(request.takeError()));
|
2017-05-26 19:46:27 +08:00
|
|
|
|
2020-11-10 05:36:26 +08:00
|
|
|
if (Expected<std::vector<uint8_t>> bytes =
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->TraceGetBinaryData(*request)) {
|
2020-11-10 05:36:26 +08:00
|
|
|
StreamGDBRemote response;
|
|
|
|
response.PutEscapedBytes(bytes->data(), bytes->size());
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
} else
|
|
|
|
return SendErrorResponse(bytes.takeError());
|
2017-05-26 19:46:27 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(68);
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
lldb::pid_t pid = m_current_process->GetID();
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
|
|
|
|
ProcessInstanceInfo proc_info;
|
|
|
|
if (!Host::GetProcessInfo(pid, proc_info))
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
|
|
|
|
StreamString response;
|
|
|
|
CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(68);
|
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Make sure we set the current thread so g and p packets return the data the
|
|
|
|
// gdb will expect.
|
2021-04-11 17:37:36 +08:00
|
|
|
lldb::tid_t tid = m_current_process->GetCurrentThreadID();
|
2015-02-11 18:29:30 +08:00
|
|
|
SetCurrentThreadID(tid);
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
|
2017-10-17 23:52:16 +08:00
|
|
|
if (!thread)
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(69);
|
|
|
|
|
|
|
|
StreamString response;
|
2022-06-20 14:59:27 +08:00
|
|
|
response.PutCString("QC");
|
2022-06-22 14:32:05 +08:00
|
|
|
AppendThreadIDToResponse(response, m_current_process->GetID(),
|
|
|
|
thread->GetID());
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-10 21:53:11 +08:00
|
|
|
if (m_debugged_processes.empty()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "No debugged process found.");
|
2015-07-28 17:06:56 +08:00
|
|
|
return PacketResult::Success;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-06-10 21:53:11 +08:00
|
|
|
for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end();
|
|
|
|
++it) {
|
|
|
|
LLDB_LOG(log, "Killing process {0}", it->first);
|
2022-07-13 23:33:28 +08:00
|
|
|
Status error = it->second.process_up->Kill();
|
2022-06-10 21:53:11 +08:00
|
|
|
if (error.Fail())
|
|
|
|
LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", it->first,
|
|
|
|
error);
|
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
// The response to kill packet is undefined per the spec. LLDB
|
|
|
|
// follows the same rules as for continue packets, i.e. no response
|
|
|
|
// in all-stop mode, and "OK" in non-stop mode; in both cases this
|
|
|
|
// is followed by the actual stop reason.
|
|
|
|
return SendContinueSuccessResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-06-12 14:55:41 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vKill(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2022-06-12 14:55:41 +08:00
|
|
|
|
|
|
|
packet.SetFilePos(6); // vKill;
|
|
|
|
uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"vKill failed to parse the process id");
|
|
|
|
|
|
|
|
auto it = m_debugged_processes.find(pid);
|
|
|
|
if (it == m_debugged_processes.end())
|
|
|
|
return SendErrorResponse(42);
|
|
|
|
|
2022-07-13 23:33:28 +08:00
|
|
|
Status error = it->second.process_up->Kill();
|
2022-06-12 14:55:41 +08:00
|
|
|
if (error.Fail())
|
|
|
|
return SendErrorResponse(error.ToError());
|
|
|
|
|
|
|
|
// OK response is sent when the process dies.
|
2022-07-13 23:33:28 +08:00
|
|
|
it->second.flags |= DebuggedProcess::Flag::vkilled;
|
2022-06-12 14:55:41 +08:00
|
|
|
return PacketResult::Success;
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
packet.SetFilePos(::strlen("QSetDisableASLR:"));
|
|
|
|
if (packet.GetU32(0))
|
|
|
|
m_process_launch_info.GetFlags().Set(eLaunchFlagDisableASLR);
|
|
|
|
else
|
|
|
|
m_process_launch_info.GetFlags().Clear(eLaunchFlagDisableASLR);
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
packet.SetFilePos(::strlen("QSetWorkingDir:"));
|
|
|
|
std::string path;
|
|
|
|
packet.GetHexByteString(path);
|
2018-11-02 05:05:36 +08:00
|
|
|
m_process_launch_info.SetWorkingDirectory(FileSpec(path));
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2015-05-30 03:52:29 +08:00
|
|
|
FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};
|
|
|
|
if (working_dir) {
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamString response;
|
2022-07-26 14:29:30 +08:00
|
|
|
response.PutStringAsRawHex8(working_dir.GetPath().c_str());
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SendErrorResponse(14);
|
|
|
|
}
|
|
|
|
|
2021-04-13 22:07:28 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
m_thread_suffix_supported = true;
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
m_list_threads_in_stop_reply = true;
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::ResumeProcess(
|
|
|
|
NativeProcessProtocol &process, const ResumeActionList &actions) {
|
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
|
|
|
|
|
|
|
// In non-stop protocol mode, the process could be running already.
|
|
|
|
// We do not support resuming threads independently, so just error out.
|
|
|
|
if (!process.CanResume()) {
|
|
|
|
LLDB_LOG(log, "process {0} cannot be resumed (state={1})", process.GetID(),
|
|
|
|
process.GetState());
|
|
|
|
return SendErrorResponse(0x37);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status error = process.Resume(actions);
|
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log, "process {0} failed to resume: {1}", process.GetID(), error);
|
|
|
|
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
|
|
|
|
}
|
|
|
|
|
|
|
|
LLDB_LOG(log, "process {0} resumed", process.GetID());
|
|
|
|
|
|
|
|
return PacketResult::Success;
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Ensure we have a native process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_continue_process) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s no debugged process "
|
|
|
|
"shared pointer",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x36);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Pull out the signal number.
|
|
|
|
packet.SetFilePos(::strlen("C"));
|
|
|
|
if (packet.GetBytesLeft() < 1) {
|
|
|
|
// Shouldn't be using a C without a signal.
|
|
|
|
return SendIllFormedResponse(packet, "C packet specified without signal.");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
const uint32_t signo =
|
|
|
|
packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
|
|
|
|
if (signo == std::numeric_limits<uint32_t>::max())
|
|
|
|
return SendIllFormedResponse(packet, "failed to parse signal number");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Handle optional continue address.
|
|
|
|
if (packet.GetBytesLeft() > 0) {
|
|
|
|
// FIXME add continue at address support for $C{signo}[;{continue-address}].
|
2015-03-31 17:52:22 +08:00
|
|
|
if (*packet.Peek() == ';')
|
2019-08-21 12:55:56 +08:00
|
|
|
return SendUnimplementedResponse(packet.GetStringRef().data());
|
2015-02-11 18:29:30 +08:00
|
|
|
else
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "unexpected content after $C{signal-number}");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
// In non-stop protocol mode, the process could be running already.
|
|
|
|
// We do not support resuming threads independently, so just error out.
|
|
|
|
if (!m_continue_process->CanResume()) {
|
|
|
|
LLDB_LOG(log, "process cannot be resumed (state={0})",
|
|
|
|
m_continue_process->GetState());
|
|
|
|
return SendErrorResponse(0x37);
|
|
|
|
}
|
|
|
|
|
2019-09-17 17:31:00 +08:00
|
|
|
ResumeActionList resume_actions(StateType::eStateRunning,
|
|
|
|
LLDB_INVALID_SIGNAL_NUMBER);
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// We have two branches: what to do if a continue thread is specified (in
|
2018-05-01 00:49:04 +08:00
|
|
|
// which case we target sending the signal to that thread), or when we don't
|
|
|
|
// have a continue thread set (in which case we send a signal to the
|
|
|
|
// process).
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// TODO discuss with Greg Clayton, make sure this makes sense.
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
lldb::tid_t signal_tid = GetContinueThreadID();
|
|
|
|
if (signal_tid != LLDB_INVALID_THREAD_ID) {
|
|
|
|
// The resume action for the continue thread (or all threads if a continue
|
|
|
|
// thread is not set).
|
|
|
|
ResumeAction action = {GetContinueThreadID(), StateType::eStateRunning,
|
2015-03-31 17:52:22 +08:00
|
|
|
static_cast<int>(signo)};
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Add the action for the continue thread (or all threads when the continue
|
|
|
|
// thread isn't present).
|
|
|
|
resume_actions.Append(action);
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Send the signal to the process since we weren't targeting a specific
|
|
|
|
// continue thread with the signal.
|
2021-04-11 17:37:36 +08:00
|
|
|
error = m_continue_process->Signal(signo);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "failed to send signal for process {0}: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_continue_process->GetID(), error);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x52);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
// NB: this checks CanResume() twice but using a single code path for
|
|
|
|
// resuming still seems worth it.
|
|
|
|
PacketResult resume_res = ResumeProcess(*m_continue_process, resume_actions);
|
|
|
|
if (resume_res != PacketResult::Success)
|
|
|
|
return resume_res;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
// Don't send an "OK" packet, except in non-stop mode;
|
|
|
|
// otherwise, the response is the stopped/exited message.
|
|
|
|
return SendContinueSuccessResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
packet.SetFilePos(packet.GetFilePos() + ::strlen("c"));
|
|
|
|
|
|
|
|
// For now just support all continue.
|
|
|
|
const bool has_continue_address = (packet.GetBytesLeft() > 0);
|
|
|
|
if (has_continue_address) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "not implemented for c[address] variant [{0} remains]",
|
|
|
|
packet.Peek());
|
2019-08-21 12:55:56 +08:00
|
|
|
return SendUnimplementedResponse(packet.GetStringRef().data());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Ensure we have a native process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_continue_process) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s no debugged process "
|
|
|
|
"shared pointer",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x36);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the ResumeActionList
|
2019-09-19 13:49:14 +08:00
|
|
|
ResumeActionList actions(StateType::eStateRunning,
|
|
|
|
LLDB_INVALID_SIGNAL_NUMBER);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
PacketResult resume_res = ResumeProcess(*m_continue_process, actions);
|
|
|
|
if (resume_res != PacketResult::Success)
|
|
|
|
return resume_res;
|
2022-04-12 22:21:09 +08:00
|
|
|
|
|
|
|
return SendContinueSuccessResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vCont_actions(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
StreamString response;
|
2022-06-04 02:21:26 +08:00
|
|
|
response.Printf("vCont;c;C;s;S;t");
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
static bool ResumeActionListStopsAllThreads(ResumeActionList &actions) {
|
|
|
|
// We're doing a stop-all if and only if our only action is a "t" for all
|
|
|
|
// threads.
|
|
|
|
if (const ResumeAction *default_action =
|
|
|
|
actions.GetActionForThread(LLDB_INVALID_THREAD_ID, false)) {
|
|
|
|
if (default_action->state == eStateSuspended && actions.GetSize() == 1)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vCont(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s handling vCont packet",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
packet.SetFilePos(::strlen("vCont"));
|
|
|
|
|
|
|
|
if (packet.GetBytesLeft() == 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s missing action from "
|
|
|
|
"vCont package",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendIllFormedResponse(packet, "Missing action from vCont package");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-06-15 22:48:48 +08:00
|
|
|
if (::strcmp(packet.Peek(), ";s") == 0) {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Move past the ';', then do a simple 's'.
|
|
|
|
packet.SetFilePos(packet.GetFilePos() + 1);
|
|
|
|
return Handle_s(packet);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-06-15 22:48:48 +08:00
|
|
|
std::unordered_map<lldb::pid_t, ResumeActionList> thread_actions;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-08-31 16:43:37 +08:00
|
|
|
while (packet.GetBytesLeft() && *packet.Peek() == ';') {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Skip the semi-colon.
|
|
|
|
packet.GetChar();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Build up the thread action.
|
|
|
|
ResumeAction thread_action;
|
|
|
|
thread_action.tid = LLDB_INVALID_THREAD_ID;
|
|
|
|
thread_action.state = eStateInvalid;
|
2019-09-19 13:49:14 +08:00
|
|
|
thread_action.signal = LLDB_INVALID_SIGNAL_NUMBER;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const char action = packet.GetChar();
|
|
|
|
switch (action) {
|
|
|
|
case 'C':
|
|
|
|
thread_action.signal = packet.GetHexMaxU32(false, 0);
|
|
|
|
if (thread_action.signal == 0)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Could not parse signal in vCont packet C action");
|
2022-08-09 02:31:49 +08:00
|
|
|
[[fallthrough]];
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case 'c':
|
|
|
|
// Continue
|
|
|
|
thread_action.state = eStateRunning;
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case 'S':
|
|
|
|
thread_action.signal = packet.GetHexMaxU32(false, 0);
|
|
|
|
if (thread_action.signal == 0)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Could not parse signal in vCont packet S action");
|
2022-08-09 02:31:49 +08:00
|
|
|
[[fallthrough]];
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case 's':
|
2016-09-07 04:57:50 +08:00
|
|
|
// Step
|
2015-02-11 18:29:30 +08:00
|
|
|
thread_action.state = eStateStepping;
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-04 02:21:26 +08:00
|
|
|
case 't':
|
|
|
|
// Stop
|
|
|
|
thread_action.state = eStateSuspended;
|
|
|
|
break;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
default:
|
|
|
|
return SendIllFormedResponse(packet, "Unsupported vCont action");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-07-01 21:12:00 +08:00
|
|
|
// If there's no thread-id (e.g. "vCont;c"), it's "p-1.-1".
|
2022-06-15 22:48:48 +08:00
|
|
|
lldb::pid_t pid = StringExtractorGDBRemote::AllProcesses;
|
|
|
|
lldb::tid_t tid = StringExtractorGDBRemote::AllThreads;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out optional :{thread-id} value.
|
|
|
|
if (packet.GetBytesLeft() && (*packet.Peek() == ':')) {
|
|
|
|
// Consume the separator.
|
|
|
|
packet.GetChar();
|
|
|
|
|
2022-07-01 21:12:00 +08:00
|
|
|
auto pid_tid = packet.GetPidTid(LLDB_INVALID_PROCESS_ID);
|
2022-06-15 22:48:48 +08:00
|
|
|
if (!pid_tid)
|
|
|
|
return SendIllFormedResponse(packet, "Malformed thread-id");
|
2021-03-30 19:25:06 +08:00
|
|
|
|
2022-06-15 22:48:48 +08:00
|
|
|
pid = pid_tid->first;
|
|
|
|
tid = pid_tid->second;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
if (thread_action.state == eStateSuspended &&
|
|
|
|
tid != StringExtractorGDBRemote::AllThreads) {
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "'t' action not supported for individual threads");
|
|
|
|
}
|
|
|
|
|
2022-07-01 21:12:00 +08:00
|
|
|
// If we get TID without PID, it's the current process.
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID) {
|
2022-06-15 22:48:48 +08:00
|
|
|
if (!m_continue_process) {
|
2022-07-01 21:12:00 +08:00
|
|
|
LLDB_LOG(log, "no process selected via Hc");
|
2022-06-15 22:48:48 +08:00
|
|
|
return SendErrorResponse(0x36);
|
|
|
|
}
|
|
|
|
pid = m_continue_process->GetID();
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-07-01 21:12:00 +08:00
|
|
|
assert(pid != LLDB_INVALID_PROCESS_ID);
|
2022-06-15 22:48:48 +08:00
|
|
|
if (tid == StringExtractorGDBRemote::AllThreads)
|
|
|
|
tid = LLDB_INVALID_THREAD_ID;
|
|
|
|
thread_action.tid = tid;
|
|
|
|
|
2022-07-01 21:12:00 +08:00
|
|
|
if (pid == StringExtractorGDBRemote::AllProcesses) {
|
|
|
|
if (tid != LLDB_INVALID_THREAD_ID)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "vCont: p-1 is not valid with a specific tid");
|
|
|
|
for (auto &process_it : m_debugged_processes)
|
|
|
|
thread_actions[process_it.first].Append(thread_action);
|
|
|
|
} else
|
|
|
|
thread_actions[pid].Append(thread_action);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-15 22:48:48 +08:00
|
|
|
assert(thread_actions.size() >= 1);
|
2022-07-01 21:12:00 +08:00
|
|
|
if (thread_actions.size() > 1 && !m_non_stop)
|
2022-06-15 22:48:48 +08:00
|
|
|
return SendIllFormedResponse(
|
2022-07-01 21:12:00 +08:00
|
|
|
packet,
|
|
|
|
"Resuming multiple processes is supported in non-stop mode only");
|
2022-06-15 22:48:48 +08:00
|
|
|
|
|
|
|
for (std::pair<lldb::pid_t, ResumeActionList> x : thread_actions) {
|
|
|
|
auto process_it = m_debugged_processes.find(x.first);
|
|
|
|
if (process_it == m_debugged_processes.end()) {
|
|
|
|
LLDB_LOG(log, "vCont failed for process {0}: process not debugged",
|
|
|
|
x.first);
|
|
|
|
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
|
|
|
|
}
|
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
// There are four possible scenarios here. These are:
|
|
|
|
// 1. vCont on a stopped process that resumes at least one thread.
|
|
|
|
// In this case, we call Resume().
|
|
|
|
// 2. vCont on a stopped process that leaves all threads suspended.
|
|
|
|
// A no-op.
|
|
|
|
// 3. vCont on a running process that requests suspending all
|
|
|
|
// running threads. In this case, we call Interrupt().
|
|
|
|
// 4. vCont on a running process that requests suspending a subset
|
|
|
|
// of running threads or resuming a subset of suspended threads.
|
|
|
|
// Since we do not support full nonstop mode, this is unsupported
|
|
|
|
// and we return an error.
|
|
|
|
|
|
|
|
assert(process_it->second.process_up);
|
|
|
|
if (ResumeActionListStopsAllThreads(x.second)) {
|
|
|
|
if (process_it->second.process_up->IsRunning()) {
|
|
|
|
assert(m_non_stop);
|
|
|
|
|
|
|
|
Status error = process_it->second.process_up->Interrupt();
|
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log, "vCont failed to halt process {0}: {1}", x.first,
|
|
|
|
error);
|
|
|
|
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
|
|
|
|
}
|
|
|
|
|
|
|
|
LLDB_LOG(log, "halted process {0}", x.first);
|
2022-07-15 19:43:34 +08:00
|
|
|
|
2022-06-28 12:00:46 +08:00
|
|
|
// hack to avoid enabling stdio forwarding after stop
|
|
|
|
// TODO: remove this when we improve stdio forwarding for nonstop
|
|
|
|
assert(thread_actions.size() == 1);
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PacketResult resume_res =
|
|
|
|
ResumeProcess(*process_it->second.process_up, x.second);
|
|
|
|
if (resume_res != PacketResult::Success)
|
|
|
|
return resume_res;
|
|
|
|
}
|
2022-06-15 22:48:48 +08:00
|
|
|
}
|
2022-04-12 22:21:09 +08:00
|
|
|
|
|
|
|
return SendContinueSuccessResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "setting current thread id to {0}", tid);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
m_current_tid = tid;
|
2021-04-11 17:37:36 +08:00
|
|
|
if (m_current_process)
|
|
|
|
m_current_process->SetCurrentThreadID(m_current_tid);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "setting continue thread id to {0}", tid);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
m_continue_tid = tid;
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_stop_reason(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Handle the $? gdbremote command.
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
if (m_non_stop) {
|
|
|
|
// Clear the notification queue first, except for pending exit
|
|
|
|
// notifications.
|
|
|
|
llvm::erase_if(m_stop_notification_queue, [](const std::string &x) {
|
|
|
|
return x.front() != 'W' && x.front() != 'X';
|
|
|
|
});
|
|
|
|
|
2022-06-10 21:53:11 +08:00
|
|
|
if (m_current_process) {
|
|
|
|
// Queue stop reply packets for all active threads. Start with
|
|
|
|
// the current thread (for clients that don't actually support multiple
|
|
|
|
// stop reasons).
|
|
|
|
NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
|
2022-06-30 13:58:12 +08:00
|
|
|
if (thread) {
|
|
|
|
StreamString stop_reply = PrepareStopReplyPacketForThread(*thread);
|
|
|
|
if (!stop_reply.Empty())
|
|
|
|
m_stop_notification_queue.push_back(stop_reply.GetString().str());
|
|
|
|
}
|
2022-06-10 21:53:11 +08:00
|
|
|
EnqueueStopReplyPackets(thread ? thread->GetID()
|
|
|
|
: LLDB_INVALID_THREAD_ID);
|
|
|
|
}
|
2022-04-12 22:21:09 +08:00
|
|
|
|
|
|
|
// If the notification queue is empty (i.e. everything is running), send OK.
|
|
|
|
if (m_stop_notification_queue.empty())
|
|
|
|
return SendOKResponse();
|
|
|
|
|
|
|
|
// Send the first item from the new notification queue synchronously.
|
|
|
|
return SendPacketNoLock(m_stop_notification_queue.front());
|
|
|
|
}
|
|
|
|
|
2022-06-10 21:53:11 +08:00
|
|
|
// If no process, indicate error
|
|
|
|
if (!m_current_process)
|
|
|
|
return SendErrorResponse(02);
|
|
|
|
|
2022-06-10 00:54:50 +08:00
|
|
|
return SendStopReasonForState(*m_current_process,
|
2022-04-12 22:21:09 +08:00
|
|
|
m_current_process->GetState(),
|
|
|
|
/*force_synchronous=*/true);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
2015-07-21 21:20:25 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
|
2022-04-12 22:21:09 +08:00
|
|
|
NativeProcessProtocol &process, lldb::StateType process_state,
|
|
|
|
bool force_synchronous) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-30 16:47:15 +08:00
|
|
|
if (m_disabling_non_stop) {
|
|
|
|
// Check if we are waiting for any more processes to stop. If we are,
|
|
|
|
// do not send the OK response yet.
|
|
|
|
for (const auto &it : m_debugged_processes) {
|
|
|
|
if (it.second.process_up->IsRunning())
|
|
|
|
return PacketResult::Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If all expected processes were stopped after a QNonStop:0 request,
|
|
|
|
// send the OK response.
|
|
|
|
m_disabling_non_stop = false;
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
switch (process_state) {
|
|
|
|
case eStateAttaching:
|
|
|
|
case eStateLaunching:
|
|
|
|
case eStateRunning:
|
|
|
|
case eStateStepping:
|
|
|
|
case eStateDetached:
|
|
|
|
// NOTE: gdb protocol doc looks like it should return $OK
|
|
|
|
// when everything is running (i.e. no stopped result).
|
|
|
|
return PacketResult::Success; // Ignore
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case eStateSuspended:
|
|
|
|
case eStateStopped:
|
|
|
|
case eStateCrashed: {
|
2022-06-10 00:54:50 +08:00
|
|
|
lldb::tid_t tid = process.GetCurrentThreadID();
|
2018-05-01 00:49:04 +08:00
|
|
|
// Make sure we set the current thread so g and p packets return the data
|
|
|
|
// the gdb will expect.
|
2015-02-11 18:29:30 +08:00
|
|
|
SetCurrentThreadID(tid);
|
2022-04-12 22:21:09 +08:00
|
|
|
return SendStopReplyPacketForThread(process, tid, force_synchronous);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case eStateInvalid:
|
|
|
|
case eStateUnloaded:
|
|
|
|
case eStateExited:
|
2022-06-10 00:54:50 +08:00
|
|
|
return SendWResponse(&process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
default:
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}",
|
2022-06-10 00:54:50 +08:00
|
|
|
process.GetID(), process_state);
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(68);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Ensure we have a thread.
|
2021-04-11 17:37:36 +08:00
|
|
|
NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0);
|
2017-10-17 23:52:16 +08:00
|
|
|
if (!thread)
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(69);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the register context for the first thread.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext ®_context = thread->GetRegisterContext();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the register number from the request.
|
|
|
|
packet.SetFilePos(strlen("qRegisterInfo"));
|
|
|
|
const uint32_t reg_index =
|
|
|
|
packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
|
|
|
|
if (reg_index == std::numeric_limits<uint32_t>::max())
|
|
|
|
return SendErrorResponse(69);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Return the end of registers response if we've iterated one past the end of
|
|
|
|
// the register set.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
if (reg_index >= reg_context.GetUserRegisterCount())
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(69);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!reg_info)
|
|
|
|
return SendErrorResponse(69);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Build the reginfos response.
|
|
|
|
StreamGDBRemote response;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutCString("name:");
|
|
|
|
response.PutCString(reg_info->name);
|
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reg_info->alt_name && reg_info->alt_name[0]) {
|
|
|
|
response.PutCString("alt-name:");
|
|
|
|
response.PutCString(reg_info->alt_name);
|
2016-07-22 20:55:35 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2020-12-02 06:09:14 +08:00
|
|
|
response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8);
|
|
|
|
|
|
|
|
if (!reg_context.RegisterOffsetIsDynamic())
|
|
|
|
response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
|
|
|
|
if (!encoding.empty())
|
|
|
|
response << "encoding:" << encoding << ';';
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
llvm::StringRef format = GetFormatNameOrEmpty(*reg_info);
|
|
|
|
if (!format.empty())
|
|
|
|
response << "format:" << format << ';';
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const char *const register_set_name =
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index);
|
2020-02-21 01:15:37 +08:00
|
|
|
if (register_set_name)
|
|
|
|
response << "set:" << register_set_name << ';';
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-08-15 09:21:01 +08:00
|
|
|
if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] !=
|
|
|
|
LLDB_INVALID_REGNUM)
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
response.Printf("ehframe:%" PRIu32 ";",
|
|
|
|
reg_info->kinds[RegisterKind::eRegisterKindEHFrame]);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
|
|
|
|
response.Printf("dwarf:%" PRIu32 ";",
|
|
|
|
reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info);
|
|
|
|
if (!kind_generic.empty())
|
|
|
|
response << "generic:" << kind_generic << ';';
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) {
|
|
|
|
response.PutCString("container-regs:");
|
2020-02-21 01:15:37 +08:00
|
|
|
CollectRegNums(reg_info->value_regs, response, true);
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutChar(';');
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) {
|
|
|
|
response.PutCString("invalidate-regs:");
|
2020-02-21 01:15:37 +08:00
|
|
|
CollectRegNums(reg_info->invalidate_regs, response, true);
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutChar(';');
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2022-06-25 21:04:26 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::AddProcessThreads(
|
|
|
|
StreamGDBRemote &response, NativeProcessProtocol &process, bool &had_any) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-25 21:04:26 +08:00
|
|
|
lldb::pid_t pid = process.GetID();
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-25 21:04:26 +08:00
|
|
|
LLDB_LOG(log, "iterating over threads of process {0}", process.GetID());
|
2022-06-28 14:24:24 +08:00
|
|
|
for (NativeThreadProtocol &thread : process.Threads()) {
|
|
|
|
LLDB_LOG(log, "iterated thread tid={0}", thread.GetID());
|
2022-06-25 21:04:26 +08:00
|
|
|
response.PutChar(had_any ? ',' : 'm');
|
2022-06-28 14:24:24 +08:00
|
|
|
AppendThreadIDToResponse(response, pid, thread.GetID());
|
2022-06-25 21:04:26 +08:00
|
|
|
had_any = true;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2022-06-25 21:04:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
assert(m_debugged_processes.size() == 1 ||
|
|
|
|
bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::multiprocess));
|
|
|
|
|
|
|
|
bool had_any = false;
|
|
|
|
StreamGDBRemote response;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-06-25 21:04:26 +08:00
|
|
|
for (auto &pid_ptr : m_debugged_processes)
|
2022-07-13 23:33:28 +08:00
|
|
|
AddProcessThreads(response, *pid_ptr.second.process_up, had_any);
|
2022-06-25 21:04:26 +08:00
|
|
|
|
|
|
|
if (!had_any)
|
|
|
|
return SendOKResponse();
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// FIXME for now we return the full thread list in the initial packet and
|
|
|
|
// always do nothing here.
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock("l");
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2019-05-30 15:25:22 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2019-05-30 15:25:22 +08:00
|
|
|
|
|
|
|
// Move past packet name.
|
|
|
|
packet.SetFilePos(strlen("g"));
|
|
|
|
|
|
|
|
// Get the thread to use.
|
|
|
|
NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
|
|
|
|
if (!thread) {
|
|
|
|
LLDB_LOG(log, "failed, no thread available");
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the thread's register context.
|
|
|
|
NativeRegisterContext ®_ctx = thread->GetRegisterContext();
|
|
|
|
|
|
|
|
std::vector<uint8_t> regs_buffer;
|
|
|
|
for (uint32_t reg_num = 0; reg_num < reg_ctx.GetUserRegisterCount();
|
|
|
|
++reg_num) {
|
|
|
|
const RegisterInfo *reg_info = reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
|
|
|
|
|
|
|
if (reg_info == nullptr) {
|
|
|
|
LLDB_LOG(log, "failed to get register info for register index {0}",
|
|
|
|
reg_num);
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg_info->value_regs != nullptr)
|
|
|
|
continue; // skip registers that are contained in other registers
|
|
|
|
|
|
|
|
RegisterValue reg_value;
|
|
|
|
Status error = reg_ctx.ReadRegister(reg_info, reg_value);
|
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log, "failed to read register at index {0}", reg_num);
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg_info->byte_offset + reg_info->byte_size >= regs_buffer.size())
|
|
|
|
// Resize the buffer to guarantee it can store the register offsetted
|
|
|
|
// data.
|
|
|
|
regs_buffer.resize(reg_info->byte_offset + reg_info->byte_size);
|
|
|
|
|
|
|
|
// Copy the register offsetted data to the buffer.
|
|
|
|
memcpy(regs_buffer.data() + reg_info->byte_offset, reg_value.GetBytes(),
|
|
|
|
reg_info->byte_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the response.
|
|
|
|
StreamGDBRemote response;
|
|
|
|
response.PutBytesAsRawHex8(regs_buffer.data(), regs_buffer.size());
|
|
|
|
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the register number from the request.
|
|
|
|
packet.SetFilePos(strlen("p"));
|
|
|
|
const uint32_t reg_index =
|
|
|
|
packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
|
|
|
|
if (reg_index == std::numeric_limits<uint32_t>::max()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, could not "
|
|
|
|
"parse register number from request \"%s\"",
|
2019-08-21 12:55:56 +08:00
|
|
|
__FUNCTION__, packet.GetStringRef().data());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread to use.
|
2017-10-17 23:52:16 +08:00
|
|
|
NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
|
|
|
|
if (!thread) {
|
|
|
|
LLDB_LOG(log, "failed, no thread available");
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread's register context.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext ®_context = thread->GetRegisterContext();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Return the end of registers response if we've iterated one past the end of
|
|
|
|
// the register set.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
if (reg_index >= reg_context.GetUserRegisterCount()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, requested "
|
|
|
|
"register %" PRIu32 " beyond register count %" PRIu32,
|
|
|
|
__FUNCTION__, reg_index, reg_context.GetUserRegisterCount());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!reg_info) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, requested "
|
|
|
|
"register %" PRIu32 " returned NULL",
|
|
|
|
__FUNCTION__, reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Build the reginfos response.
|
|
|
|
StreamGDBRemote response;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Retrieve the value
|
|
|
|
RegisterValue reg_value;
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_context.ReadRegister(reg_info, reg_value);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, read of "
|
|
|
|
"requested register %" PRIu32 " (%s) failed: %s",
|
|
|
|
__FUNCTION__, reg_index, reg_info->name, error.AsCString());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const uint8_t *const data =
|
2020-01-07 19:13:03 +08:00
|
|
|
static_cast<const uint8_t *>(reg_value.GetBytes());
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!data) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed to get data "
|
|
|
|
"bytes from requested register %" PRIu32,
|
|
|
|
__FUNCTION__, reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME flip as needed to get data in big/little endian format for this host.
|
|
|
|
for (uint32_t i = 0; i < reg_value.GetByteSize(); ++i)
|
|
|
|
response.PutHex8(data[i]);
|
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Ensure there is more content.
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Empty P packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the register number from the request.
|
|
|
|
packet.SetFilePos(strlen("P"));
|
|
|
|
const uint32_t reg_index =
|
|
|
|
packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
|
|
|
|
if (reg_index == std::numeric_limits<uint32_t>::max()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, could not "
|
|
|
|
"parse register number from request \"%s\"",
|
2019-08-21 12:55:56 +08:00
|
|
|
__FUNCTION__, packet.GetStringRef().data());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x29);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Note debugserver would send an E30 here.
|
|
|
|
if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != '='))
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "P packet missing '=' char after register number");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the value.
|
2020-04-29 10:48:45 +08:00
|
|
|
uint8_t reg_bytes[RegisterValue::kMaxRegisterByteSize];
|
2016-08-31 02:12:11 +08:00
|
|
|
size_t reg_size = packet.GetHexBytesAvail(reg_bytes);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread to use.
|
2017-10-17 23:52:16 +08:00
|
|
|
NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
|
|
|
|
if (!thread) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no thread "
|
|
|
|
"available (thread index 0)",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x28);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread's register context.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext ®_context = thread->GetRegisterContext();
|
|
|
|
const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!reg_info) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, requested "
|
|
|
|
"register %" PRIu32 " returned NULL",
|
|
|
|
__FUNCTION__, reg_index);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x48);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Return the end of registers response if we've iterated one past the end of
|
|
|
|
// the register set.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
if (reg_index >= reg_context.GetUserRegisterCount()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, requested "
|
|
|
|
"register %" PRIu32 " beyond register count %" PRIu32,
|
|
|
|
__FUNCTION__, reg_index, reg_context.GetUserRegisterCount());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x47);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2021-09-23 20:10:49 +08:00
|
|
|
if (reg_size != reg_info->byte_size)
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendIllFormedResponse(packet, "P packet register size is incorrect");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Build the reginfos response.
|
|
|
|
StreamGDBRemote response;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
RegisterValue reg_value(makeArrayRef(reg_bytes, reg_size),
|
|
|
|
m_current_process->GetArchitecture().GetByteOrder());
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_context.WriteRegister(reg_info, reg_value);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, write of "
|
|
|
|
"requested register %" PRIu32 " (%s) failed: %s",
|
|
|
|
__FUNCTION__, reg_index, reg_info->name, error.AsCString());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x32);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Parse out which variant of $H is requested.
|
|
|
|
packet.SetFilePos(strlen("H"));
|
|
|
|
if (packet.GetBytesLeft() < 1) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, H command "
|
|
|
|
"missing {g,c} variant",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendIllFormedResponse(packet, "H command missing {g,c} variant");
|
|
|
|
}
|
|
|
|
|
|
|
|
const char h_variant = packet.GetChar();
|
2021-04-11 18:31:06 +08:00
|
|
|
NativeProcessProtocol *default_process;
|
2015-02-11 18:29:30 +08:00
|
|
|
switch (h_variant) {
|
|
|
|
case 'g':
|
2021-04-11 18:31:06 +08:00
|
|
|
default_process = m_current_process;
|
2015-02-11 18:29:30 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
2021-04-11 18:31:06 +08:00
|
|
|
default_process = m_continue_process;
|
2015-02-11 18:29:30 +08:00
|
|
|
break;
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
default:
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c",
|
|
|
|
__FUNCTION__, h_variant);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"H variant unsupported, should be c or g");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the thread number.
|
2021-04-11 18:31:06 +08:00
|
|
|
auto pid_tid = packet.GetPidTid(default_process ? default_process->GetID()
|
|
|
|
: LLDB_INVALID_PROCESS_ID);
|
|
|
|
if (!pid_tid)
|
|
|
|
return SendErrorResponse(llvm::make_error<StringError>(
|
|
|
|
inconvertibleErrorCode(), "Malformed thread-id"));
|
|
|
|
|
|
|
|
lldb::pid_t pid = pid_tid->first;
|
|
|
|
lldb::tid_t tid = pid_tid->second;
|
|
|
|
|
|
|
|
if (pid == StringExtractorGDBRemote::AllProcesses)
|
|
|
|
return SendUnimplementedResponse("Selecting all processes not supported");
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendErrorResponse(llvm::make_error<StringError>(
|
|
|
|
inconvertibleErrorCode(), "No current process and no PID provided"));
|
|
|
|
|
|
|
|
// Check the process ID and find respective process instance.
|
|
|
|
auto new_process_it = m_debugged_processes.find(pid);
|
|
|
|
if (new_process_it == m_debugged_processes.end())
|
|
|
|
return SendErrorResponse(llvm::make_error<StringError>(
|
|
|
|
inconvertibleErrorCode(),
|
|
|
|
llvm::formatv("No process with PID {0} debugged", pid)));
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Ensure we have the given thread when not specifying -1 (all threads) or 0
|
|
|
|
// (any thread).
|
|
|
|
if (tid != LLDB_INVALID_THREAD_ID && tid != 0) {
|
2022-07-13 23:33:28 +08:00
|
|
|
NativeThreadProtocol *thread =
|
|
|
|
new_process_it->second.process_up->GetThreadByID(tid);
|
2017-10-17 23:52:16 +08:00
|
|
|
if (!thread) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64
|
|
|
|
" not found",
|
|
|
|
__FUNCTION__, tid);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-11 18:31:06 +08:00
|
|
|
// Now switch the given process and thread type.
|
2015-02-11 18:29:30 +08:00
|
|
|
switch (h_variant) {
|
|
|
|
case 'g':
|
2022-07-13 23:33:28 +08:00
|
|
|
m_current_process = new_process_it->second.process_up.get();
|
2015-02-11 18:29:30 +08:00
|
|
|
SetCurrentThreadID(tid);
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
case 'c':
|
2022-07-13 23:33:28 +08:00
|
|
|
m_continue_process = new_process_it->second.process_up.get();
|
2015-02-11 18:29:30 +08:00
|
|
|
SetContinueThreadID(tid);
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2015-02-11 18:29:30 +08:00
|
|
|
assert(false && "unsupported $H variant - shouldn't get here");
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"H variant unsupported, should be c or g");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
packet.SetFilePos(::strlen("I"));
|
2016-08-31 02:12:11 +08:00
|
|
|
uint8_t tmp[4096];
|
2015-02-11 18:29:30 +08:00
|
|
|
for (;;) {
|
2016-08-31 02:12:11 +08:00
|
|
|
size_t read = packet.GetHexBytesAvail(tmp);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (read == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// write directly to stdin *this might block if stdin buffer is full*
|
|
|
|
// TODO: enqueue this block in circular buffer and send window size to
|
|
|
|
// remote host
|
|
|
|
ConnectionStatus status;
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2022-08-23 00:59:08 +08:00
|
|
|
m_stdio_communication.WriteAll(tmp, read, status, &error);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_interrupt(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "failed, no process available");
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Interrupt the process.
|
2021-04-11 17:37:36 +08:00
|
|
|
Status error = m_current_process->Interrupt();
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2021-04-11 17:37:36 +08:00
|
|
|
LLDB_LOG(log, "failed for process {0}: {1}", m_current_process->GetID(),
|
2017-07-18 17:24:48 +08:00
|
|
|
error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
LLDB_LOG(log, "stopped process {0}", m_current_process->GetID());
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// No response required from stop all.
|
|
|
|
return PacketResult::Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
2015-10-14 20:59:37 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_memory_read(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the memory address.
|
|
|
|
packet.SetFilePos(strlen("m"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short m packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Read the address. Punting on validation.
|
|
|
|
// FIXME replace with Hex U64 read with no default value that fails on failed
|
|
|
|
// read.
|
|
|
|
const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Validate comma.
|
|
|
|
if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
|
|
|
|
return SendIllFormedResponse(packet, "Comma sep missing in m packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get # bytes to read.
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Length missing in m packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
|
|
|
|
if (byte_count == 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s nothing to read: "
|
|
|
|
"zero-length packet",
|
|
|
|
__FUNCTION__);
|
2015-10-14 20:59:37 +08:00
|
|
|
return SendOKResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Allocate the response buffer.
|
|
|
|
std::string buf(byte_count, '\0');
|
|
|
|
if (buf.empty())
|
|
|
|
return SendErrorResponse(0x78);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Retrieve the process memory.
|
2015-04-30 01:24:48 +08:00
|
|
|
size_t bytes_read = 0;
|
2021-04-11 17:37:36 +08:00
|
|
|
Status error = m_current_process->ReadMemoryWithoutTrap(
|
2015-04-30 01:24:48 +08:00
|
|
|
read_addr, &buf[0], byte_count, bytes_read);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
|
|
|
|
" mem 0x%" PRIx64 ": failed to read. Error: %s",
|
2021-04-11 17:37:36 +08:00
|
|
|
__FUNCTION__, m_current_process->GetID(), read_addr,
|
2019-07-25 01:56:10 +08:00
|
|
|
error.AsCString());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x08);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (bytes_read == 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
|
|
|
|
" mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes",
|
2021-04-11 17:37:36 +08:00
|
|
|
__FUNCTION__, m_current_process->GetID(), read_addr, byte_count);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x08);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamGDBRemote response;
|
2015-10-14 20:59:37 +08:00
|
|
|
packet.SetFilePos(0);
|
|
|
|
char kind = packet.GetChar('?');
|
|
|
|
if (kind == 'x')
|
|
|
|
response.PutEscapedBytes(buf.data(), byte_count);
|
|
|
|
else {
|
|
|
|
assert(kind == 'm');
|
|
|
|
for (size_t i = 0; i < bytes_read; ++i)
|
|
|
|
response.PutHex8(buf[i]);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2020-10-09 19:59:50 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2020-10-09 19:59:50 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2020-10-09 19:59:50 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse out the memory address.
|
|
|
|
packet.SetFilePos(strlen("_M"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short _M packet");
|
|
|
|
|
|
|
|
const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
|
|
|
|
if (size == LLDB_INVALID_ADDRESS)
|
|
|
|
return SendIllFormedResponse(packet, "Address not valid");
|
|
|
|
if (packet.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(packet, "Bad packet");
|
|
|
|
Permissions perms = {};
|
|
|
|
while (packet.GetBytesLeft() > 0) {
|
|
|
|
switch (packet.GetChar()) {
|
|
|
|
case 'r':
|
|
|
|
perms |= ePermissionsReadable;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
perms |= ePermissionsWritable;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
perms |= ePermissionsExecutable;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return SendIllFormedResponse(packet, "Bad permissions");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
llvm::Expected<addr_t> addr = m_current_process->AllocateMemory(size, perms);
|
2020-10-09 19:59:50 +08:00
|
|
|
if (!addr)
|
|
|
|
return SendErrorResponse(addr.takeError());
|
|
|
|
|
|
|
|
StreamGDBRemote response;
|
|
|
|
response.PutHex64(*addr);
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2020-10-09 19:59:50 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2020-10-09 19:59:50 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse out the memory address.
|
|
|
|
packet.SetFilePos(strlen("_m"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short m packet");
|
|
|
|
|
|
|
|
const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
|
|
|
|
if (addr == LLDB_INVALID_ADDRESS)
|
|
|
|
return SendIllFormedResponse(packet, "Address not valid");
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (llvm::Error Err = m_current_process->DeallocateMemory(addr))
|
2020-10-09 19:59:50 +08:00
|
|
|
return SendErrorResponse(std::move(Err));
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the memory address.
|
|
|
|
packet.SetFilePos(strlen("M"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short M packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Read the address. Punting on validation.
|
|
|
|
// FIXME replace with Hex U64 read with no default value that fails on failed
|
|
|
|
// read.
|
|
|
|
const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Validate comma.
|
|
|
|
if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
|
|
|
|
return SendIllFormedResponse(packet, "Comma sep missing in M packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get # bytes to read.
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Length missing in M packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
|
|
|
|
if (byte_count == 0) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "nothing to write: zero-length packet");
|
2015-02-11 18:29:30 +08:00
|
|
|
return PacketResult::Success;
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Validate colon.
|
|
|
|
if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Comma sep missing in M packet after byte length");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Allocate the conversion buffer.
|
|
|
|
std::vector<uint8_t> buf(byte_count, 0);
|
|
|
|
if (buf.empty())
|
|
|
|
return SendErrorResponse(0x78);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Convert the hex memory write contents to bytes.
|
|
|
|
StreamGDBRemote response;
|
2016-08-31 02:12:11 +08:00
|
|
|
const uint64_t convert_count = packet.GetHexBytes(buf, 0);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (convert_count != byte_count) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log,
|
|
|
|
"pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} "
|
|
|
|
"to convert.",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), write_addr, byte_count, convert_count);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendIllFormedResponse(packet, "M content byte length specified did "
|
|
|
|
"not match hex-encoded content "
|
|
|
|
"length");
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Write the process memory.
|
2015-04-30 01:24:48 +08:00
|
|
|
size_t bytes_written = 0;
|
2021-04-11 17:37:36 +08:00
|
|
|
Status error = m_current_process->WriteMemory(write_addr, &buf[0], byte_count,
|
|
|
|
bytes_written);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), write_addr, error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (bytes_written == 0) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), write_addr, byte_count);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Currently only the NativeProcessProtocol knows if it can handle a
|
2018-05-01 00:49:04 +08:00
|
|
|
// qMemoryRegionInfoSupported request, but we're not guaranteed to be
|
|
|
|
// attached to a process. For now we'll assume the client only asks this
|
|
|
|
// when a process is being debugged.
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Ensure we have a process running; otherwise, we can't figure this out
|
|
|
|
// since we won't have a NativeProcessProtocol.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test if we can get any region back when asking for the region around NULL.
|
|
|
|
MemoryRegionInfo region_info;
|
2021-04-11 17:37:36 +08:00
|
|
|
const Status error = m_current_process->GetMemoryRegionInfo(0, region_info);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
|
|
|
// We don't support memory region info collection for this
|
|
|
|
// NativeProcessProtocol.
|
|
|
|
return SendUnimplementedResponse("");
|
|
|
|
}
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Ensure we have a process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the memory address.
|
|
|
|
packet.SetFilePos(strlen("qMemoryRegionInfo:"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Read the address. Punting on validation.
|
|
|
|
const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamGDBRemote response;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the memory region info for the target address.
|
|
|
|
MemoryRegionInfo region_info;
|
2017-05-12 12:51:55 +08:00
|
|
|
const Status error =
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetMemoryRegionInfo(read_addr, region_info);
|
2015-06-19 04:43:56 +08:00
|
|
|
if (error.Fail()) {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Return the error message.
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
response.PutCString("error:");
|
2019-02-12 22:28:55 +08:00
|
|
|
response.PutStringAsRawHex8(error.AsCString());
|
2016-07-22 20:55:35 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
} else {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Range start and size.
|
|
|
|
response.Printf("start:%" PRIx64 ";size:%" PRIx64 ";",
|
|
|
|
region_info.GetRange().GetRangeBase(),
|
|
|
|
region_info.GetRange().GetByteSize());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Permissions.
|
|
|
|
if (region_info.GetReadable() || region_info.GetWritable() ||
|
|
|
|
region_info.GetExecutable()) {
|
|
|
|
// Write permissions info.
|
|
|
|
response.PutCString("permissions:");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (region_info.GetReadable())
|
|
|
|
response.PutChar('r');
|
|
|
|
if (region_info.GetWritable())
|
|
|
|
response.PutChar('w');
|
|
|
|
if (region_info.GetExecutable())
|
|
|
|
response.PutChar('x');
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-07-22 20:55:35 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2020-08-17 22:02:04 +08:00
|
|
|
// Flags
|
|
|
|
MemoryRegionInfo::OptionalBool memory_tagged =
|
|
|
|
region_info.GetMemoryTagged();
|
|
|
|
if (memory_tagged != MemoryRegionInfo::eDontKnow) {
|
|
|
|
response.PutCString("flags:");
|
|
|
|
if (memory_tagged == MemoryRegionInfo::eYes) {
|
|
|
|
response.PutCString("mt");
|
|
|
|
}
|
|
|
|
response.PutChar(';');
|
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
// Name
|
2016-07-22 20:55:35 +08:00
|
|
|
ConstString name = region_info.GetName();
|
|
|
|
if (name) {
|
|
|
|
response.PutCString("name:");
|
2020-02-11 16:05:37 +08:00
|
|
|
response.PutStringAsRawHex8(name.GetStringRef());
|
2016-07-22 20:55:35 +08:00
|
|
|
response.PutChar(';');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) {
|
|
|
|
// Ensure we have a process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "failed, no process available");
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out software or hardware breakpoint or watchpoint requested.
|
|
|
|
packet.SetFilePos(strlen("Z"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Too short Z packet, missing software/hardware specifier");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
bool want_breakpoint = true;
|
|
|
|
bool want_hardware = false;
|
2015-08-12 19:30:21 +08:00
|
|
|
uint32_t watch_flags = 0;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const GDBStoppointType stoppoint_type =
|
|
|
|
GDBStoppointType(packet.GetS32(eStoppointInvalid));
|
|
|
|
switch (stoppoint_type) {
|
|
|
|
case eBreakpointSoftware:
|
|
|
|
want_hardware = false;
|
|
|
|
want_breakpoint = true;
|
|
|
|
break;
|
|
|
|
case eBreakpointHardware:
|
|
|
|
want_hardware = true;
|
|
|
|
want_breakpoint = true;
|
|
|
|
break;
|
|
|
|
case eWatchpointWrite:
|
2015-08-12 19:30:21 +08:00
|
|
|
watch_flags = 1;
|
2015-02-11 18:29:30 +08:00
|
|
|
want_hardware = true;
|
|
|
|
want_breakpoint = false;
|
|
|
|
break;
|
|
|
|
case eWatchpointRead:
|
2015-08-12 19:30:21 +08:00
|
|
|
watch_flags = 2;
|
2015-02-11 18:29:30 +08:00
|
|
|
want_hardware = true;
|
|
|
|
want_breakpoint = false;
|
|
|
|
break;
|
|
|
|
case eWatchpointReadWrite:
|
2015-08-12 19:30:21 +08:00
|
|
|
watch_flags = 3;
|
2015-02-11 18:29:30 +08:00
|
|
|
want_hardware = true;
|
|
|
|
want_breakpoint = false;
|
|
|
|
break;
|
|
|
|
case eStoppointInvalid:
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Z packet had invalid software/hardware specifier");
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Malformed Z packet, expecting comma after stoppoint type");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the stoppoint address.
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short Z packet, missing address");
|
|
|
|
const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Malformed Z packet, expecting comma after address");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the stoppoint size (i.e. size hint for opcode size).
|
|
|
|
const uint32_t size =
|
|
|
|
packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
|
|
|
|
if (size == std::numeric_limits<uint32_t>::max())
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Malformed Z packet, failed to parse size argument");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (want_breakpoint) {
|
|
|
|
// Try to set the breakpoint.
|
2017-05-12 12:51:55 +08:00
|
|
|
const Status error =
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->SetBreakpoint(addr, size, want_hardware);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Success())
|
|
|
|
return SendOKResponse();
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Breakpoints);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
} else {
|
|
|
|
// Try to set the watchpoint.
|
2021-04-11 17:37:36 +08:00
|
|
|
const Status error = m_current_process->SetWatchpoint(
|
2015-02-11 18:29:30 +08:00
|
|
|
addr, size, watch_flags, want_hardware);
|
|
|
|
if (error.Success())
|
|
|
|
return SendOKResponse();
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Watchpoints);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
|
|
|
|
// Ensure we have a process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "failed, no process available");
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out software or hardware breakpoint or watchpoint requested.
|
|
|
|
packet.SetFilePos(strlen("z"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Too short z packet, missing software/hardware specifier");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
bool want_breakpoint = true;
|
2017-02-24 21:27:31 +08:00
|
|
|
bool want_hardware = false;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const GDBStoppointType stoppoint_type =
|
|
|
|
GDBStoppointType(packet.GetS32(eStoppointInvalid));
|
|
|
|
switch (stoppoint_type) {
|
|
|
|
case eBreakpointHardware:
|
|
|
|
want_breakpoint = true;
|
2017-02-24 21:27:31 +08:00
|
|
|
want_hardware = true;
|
2015-02-11 18:29:30 +08:00
|
|
|
break;
|
|
|
|
case eBreakpointSoftware:
|
|
|
|
want_breakpoint = true;
|
|
|
|
break;
|
|
|
|
case eWatchpointWrite:
|
|
|
|
want_breakpoint = false;
|
|
|
|
break;
|
|
|
|
case eWatchpointRead:
|
|
|
|
want_breakpoint = false;
|
|
|
|
break;
|
|
|
|
case eWatchpointReadWrite:
|
|
|
|
want_breakpoint = false;
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
2015-02-11 18:29:30 +08:00
|
|
|
default:
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "z packet had invalid software/hardware specifier");
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Malformed z packet, expecting comma after stoppoint type");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the stoppoint address.
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(packet, "Too short z packet, missing address");
|
|
|
|
const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Malformed z packet, expecting comma after address");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
/*
|
|
|
|
// Parse out the stoppoint size (i.e. size hint for opcode size).
|
|
|
|
const uint32_t size = packet.GetHexMaxU32 (false,
|
|
|
|
std::numeric_limits<uint32_t>::max ());
|
|
|
|
if (size == std::numeric_limits<uint32_t>::max ())
|
|
|
|
return SendIllFormedResponse(packet, "Malformed z packet, failed to parse
|
|
|
|
size argument");
|
|
|
|
*/
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (want_breakpoint) {
|
|
|
|
// Try to clear the breakpoint.
|
2017-05-12 12:51:55 +08:00
|
|
|
const Status error =
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->RemoveBreakpoint(addr, want_hardware);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Success())
|
|
|
|
return SendOKResponse();
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Breakpoints);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
} else {
|
|
|
|
// Try to clear the watchpoint.
|
2021-04-11 17:37:36 +08:00
|
|
|
const Status error = m_current_process->RemoveWatchpoint(addr);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Success())
|
|
|
|
return SendOKResponse();
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Watchpoints);
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x09);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Ensure we have a process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_continue_process ||
|
|
|
|
(m_continue_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x32);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// We first try to use a continue thread id. If any one or any all set, use
|
2018-05-01 00:49:04 +08:00
|
|
|
// the current thread. Bail out if we don't have a thread id.
|
2015-02-11 18:29:30 +08:00
|
|
|
lldb::tid_t tid = GetContinueThreadID();
|
|
|
|
if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
|
|
|
|
tid = GetCurrentThreadID();
|
|
|
|
if (tid == LLDB_INVALID_THREAD_ID)
|
|
|
|
return SendErrorResponse(0x33);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Double check that we have such a thread.
|
|
|
|
// TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
|
2021-04-11 17:37:36 +08:00
|
|
|
NativeThreadProtocol *thread = m_continue_process->GetThreadByID(tid);
|
2017-10-17 23:52:16 +08:00
|
|
|
if (!thread)
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x33);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Create the step action for the given thread.
|
2019-09-19 13:49:14 +08:00
|
|
|
ResumeAction action = {tid, eStateStepping, LLDB_INVALID_SIGNAL_NUMBER};
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Setup the actions list.
|
2015-03-31 17:52:22 +08:00
|
|
|
ResumeActionList actions;
|
2015-02-11 18:29:30 +08:00
|
|
|
actions.Append(action);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// All other threads stop while we're single stepping a thread.
|
|
|
|
actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
|
2022-06-28 12:00:46 +08:00
|
|
|
|
|
|
|
PacketResult resume_res = ResumeProcess(*m_continue_process, actions);
|
|
|
|
if (resume_res != PacketResult::Success)
|
|
|
|
return resume_res;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
// No response here, unless in non-stop mode.
|
|
|
|
// Otherwise, the stop or exit will come from the resulting action.
|
|
|
|
return SendContinueSuccessResponse();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
|
|
|
GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
|
|
|
|
// Ensure we have a thread.
|
2021-04-11 17:37:36 +08:00
|
|
|
NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0);
|
2020-02-21 01:15:37 +08:00
|
|
|
if (!thread)
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"No thread available");
|
|
|
|
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2020-02-21 01:15:37 +08:00
|
|
|
// Get the register context for the first thread.
|
|
|
|
NativeRegisterContext ®_context = thread->GetRegisterContext();
|
|
|
|
|
|
|
|
StreamString response;
|
|
|
|
|
|
|
|
response.Printf("<?xml version=\"1.0\"?>");
|
|
|
|
response.Printf("<target version=\"1.0\">");
|
|
|
|
|
|
|
|
response.Printf("<architecture>%s</architecture>",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetArchitecture()
|
2020-02-21 01:15:37 +08:00
|
|
|
.GetTriple()
|
|
|
|
.getArchName()
|
|
|
|
.str()
|
|
|
|
.c_str());
|
|
|
|
|
|
|
|
response.Printf("<feature>");
|
|
|
|
|
|
|
|
const int registers_count = reg_context.GetUserRegisterCount();
|
|
|
|
for (int reg_index = 0; reg_index < registers_count; reg_index++) {
|
|
|
|
const RegisterInfo *reg_info =
|
|
|
|
reg_context.GetRegisterInfoAtIndex(reg_index);
|
|
|
|
|
|
|
|
if (!reg_info) {
|
|
|
|
LLDB_LOGF(log,
|
|
|
|
"%s failed to get register info for register index %" PRIu32,
|
|
|
|
"target.xml", reg_index);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-12-02 06:09:14 +08:00
|
|
|
response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ",
|
|
|
|
reg_info->name, reg_info->byte_size * 8, reg_index);
|
|
|
|
|
|
|
|
if (!reg_context.RegisterOffsetIsDynamic())
|
|
|
|
response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset);
|
2020-02-21 01:15:37 +08:00
|
|
|
|
|
|
|
if (reg_info->alt_name && reg_info->alt_name[0])
|
|
|
|
response.Printf("altname=\"%s\" ", reg_info->alt_name);
|
|
|
|
|
|
|
|
llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
|
|
|
|
if (!encoding.empty())
|
|
|
|
response << "encoding=\"" << encoding << "\" ";
|
|
|
|
|
|
|
|
llvm::StringRef format = GetFormatNameOrEmpty(*reg_info);
|
|
|
|
if (!format.empty())
|
|
|
|
response << "format=\"" << format << "\" ";
|
|
|
|
|
|
|
|
const char *const register_set_name =
|
|
|
|
reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index);
|
|
|
|
if (register_set_name)
|
|
|
|
response << "group=\"" << register_set_name << "\" ";
|
|
|
|
|
|
|
|
if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] !=
|
|
|
|
LLDB_INVALID_REGNUM)
|
|
|
|
response.Printf("ehframe_regnum=\"%" PRIu32 "\" ",
|
|
|
|
reg_info->kinds[RegisterKind::eRegisterKindEHFrame]);
|
|
|
|
|
|
|
|
if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] !=
|
|
|
|
LLDB_INVALID_REGNUM)
|
|
|
|
response.Printf("dwarf_regnum=\"%" PRIu32 "\" ",
|
|
|
|
reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
|
|
|
|
|
|
|
|
llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info);
|
|
|
|
if (!kind_generic.empty())
|
|
|
|
response << "generic=\"" << kind_generic << "\" ";
|
|
|
|
|
|
|
|
if (reg_info->value_regs &&
|
|
|
|
reg_info->value_regs[0] != LLDB_INVALID_REGNUM) {
|
|
|
|
response.PutCString("value_regnums=\"");
|
|
|
|
CollectRegNums(reg_info->value_regs, response, false);
|
|
|
|
response.Printf("\" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) {
|
|
|
|
response.PutCString("invalidate_regnums=\"");
|
|
|
|
CollectRegNums(reg_info->invalidate_regs, response, false);
|
|
|
|
response.Printf("\" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Printf("/>");
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Printf("</feature>");
|
|
|
|
response.Printf("</target>");
|
|
|
|
return MemoryBuffer::getMemBufferCopy(response.GetString(), "target.xml");
|
|
|
|
}
|
|
|
|
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
|
|
|
GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
|
|
|
|
llvm::StringRef annex) {
|
2020-02-21 01:15:37 +08:00
|
|
|
// Make sure we have a valid process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
2020-02-21 01:15:37 +08:00
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"No process available");
|
|
|
|
}
|
2020-02-18 13:16:52 +08:00
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
if (object == "auxv") {
|
2015-02-11 18:29:30 +08:00
|
|
|
// Grab the auxv data.
|
2021-04-11 17:37:36 +08:00
|
|
|
auto buffer_or_error = m_current_process->GetAuxvData();
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
if (!buffer_or_error)
|
|
|
|
return llvm::errorCodeToError(buffer_or_error.getError());
|
|
|
|
return std::move(*buffer_or_error);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-01-12 03:28:37 +08:00
|
|
|
if (object == "siginfo") {
|
|
|
|
NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
|
|
|
|
if (!thread)
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"no current thread");
|
|
|
|
|
|
|
|
auto buffer_or_error = thread->GetSiginfo();
|
|
|
|
if (!buffer_or_error)
|
|
|
|
return buffer_or_error.takeError();
|
|
|
|
return std::move(*buffer_or_error);
|
|
|
|
}
|
|
|
|
|
2019-07-24 04:40:30 +08:00
|
|
|
if (object == "libraries-svr4") {
|
2021-04-11 17:37:36 +08:00
|
|
|
auto library_list = m_current_process->GetLoadedSVR4Libraries();
|
2019-07-24 04:40:30 +08:00
|
|
|
if (!library_list)
|
|
|
|
return library_list.takeError();
|
|
|
|
|
|
|
|
StreamString response;
|
|
|
|
response.Printf("<library-list-svr4 version=\"1.0\">");
|
|
|
|
for (auto const &library : *library_list) {
|
|
|
|
response.Printf("<library name=\"%s\" ",
|
|
|
|
XMLEncodeAttributeValue(library.name.c_str()).c_str());
|
|
|
|
response.Printf("lm=\"0x%" PRIx64 "\" ", library.link_map);
|
|
|
|
response.Printf("l_addr=\"0x%" PRIx64 "\" ", library.base_addr);
|
|
|
|
response.Printf("l_ld=\"0x%" PRIx64 "\" />", library.ld_addr);
|
|
|
|
}
|
|
|
|
response.Printf("</library-list-svr4>");
|
|
|
|
return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2020-02-21 01:15:37 +08:00
|
|
|
if (object == "features" && annex == "target.xml")
|
|
|
|
return BuildTargetXml();
|
|
|
|
|
2020-10-09 17:23:17 +08:00
|
|
|
return llvm::make_error<UnimplementedError>();
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qXfer(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
SmallVector<StringRef, 5> fields;
|
|
|
|
// The packet format is "qXfer:<object>:<action>:<annex>:offset,length"
|
|
|
|
StringRef(packet.GetStringRef()).split(fields, ':', 4);
|
|
|
|
if (fields.size() != 5)
|
|
|
|
return SendIllFormedResponse(packet, "malformed qXfer packet");
|
|
|
|
StringRef &xfer_object = fields[1];
|
|
|
|
StringRef &xfer_action = fields[2];
|
|
|
|
StringRef &xfer_annex = fields[3];
|
|
|
|
StringExtractor offset_data(fields[4]);
|
|
|
|
if (xfer_action != "read")
|
|
|
|
return SendUnimplementedResponse("qXfer action not supported");
|
|
|
|
// Parse offset.
|
|
|
|
const uint64_t xfer_offset =
|
|
|
|
offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max());
|
|
|
|
if (xfer_offset == std::numeric_limits<uint64_t>::max())
|
|
|
|
return SendIllFormedResponse(packet, "qXfer packet missing offset");
|
|
|
|
// Parse out comma.
|
|
|
|
if (offset_data.GetChar() != ',')
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"qXfer packet missing comma after offset");
|
|
|
|
// Parse out the length.
|
|
|
|
const uint64_t xfer_length =
|
|
|
|
offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max());
|
|
|
|
if (xfer_length == std::numeric_limits<uint64_t>::max())
|
|
|
|
return SendIllFormedResponse(packet, "qXfer packet missing length");
|
|
|
|
|
|
|
|
// Get a previously constructed buffer if it exists or create it now.
|
|
|
|
std::string buffer_key = (xfer_object + xfer_action + xfer_annex).str();
|
|
|
|
auto buffer_it = m_xfer_buffer_map.find(buffer_key);
|
|
|
|
if (buffer_it == m_xfer_buffer_map.end()) {
|
|
|
|
auto buffer_up = ReadXferObject(xfer_object, xfer_annex);
|
|
|
|
if (!buffer_up)
|
|
|
|
return SendErrorResponse(buffer_up.takeError());
|
|
|
|
buffer_it = m_xfer_buffer_map
|
|
|
|
.insert(std::make_pair(buffer_key, std::move(*buffer_up)))
|
|
|
|
.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send back the response
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamGDBRemote response;
|
|
|
|
bool done_with_buffer = false;
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
llvm::StringRef buffer = buffer_it->second->getBuffer();
|
|
|
|
if (xfer_offset >= buffer.size()) {
|
2015-02-11 18:29:30 +08:00
|
|
|
// We have nothing left to send. Mark the buffer as complete.
|
|
|
|
response.PutChar('l');
|
|
|
|
done_with_buffer = true;
|
|
|
|
} else {
|
|
|
|
// Figure out how many bytes are available starting at the given offset.
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
buffer = buffer.drop_front(xfer_offset);
|
2015-02-11 18:29:30 +08:00
|
|
|
// Mark the response type according to whether we're reading the remainder
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
// of the data.
|
|
|
|
if (xfer_length >= buffer.size()) {
|
2015-02-11 18:29:30 +08:00
|
|
|
// There will be nothing left to read after this
|
|
|
|
response.PutChar('l');
|
|
|
|
done_with_buffer = true;
|
|
|
|
} else {
|
|
|
|
// There will still be bytes to read after this request.
|
|
|
|
response.PutChar('m');
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
buffer = buffer.take_front(xfer_length);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
// Now write the data in encoded binary form.
|
2017-03-17 19:08:40 +08:00
|
|
|
response.PutEscapedBytes(buffer.data(), buffer.size());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
if (done_with_buffer)
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
m_xfer_buffer_map.erase(buffer_it);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Move past packet name.
|
|
|
|
packet.SetFilePos(strlen("QSaveRegisterState"));
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread to use.
|
2017-10-17 23:52:16 +08:00
|
|
|
NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
|
|
|
|
if (!thread) {
|
2015-02-11 18:29:30 +08:00
|
|
|
if (m_thread_suffix_supported)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "No thread specified in QSaveRegisterState packet");
|
|
|
|
else
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"No thread was is set with the Hg packet");
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Grab the register context for the thread.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext& reg_context = thread->GetRegisterContext();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Save registers to a buffer.
|
2022-04-06 05:17:26 +08:00
|
|
|
WritableDataBufferSP register_data_sp;
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_context.ReadAllRegisterValues(register_data_sp);
|
2015-06-19 04:43:56 +08:00
|
|
|
if (error.Fail()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to save all register values: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x75);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Allocate a new save id.
|
|
|
|
const uint32_t save_id = GetNextSavedRegistersID();
|
|
|
|
assert((m_saved_registers_map.find(save_id) == m_saved_registers_map.end()) &&
|
|
|
|
"GetNextRegisterSaveID() returned an existing register save id");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Save the register data buffer under the save id.
|
|
|
|
{
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
|
2015-02-11 18:29:30 +08:00
|
|
|
m_saved_registers_map[save_id] = register_data_sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the response.
|
|
|
|
StreamGDBRemote response;
|
|
|
|
response.Printf("%" PRIu32, save_id);
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out save id.
|
|
|
|
packet.SetFilePos(strlen("QRestoreRegisterState:"));
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "QRestoreRegisterState packet missing register save id");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
const uint32_t save_id = packet.GetU32(0);
|
|
|
|
if (save_id == 0) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "QRestoreRegisterState packet has malformed save id, "
|
|
|
|
"expecting decimal uint32_t");
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x76);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Get the thread to use.
|
2017-10-17 23:52:16 +08:00
|
|
|
NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
|
|
|
|
if (!thread) {
|
2015-02-11 18:29:30 +08:00
|
|
|
if (m_thread_suffix_supported)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "No thread specified in QRestoreRegisterState packet");
|
|
|
|
else
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"No thread was is set with the Hg packet");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab the register context for the thread.
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
NativeRegisterContext ®_context = thread->GetRegisterContext();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Retrieve register state buffer, then remove from the list.
|
|
|
|
DataBufferSP register_data_sp;
|
2016-09-07 04:57:50 +08:00
|
|
|
{
|
2015-02-11 18:29:30 +08:00
|
|
|
std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
|
|
|
|
|
|
|
|
// Find the register set buffer for the given save id.
|
|
|
|
auto it = m_saved_registers_map.find(save_id);
|
|
|
|
if (it == m_saved_registers_map.end()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log,
|
|
|
|
"pid {0} does not have a register set save buffer for id {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), save_id);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x77);
|
|
|
|
}
|
|
|
|
register_data_sp = it->second;
|
|
|
|
|
|
|
|
// Remove it from the map.
|
|
|
|
m_saved_registers_map.erase(it);
|
|
|
|
}
|
|
|
|
|
Clean up NativeRegisterContext
Summary:
This commit removes the concrete_frame_idx member from
NativeRegisterContext and related functions, which was always set to
zero and never used.
I also change the native thread class to store a NativeRegisterContext
as a unique_ptr (documenting the ownership) and make sure it is always
initialized (most of the code was already blindly dereferencing the
register context pointer, assuming it would always be present -- this
makes its treatment consistent).
Reviewers: eugene, clayborg, krytarowski
Subscribers: aemerson, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, uweigand, alexandreyy, lldb-commits
Differential Revision: https://reviews.llvm.org/D39837
llvm-svn: 317881
2017-11-10 19:05:49 +08:00
|
|
|
Status error = reg_context.WriteAllRegisterValues(register_data_sp);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (error.Fail()) {
|
2017-07-18 17:24:48 +08:00
|
|
|
LLDB_LOG(log, "pid {0} failed to restore all register values: {1}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID(), error);
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x77);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vAttach(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Consume the ';' after vAttach.
|
|
|
|
packet.SetFilePos(strlen("vAttach"));
|
|
|
|
if (!packet.GetBytesLeft() || packet.GetChar() != ';')
|
|
|
|
return SendIllFormedResponse(packet, "vAttach missing expected ';'");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Grab the PID to which we will attach (assume hex encoding).
|
|
|
|
lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"vAttach failed to parse the process id");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Attempt to attach.
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s attempting to attach to "
|
|
|
|
"pid %" PRIu64,
|
|
|
|
__FUNCTION__, pid);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error = AttachToProcess(pid);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-06-19 04:43:56 +08:00
|
|
|
if (error.Fail()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed to attach to "
|
|
|
|
"pid %" PRIu64 ": %s\n",
|
|
|
|
__FUNCTION__, pid, error.AsCString());
|
2018-04-11 21:30:54 +08:00
|
|
|
return SendErrorResponse(error);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Notify we attached by sending a stop packet.
|
2022-06-10 00:54:50 +08:00
|
|
|
assert(m_current_process);
|
|
|
|
return SendStopReasonForState(*m_current_process,
|
2022-04-12 22:21:09 +08:00
|
|
|
m_current_process->GetState(),
|
|
|
|
/*force_synchronous=*/false);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2021-01-14 16:24:31 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-01-14 16:24:31 +08:00
|
|
|
|
|
|
|
// Consume the ';' after the identifier.
|
|
|
|
packet.SetFilePos(strlen("vAttachWait"));
|
|
|
|
|
|
|
|
if (!packet.GetBytesLeft() || packet.GetChar() != ';')
|
|
|
|
return SendIllFormedResponse(packet, "vAttachWait missing expected ';'");
|
|
|
|
|
|
|
|
// Allocate the buffer for the process name from vAttachWait.
|
|
|
|
std::string process_name;
|
|
|
|
if (!packet.GetHexByteString(process_name))
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"vAttachWait failed to parse process name");
|
|
|
|
|
|
|
|
LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
|
|
|
|
|
2021-01-25 04:29:59 +08:00
|
|
|
Status error = AttachWaitProcess(process_name, false);
|
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
|
|
|
|
error);
|
|
|
|
return SendErrorResponse(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify we attached by sending a stop packet.
|
2022-06-10 00:54:50 +08:00
|
|
|
assert(m_current_process);
|
|
|
|
return SendStopReasonForState(*m_current_process,
|
2022-04-12 22:21:09 +08:00
|
|
|
m_current_process->GetState(),
|
|
|
|
/*force_synchronous=*/false);
|
2021-01-25 04:29:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-01-25 04:29:59 +08:00
|
|
|
|
|
|
|
// Consume the ';' after the identifier.
|
|
|
|
packet.SetFilePos(strlen("vAttachOrWait"));
|
|
|
|
|
|
|
|
if (!packet.GetBytesLeft() || packet.GetChar() != ';')
|
|
|
|
return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'");
|
|
|
|
|
|
|
|
// Allocate the buffer for the process name from vAttachWait.
|
|
|
|
std::string process_name;
|
|
|
|
if (!packet.GetHexByteString(process_name))
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"vAttachOrWait failed to parse process name");
|
|
|
|
|
|
|
|
LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
|
|
|
|
|
|
|
|
Status error = AttachWaitProcess(process_name, true);
|
2021-01-14 16:24:31 +08:00
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
|
|
|
|
error);
|
|
|
|
return SendErrorResponse(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify we attached by sending a stop packet.
|
2022-06-10 00:54:50 +08:00
|
|
|
assert(m_current_process);
|
|
|
|
return SendStopReasonForState(*m_current_process,
|
2022-04-12 22:21:09 +08:00
|
|
|
m_current_process->GetState(),
|
|
|
|
/*force_synchronous=*/false);
|
2021-01-14 16:24:31 +08:00
|
|
|
}
|
|
|
|
|
2021-08-12 04:58:11 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vRun(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-08-12 04:58:11 +08:00
|
|
|
|
|
|
|
llvm::StringRef s = packet.GetStringRef();
|
|
|
|
if (!s.consume_front("vRun;"))
|
|
|
|
return SendErrorResponse(8);
|
|
|
|
|
|
|
|
llvm::SmallVector<llvm::StringRef, 16> argv;
|
|
|
|
s.split(argv, ';');
|
|
|
|
|
|
|
|
for (llvm::StringRef hex_arg : argv) {
|
|
|
|
StringExtractor arg_ext{hex_arg};
|
|
|
|
std::string arg;
|
|
|
|
arg_ext.GetHexByteString(arg);
|
|
|
|
m_process_launch_info.GetArguments().AppendArgument(arg);
|
|
|
|
LLDB_LOGF(log, "LLGSPacketHandler::%s added arg: \"%s\"", __FUNCTION__,
|
|
|
|
arg.c_str());
|
|
|
|
}
|
|
|
|
|
2022-09-06 21:36:23 +08:00
|
|
|
if (argv.empty())
|
|
|
|
return SendErrorResponse(Status("No arguments"));
|
|
|
|
m_process_launch_info.GetExecutableFile().SetFile(
|
|
|
|
m_process_launch_info.GetArguments()[0].ref(), FileSpec::Style::native);
|
|
|
|
m_process_launch_error = LaunchProcess();
|
|
|
|
if (m_process_launch_error.Fail())
|
|
|
|
return SendErrorResponse(m_process_launch_error);
|
|
|
|
assert(m_current_process);
|
|
|
|
return SendStopReasonForState(*m_current_process,
|
|
|
|
m_current_process->GetState(),
|
|
|
|
/*force_synchronous=*/true);
|
2021-08-12 04:58:11 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
|
2022-06-08 19:09:08 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Consume the ';' after D.
|
|
|
|
packet.SetFilePos(1);
|
2015-06-19 04:43:56 +08:00
|
|
|
if (packet.GetBytesLeft()) {
|
2015-02-11 18:29:30 +08:00
|
|
|
if (packet.GetChar() != ';')
|
|
|
|
return SendIllFormedResponse(packet, "D missing expected ';'");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Grab the PID from which we will detach (assume hex encoding).
|
|
|
|
pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendIllFormedResponse(packet, "D failed to parse the process id");
|
|
|
|
}
|
|
|
|
|
2021-04-13 23:32:23 +08:00
|
|
|
// Detach forked children if their PID was specified *or* no PID was requested
|
|
|
|
// (i.e. detach-all packet).
|
|
|
|
llvm::Error detach_error = llvm::Error::success();
|
|
|
|
bool detached = false;
|
|
|
|
for (auto it = m_debugged_processes.begin();
|
|
|
|
it != m_debugged_processes.end();) {
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) {
|
2022-06-08 19:09:08 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s detaching %" PRId64,
|
|
|
|
__FUNCTION__, it->first);
|
2022-07-13 23:33:28 +08:00
|
|
|
if (llvm::Error e = it->second.process_up->Detach().ToError())
|
2021-04-13 23:32:23 +08:00
|
|
|
detach_error = llvm::joinErrors(std::move(detach_error), std::move(e));
|
|
|
|
else {
|
2022-07-13 23:33:28 +08:00
|
|
|
if (it->second.process_up.get() == m_current_process)
|
2021-04-13 23:32:23 +08:00
|
|
|
m_current_process = nullptr;
|
2022-07-13 23:33:28 +08:00
|
|
|
if (it->second.process_up.get() == m_continue_process)
|
2021-04-13 23:32:23 +08:00
|
|
|
m_continue_process = nullptr;
|
|
|
|
it = m_debugged_processes.erase(it);
|
|
|
|
detached = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++it;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2021-04-13 23:32:23 +08:00
|
|
|
if (detach_error)
|
|
|
|
return SendErrorResponse(std::move(detach_error));
|
|
|
|
if (!detached)
|
|
|
|
return SendErrorResponse(Status("PID %" PRIu64 " not traced", pid));
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2022-06-07 23:04:01 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
|
|
|
return SendErrorResponse(50);
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
packet.SetFilePos(strlen("qThreadStopInfo"));
|
2021-03-30 19:30:12 +08:00
|
|
|
const lldb::tid_t tid = packet.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID);
|
2015-02-11 18:29:30 +08:00
|
|
|
if (tid == LLDB_INVALID_THREAD_ID) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, could not "
|
|
|
|
"parse thread id from request \"%s\"",
|
2019-08-21 12:55:56 +08:00
|
|
|
__FUNCTION__, packet.GetStringRef().data());
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(0x15);
|
|
|
|
}
|
2022-04-12 22:21:09 +08:00
|
|
|
return SendStopReplyPacketForThread(*m_current_process, tid,
|
|
|
|
/*force_synchronous=*/true);
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2015-07-16 22:14:35 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo(
|
|
|
|
StringExtractorGDBRemote &) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-07-16 22:14:35 +08:00
|
|
|
// Ensure we have a debugged process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
2015-07-16 22:14:35 +08:00
|
|
|
return SendErrorResponse(50);
|
2021-04-11 17:37:36 +08:00
|
|
|
LLDB_LOG(log, "preparing packet for pid {0}", m_current_process->GetID());
|
2015-07-16 22:14:35 +08:00
|
|
|
|
2015-07-23 17:09:29 +08:00
|
|
|
StreamString response;
|
|
|
|
const bool threads_with_valid_stop_info_only = false;
|
2021-04-11 17:37:36 +08:00
|
|
|
llvm::Expected<json::Value> threads_info =
|
|
|
|
GetJSONThreadsInfo(*m_current_process, threads_with_valid_stop_info_only);
|
2019-10-03 02:02:23 +08:00
|
|
|
if (!threads_info) {
|
2019-11-18 18:31:33 +08:00
|
|
|
LLDB_LOG_ERROR(log, threads_info.takeError(),
|
|
|
|
"failed to prepare a packet for pid {1}: {0}",
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetID());
|
2015-07-23 17:09:29 +08:00
|
|
|
return SendErrorResponse(52);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-07-16 22:14:35 +08:00
|
|
|
|
2019-10-03 02:02:23 +08:00
|
|
|
response.AsRawOstream() << *threads_info;
|
2015-07-16 22:14:35 +08:00
|
|
|
StreamGDBRemote escaped_response;
|
|
|
|
escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(escaped_response.GetString());
|
2015-07-16 22:14:35 +08:00
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
|
2015-02-11 18:29:30 +08:00
|
|
|
return SendErrorResponse(68);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
packet.SetFilePos(strlen("qWatchpointSupportInfo"));
|
|
|
|
if (packet.GetBytesLeft() == 0)
|
|
|
|
return SendOKResponse();
|
|
|
|
if (packet.GetChar() != ':')
|
|
|
|
return SendErrorResponse(67);
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
auto hw_debug_cap = m_current_process->GetHardwareDebugSupportInfo();
|
2017-02-24 21:27:31 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamGDBRemote response;
|
2017-02-24 21:27:31 +08:00
|
|
|
if (hw_debug_cap == llvm::None)
|
|
|
|
response.Printf("num:0;");
|
|
|
|
else
|
|
|
|
response.Printf("num:%d;", hw_debug_cap->second);
|
|
|
|
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendPacketNoLock(response.GetString());
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
2015-06-19 04:43:56 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
|
2015-06-19 04:43:56 +08:00
|
|
|
return SendErrorResponse(67);
|
|
|
|
|
|
|
|
packet.SetFilePos(strlen("qFileLoadAddress:"));
|
|
|
|
if (packet.GetBytesLeft() == 0)
|
|
|
|
return SendErrorResponse(68);
|
|
|
|
|
|
|
|
std::string file_name;
|
|
|
|
packet.GetHexByteString(file_name);
|
|
|
|
|
|
|
|
lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS;
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error =
|
2021-04-11 17:37:36 +08:00
|
|
|
m_current_process->GetFileLoadAddress(file_name, file_load_address);
|
2015-06-19 04:43:56 +08:00
|
|
|
if (error.Fail())
|
|
|
|
return SendErrorResponse(69);
|
|
|
|
|
|
|
|
if (file_load_address == LLDB_INVALID_ADDRESS)
|
2016-08-27 23:52:29 +08:00
|
|
|
return SendErrorResponse(1); // File not loaded
|
2015-06-19 04:43:56 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
StreamGDBRemote response;
|
|
|
|
response.PutHex64(file_load_address);
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
2017-02-24 17:29:14 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QPassSignals(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
std::vector<int> signals;
|
|
|
|
packet.SetFilePos(strlen("QPassSignals:"));
|
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Read sequence of hex signal numbers divided by a semicolon and optionally
|
|
|
|
// spaces.
|
2017-02-24 17:29:14 +08:00
|
|
|
while (packet.GetBytesLeft() > 0) {
|
|
|
|
int signal = packet.GetS32(-1, 16);
|
|
|
|
if (signal < 0)
|
|
|
|
return SendIllFormedResponse(packet, "Failed to parse signal number.");
|
|
|
|
signals.push_back(signal);
|
|
|
|
|
|
|
|
packet.SkipSpaces();
|
|
|
|
char separator = packet.GetChar();
|
|
|
|
if (separator == '\0')
|
|
|
|
break; // End of string
|
|
|
|
if (separator != ';')
|
|
|
|
return SendIllFormedResponse(packet, "Invalid separator,"
|
|
|
|
" expected semicolon.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fail if we don't have a current process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process)
|
2017-02-24 17:29:14 +08:00
|
|
|
return SendErrorResponse(68);
|
|
|
|
|
2021-04-11 17:37:36 +08:00
|
|
|
Status error = m_current_process->IgnoreSignals(signals);
|
2017-02-24 17:29:14 +08:00
|
|
|
if (error.Fail())
|
|
|
|
return SendErrorResponse(69);
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2021-02-19 23:57:59 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qMemTags(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-02-19 23:57:59 +08:00
|
|
|
|
|
|
|
// Ensure we have a process.
|
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are expecting
|
|
|
|
// qMemTags:<hex address>,<hex length>:<hex type>
|
|
|
|
|
|
|
|
// Address
|
|
|
|
packet.SetFilePos(strlen("qMemTags:"));
|
|
|
|
const char *current_char = packet.Peek();
|
|
|
|
if (!current_char || *current_char == ',')
|
|
|
|
return SendIllFormedResponse(packet, "Missing address in qMemTags packet");
|
|
|
|
const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0);
|
|
|
|
|
|
|
|
// Length
|
|
|
|
char previous_char = packet.GetChar();
|
|
|
|
current_char = packet.Peek();
|
|
|
|
// If we don't have a separator or the length field is empty
|
|
|
|
if (previous_char != ',' || (current_char && *current_char == ':'))
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"Invalid addr,length pair in qMemTags packet");
|
|
|
|
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Too short qMemtags: packet (looking for length)");
|
|
|
|
const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0);
|
|
|
|
|
|
|
|
// Type
|
|
|
|
const char *invalid_type_err = "Invalid type field in qMemTags: packet";
|
|
|
|
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
|
|
|
|
2021-06-25 21:29:12 +08:00
|
|
|
// Type is a signed integer but packed into the packet as its raw bytes.
|
|
|
|
// However, our GetU64 uses strtoull which allows +/-. We do not want this.
|
|
|
|
const char *first_type_char = packet.Peek();
|
|
|
|
if (first_type_char && (*first_type_char == '+' || *first_type_char == '-'))
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
|
|
|
|
|
|
|
// Extract type as unsigned then cast to signed.
|
|
|
|
// Using a uint64_t here so that we have some value outside of the 32 bit
|
|
|
|
// range to use as the invalid return value.
|
|
|
|
uint64_t raw_type =
|
|
|
|
packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
|
|
|
|
|
|
|
|
if ( // Make sure the cast below would be valid
|
|
|
|
raw_type > std::numeric_limits<uint32_t>::max() ||
|
2021-02-19 23:57:59 +08:00
|
|
|
// To catch inputs like "123aardvark" that will parse but clearly aren't
|
|
|
|
// valid in this case.
|
|
|
|
packet.GetBytesLeft()) {
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
|
|
|
}
|
|
|
|
|
2021-06-25 21:29:12 +08:00
|
|
|
// First narrow to 32 bits otherwise the copy into type would take
|
|
|
|
// the wrong 4 bytes on big endian.
|
|
|
|
uint32_t raw_type_32 = raw_type;
|
|
|
|
int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
|
|
|
|
|
2021-02-19 23:57:59 +08:00
|
|
|
StreamGDBRemote response;
|
|
|
|
std::vector<uint8_t> tags;
|
|
|
|
Status error = m_current_process->ReadMemoryTags(type, addr, length, tags);
|
|
|
|
if (error.Fail())
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
|
|
|
|
// This m is here in case we want to support multi part replies in the future.
|
|
|
|
// In the same manner as qfThreadInfo/qsThreadInfo.
|
|
|
|
response.PutChar('m');
|
|
|
|
response.PutBytesAsRawHex8(tags.data(), tags.size());
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
2021-03-31 21:02:34 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QMemTags(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2021-03-31 21:02:34 +08:00
|
|
|
|
|
|
|
// Ensure we have a process.
|
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
|
|
|
|
LLDB_LOGF(
|
|
|
|
log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
|
|
|
|
__FUNCTION__);
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are expecting
|
|
|
|
// QMemTags:<hex address>,<hex length>:<hex type>:<tags as hex bytes>
|
|
|
|
|
|
|
|
// Address
|
|
|
|
packet.SetFilePos(strlen("QMemTags:"));
|
|
|
|
const char *current_char = packet.Peek();
|
|
|
|
if (!current_char || *current_char == ',')
|
|
|
|
return SendIllFormedResponse(packet, "Missing address in QMemTags packet");
|
|
|
|
const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0);
|
|
|
|
|
|
|
|
// Length
|
|
|
|
char previous_char = packet.GetChar();
|
|
|
|
current_char = packet.Peek();
|
|
|
|
// If we don't have a separator or the length field is empty
|
|
|
|
if (previous_char != ',' || (current_char && *current_char == ':'))
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"Invalid addr,length pair in QMemTags packet");
|
|
|
|
|
|
|
|
if (packet.GetBytesLeft() < 1)
|
|
|
|
return SendIllFormedResponse(
|
|
|
|
packet, "Too short QMemtags: packet (looking for length)");
|
|
|
|
const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0);
|
|
|
|
|
|
|
|
// Type
|
|
|
|
const char *invalid_type_err = "Invalid type field in QMemTags: packet";
|
|
|
|
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
|
|
|
|
|
|
|
// Our GetU64 uses strtoull which allows leading +/-, we don't want that.
|
|
|
|
const char *first_type_char = packet.Peek();
|
|
|
|
if (first_type_char && (*first_type_char == '+' || *first_type_char == '-'))
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
|
|
|
|
|
|
|
// The type is a signed integer but is in the packet as its raw bytes.
|
|
|
|
// So parse first as unsigned then cast to signed later.
|
|
|
|
// We extract to 64 bit, even though we only expect 32, so that we've
|
|
|
|
// got some invalid value we can check for.
|
|
|
|
uint64_t raw_type =
|
|
|
|
packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
|
|
|
|
if (raw_type > std::numeric_limits<uint32_t>::max())
|
|
|
|
return SendIllFormedResponse(packet, invalid_type_err);
|
2021-06-25 21:29:12 +08:00
|
|
|
|
|
|
|
// First narrow to 32 bits. Otherwise the copy below would get the wrong
|
|
|
|
// 4 bytes on big endian.
|
|
|
|
uint32_t raw_type_32 = raw_type;
|
|
|
|
int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
|
2021-03-31 21:02:34 +08:00
|
|
|
|
|
|
|
// Tag data
|
|
|
|
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
|
|
|
|
return SendIllFormedResponse(packet,
|
|
|
|
"Missing tag data in QMemTags: packet");
|
|
|
|
|
|
|
|
// Must be 2 chars per byte
|
|
|
|
const char *invalid_data_err = "Invalid tag data in QMemTags: packet";
|
|
|
|
if (packet.GetBytesLeft() % 2)
|
|
|
|
return SendIllFormedResponse(packet, invalid_data_err);
|
|
|
|
|
|
|
|
// This is bytes here and is unpacked into target specific tags later
|
|
|
|
// We cannot assume that number of bytes == length here because the server
|
|
|
|
// can repeat tags to fill a given range.
|
|
|
|
std::vector<uint8_t> tag_data;
|
|
|
|
// Zero length writes will not have any tag data
|
|
|
|
// (but we pass them on because it will still check that tagging is enabled)
|
|
|
|
if (packet.GetBytesLeft()) {
|
|
|
|
size_t byte_count = packet.GetBytesLeft() / 2;
|
|
|
|
tag_data.resize(byte_count);
|
|
|
|
size_t converted_bytes = packet.GetHexBytes(tag_data, 0);
|
|
|
|
if (converted_bytes != byte_count) {
|
|
|
|
return SendIllFormedResponse(packet, invalid_data_err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Status status =
|
|
|
|
m_current_process->WriteMemoryTags(type, addr, length, tag_data);
|
|
|
|
return status.Success() ? SendOKResponse() : SendErrorResponse(1);
|
|
|
|
}
|
|
|
|
|
2021-04-26 19:47:02 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_qSaveCore(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// Fail if we don't have a current process.
|
|
|
|
if (!m_current_process ||
|
|
|
|
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
|
|
|
|
return SendErrorResponse(Status("Process not running."));
|
|
|
|
|
|
|
|
std::string path_hint;
|
|
|
|
|
|
|
|
StringRef packet_str{packet.GetStringRef()};
|
2021-09-06 19:04:21 +08:00
|
|
|
assert(packet_str.startswith("qSaveCore"));
|
|
|
|
if (packet_str.consume_front("qSaveCore;")) {
|
2021-09-27 18:22:31 +08:00
|
|
|
for (auto x : llvm::split(packet_str, ';')) {
|
2021-04-26 19:47:02 +08:00
|
|
|
if (x.consume_front("path-hint:"))
|
|
|
|
StringExtractor(x).GetHexByteString(path_hint);
|
|
|
|
else
|
|
|
|
return SendErrorResponse(Status("Unsupported qSaveCore option"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Expected<std::string> ret = m_current_process->SaveCore(path_hint);
|
|
|
|
if (!ret)
|
2021-09-06 19:04:21 +08:00
|
|
|
return SendErrorResponse(ret.takeError());
|
2021-04-26 19:47:02 +08:00
|
|
|
|
|
|
|
StreamString response;
|
|
|
|
response.PutCString("core-path:");
|
|
|
|
response.PutStringAsRawHex8(ret.get());
|
|
|
|
return SendPacketNoLock(response.GetString());
|
|
|
|
}
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_QNonStop(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
2022-06-30 16:47:15 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
StringRef packet_str{packet.GetStringRef()};
|
|
|
|
assert(packet_str.startswith("QNonStop:"));
|
|
|
|
packet_str.consume_front("QNonStop:");
|
|
|
|
if (packet_str == "0") {
|
2022-07-01 02:24:04 +08:00
|
|
|
if (m_non_stop)
|
|
|
|
StopSTDIOForwarding();
|
2022-06-30 16:47:15 +08:00
|
|
|
for (auto &process_it : m_debugged_processes) {
|
|
|
|
if (process_it.second.process_up->IsRunning()) {
|
|
|
|
assert(m_non_stop);
|
|
|
|
Status error = process_it.second.process_up->Interrupt();
|
|
|
|
if (error.Fail()) {
|
|
|
|
LLDB_LOG(log,
|
|
|
|
"while disabling nonstop, failed to halt process {0}: {1}",
|
|
|
|
process_it.first, error);
|
|
|
|
return SendErrorResponse(0x41);
|
|
|
|
}
|
|
|
|
// we must not send stop reasons after QNonStop
|
|
|
|
m_disabling_non_stop = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_stdio_notification_queue.clear();
|
|
|
|
m_stop_notification_queue.clear();
|
2022-04-12 22:21:09 +08:00
|
|
|
m_non_stop = false;
|
2022-06-30 16:47:15 +08:00
|
|
|
// If we are stopping anything, defer sending the OK response until we're
|
|
|
|
// done.
|
|
|
|
if (m_disabling_non_stop)
|
|
|
|
return PacketResult::Success;
|
2022-04-12 22:21:09 +08:00
|
|
|
} else if (packet_str == "1") {
|
2022-07-01 02:24:04 +08:00
|
|
|
if (!m_non_stop)
|
|
|
|
StartSTDIOForwarding();
|
2022-04-12 22:21:09 +08:00
|
|
|
m_non_stop = true;
|
|
|
|
} else
|
|
|
|
return SendErrorResponse(Status("Invalid QNonStop packet"));
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
2022-06-30 03:48:10 +08:00
|
|
|
GDBRemoteCommunicationServerLLGS::HandleNotificationAck(
|
|
|
|
std::deque<std::string> &queue) {
|
2022-04-12 22:21:09 +08:00
|
|
|
// Per the protocol, the first message put into the queue is sent
|
2022-06-30 03:48:10 +08:00
|
|
|
// immediately. However, it remains the queue until the client ACKs it --
|
|
|
|
// then we pop it and send the next message. The process repeats until
|
|
|
|
// the last message in the queue is ACK-ed, in which case the packet sends
|
|
|
|
// an OK response.
|
|
|
|
if (queue.empty())
|
2022-04-12 22:21:09 +08:00
|
|
|
return SendErrorResponse(Status("No pending notification to ack"));
|
2022-06-30 03:48:10 +08:00
|
|
|
queue.pop_front();
|
|
|
|
if (!queue.empty())
|
|
|
|
return SendPacketNoLock(queue.front());
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vStdio(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
return HandleNotificationAck(m_stdio_notification_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vStopped(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
PacketResult ret = HandleNotificationAck(m_stop_notification_queue);
|
2022-06-27 20:22:38 +08:00
|
|
|
// If this was the last notification and all the processes exited,
|
|
|
|
// terminate the server.
|
2022-06-30 03:48:10 +08:00
|
|
|
if (m_stop_notification_queue.empty() && m_debugged_processes.empty()) {
|
2022-04-12 22:21:09 +08:00
|
|
|
m_exit_now = true;
|
|
|
|
m_mainloop.RequestTermination();
|
|
|
|
}
|
2022-06-30 03:48:10 +08:00
|
|
|
return ret;
|
2022-04-12 22:21:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_vCtrlC(
|
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
if (!m_non_stop)
|
|
|
|
return SendErrorResponse(Status("vCtrl is only valid in non-stop mode"));
|
|
|
|
|
|
|
|
PacketResult interrupt_res = Handle_interrupt(packet);
|
|
|
|
// If interrupting the process failed, pass the result through.
|
|
|
|
if (interrupt_res != PacketResult::Success)
|
|
|
|
return interrupt_res;
|
|
|
|
// Otherwise, vCtrlC should issue an OK response (normal interrupts do not).
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2022-06-20 17:34:23 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::Handle_T(StringExtractorGDBRemote &packet) {
|
|
|
|
packet.SetFilePos(strlen("T"));
|
|
|
|
auto pid_tid = packet.GetPidTid(m_current_process ? m_current_process->GetID()
|
|
|
|
: LLDB_INVALID_PROCESS_ID);
|
|
|
|
if (!pid_tid)
|
|
|
|
return SendErrorResponse(llvm::make_error<StringError>(
|
|
|
|
inconvertibleErrorCode(), "Malformed thread-id"));
|
|
|
|
|
|
|
|
lldb::pid_t pid = pid_tid->first;
|
|
|
|
lldb::tid_t tid = pid_tid->second;
|
|
|
|
|
|
|
|
// Technically, this would also be caught by the PID check but let's be more
|
|
|
|
// explicit about the error.
|
|
|
|
if (pid == LLDB_INVALID_PROCESS_ID)
|
|
|
|
return SendErrorResponse(llvm::make_error<StringError>(
|
|
|
|
inconvertibleErrorCode(), "No current process and no PID provided"));
|
|
|
|
|
|
|
|
// Check the process ID and find respective process instance.
|
|
|
|
auto new_process_it = m_debugged_processes.find(pid);
|
|
|
|
if (new_process_it == m_debugged_processes.end())
|
|
|
|
return SendErrorResponse(1);
|
|
|
|
|
|
|
|
// Check the thread ID
|
2022-07-13 23:33:28 +08:00
|
|
|
if (!new_process_it->second.process_up->GetThreadByID(tid))
|
2022-06-20 17:34:23 +08:00
|
|
|
return SendErrorResponse(2);
|
|
|
|
|
|
|
|
return SendOKResponse();
|
|
|
|
}
|
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2015-03-31 17:52:22 +08:00
|
|
|
// Tell the stdio connection to shut down.
|
2015-02-11 18:29:30 +08:00
|
|
|
if (m_stdio_communication.IsConnected()) {
|
|
|
|
auto connection = m_stdio_communication.GetConnection();
|
|
|
|
if (connection) {
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error;
|
2015-02-11 18:29:30 +08:00
|
|
|
connection->Disconnect(&error);
|
|
|
|
|
|
|
|
if (error.Success()) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s disconnect process "
|
|
|
|
"terminal stdio - SUCCESS",
|
|
|
|
__FUNCTION__);
|
2015-02-11 18:29:30 +08:00
|
|
|
} else {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s disconnect process "
|
|
|
|
"terminal stdio - FAIL: %s",
|
|
|
|
__FUNCTION__, error.AsCString());
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
2017-10-17 23:52:16 +08:00
|
|
|
NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix(
|
2015-02-11 18:29:30 +08:00
|
|
|
StringExtractorGDBRemote &packet) {
|
|
|
|
// We have no thread if we don't have a process.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process ||
|
|
|
|
m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// If the client hasn't asked for thread suffix support, there will not be a
|
2018-05-01 00:49:04 +08:00
|
|
|
// thread suffix. Use the current thread in that case.
|
2015-02-11 18:29:30 +08:00
|
|
|
if (!m_thread_suffix_supported) {
|
|
|
|
const lldb::tid_t current_tid = GetCurrentThreadID();
|
|
|
|
if (current_tid == LLDB_INVALID_THREAD_ID)
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2015-02-11 18:29:30 +08:00
|
|
|
else if (current_tid == 0) {
|
|
|
|
// Pick a thread.
|
2021-04-11 17:37:36 +08:00
|
|
|
return m_current_process->GetThreadAtIndex(0);
|
2016-09-07 04:57:50 +08:00
|
|
|
} else
|
2021-04-11 17:37:36 +08:00
|
|
|
return m_current_process->GetThreadByID(current_tid);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Thread);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-02-11 18:29:30 +08:00
|
|
|
// Parse out the ';'.
|
|
|
|
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ';') {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s gdb-remote parse "
|
|
|
|
"error: expected ';' prior to start of thread suffix: packet "
|
|
|
|
"contents = '%s'",
|
2019-08-21 12:55:56 +08:00
|
|
|
__FUNCTION__, packet.GetStringRef().data());
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
if (!packet.GetBytesLeft())
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2015-02-11 18:29:30 +08:00
|
|
|
|
|
|
|
// Parse out thread: portion.
|
2016-08-31 16:43:37 +08:00
|
|
|
if (strncmp(packet.Peek(), "thread:", strlen("thread:")) != 0) {
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"GDBRemoteCommunicationServerLLGS::%s gdb-remote parse "
|
|
|
|
"error: expected 'thread:' but not found, packet contents = "
|
|
|
|
"'%s'",
|
2019-08-21 12:55:56 +08:00
|
|
|
__FUNCTION__, packet.GetStringRef().data());
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-02-11 18:29:30 +08:00
|
|
|
packet.SetFilePos(packet.GetFilePos() + strlen("thread:"));
|
|
|
|
const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
|
|
|
|
if (tid != 0)
|
2021-04-11 17:37:36 +08:00
|
|
|
return m_current_process->GetThreadByID(tid);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2017-10-17 23:52:16 +08:00
|
|
|
return nullptr;
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const {
|
|
|
|
if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) {
|
2018-05-01 00:49:04 +08:00
|
|
|
// Use whatever the debug process says is the current thread id since the
|
|
|
|
// protocol either didn't specify or specified we want any/all threads
|
|
|
|
// marked as the current thread.
|
2021-04-11 17:37:36 +08:00
|
|
|
if (!m_current_process)
|
2015-02-11 18:29:30 +08:00
|
|
|
return LLDB_INVALID_THREAD_ID;
|
2021-04-11 17:37:36 +08:00
|
|
|
return m_current_process->GetCurrentThreadID();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
|
|
|
// Use the specific current thread id set by the gdb remote protocol.
|
|
|
|
return m_current_tid;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
|
2015-02-11 18:29:30 +08:00
|
|
|
return m_next_saved_registers_id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() {
|
2022-01-31 22:57:48 +08:00
|
|
|
Log *log = GetLog(LLDBLog::Process);
|
2015-02-11 18:29:30 +08:00
|
|
|
|
Create a generic handler for Xfer packets
Summary:
This is the first of a few patches I have to improve the performance of dynamic module loading on Android.
In this first diff I'll describe the context of my main motivation and will then link to it in the other diffs to avoid repeating myself.
## Motivation
I have a few scenarios where opening a specific feature on an Android app takes around 40s when lldb is attached to it. The reason for that is because 40 modules are dynamicly loaded at that point in time and each one of them is taking ~1s.
## The problem
To learn about new modules we have a breakpoint on a linker function that is called twice whenever a module is loaded. One time just before it's loaded (so lldb can check which modules are loaded) and another right after it's loaded (so lldb can check again which ones are loaded and calculate the diference).
It's figuring out which modules are loaded that is taking quite some time. This is currently done by traversing the linked list of loaded shared libraries that the linker maintains in memory. Each item in the linked list requires its own `x` packet sent to the gdb server (this is android so the network also plays a part). In my scenario there are 400+ loaded libraries and even though we read 0x800 worth of bytes at a time we still make ~180 requests that end up taking 150-200ms.
We also do this twice, once before the module is loaded (state = eAdd) and another right after (state = eConsistent) which easly adds up to ~400ms per module.
## A solution
**Implement `xfer:libraries-svr4` in lldb-server:**
I noticed in the code that loads the new modules that it had support for the `xfer:libraries-svr4` packet (added ~4 years ago to support the ds2 debug server) but we didn't support it in lldb-server. This single packet returns an xml list of all the loaded modules by the process. The advantage is that there's no more need to make 180 requests to read the linked list. Additionally this new requests takes around 10ms.
**More efficient usage of the `xfer:libraries-svr4` packet in lldb:**
When `xfer:libraries-svr4` is available the Process class has a `LoadModules` function that requests this packet and then loads or unloads modules based on the current list of loaded modules by the process.
This is the function that is used by the DYLDRendezvous class to get the list of loaded modules before and after the module is loaded. However, this is really not needed since the LoadModules function already loaded or unloaded the modules accordingly. I changed this strategy to call LoadModules only once (after the process has loaded the module).
**Bugs**
I found a few issues in lldb while implementing this and have submitted independent patches for them.
I tried to devide this into multiple logical patches to make it easier to review and discuss.
## Tests
I wanted to put these set of diffs up before having all the tests up and running to start having them reviewed from a techical point of view. I'm also having some trouble making the tests running on linux so I need more time to make that happen.
# This diff
The `xfer` packages follow the same protocol, they are requested with `xfer:<object>:<read|write>:<annex>:<offset,length>` and a return that starts with `l` or `m` depending if the offset and length covers the entire data or not. Before implementing the `xfer:libraries-svr4` I refactored the `xfer:auxv` to generically handle xfer packets so we can easly add new ones.
The overall structure of the function ends up being:
* Parse the packet into its components: object, offset etc.
* Depending on the object do its own logic to generate the data.
* Return the data based on its size, the requested offset and length.
Reviewers: clayborg, xiaobai, labath
Reviewed By: labath
Subscribers: mgorny, krytarowski, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62499
llvm-svn: 362982
2019-06-11 04:59:58 +08:00
|
|
|
LLDB_LOG(log, "clearing {0} xfer buffers", m_xfer_buffer_map.size());
|
|
|
|
m_xfer_buffer_map.clear();
|
2015-02-11 18:29:30 +08:00
|
|
|
}
|
2015-03-24 19:15:23 +08:00
|
|
|
|
|
|
|
FileSpec
|
|
|
|
GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path,
|
|
|
|
const ArchSpec &arch) {
|
2021-04-11 17:37:36 +08:00
|
|
|
if (m_current_process) {
|
2015-03-24 19:15:23 +08:00
|
|
|
FileSpec file_spec;
|
2021-04-11 17:37:36 +08:00
|
|
|
if (m_current_process
|
2015-03-24 19:15:23 +08:00
|
|
|
->GetLoadedModuleFileSpec(module_path.c_str(), file_spec)
|
|
|
|
.Success()) {
|
2018-11-02 01:09:25 +08:00
|
|
|
if (FileSystem::Instance().Exists(file_spec))
|
2015-03-24 19:15:23 +08:00
|
|
|
return file_spec;
|
|
|
|
}
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2015-03-24 19:15:23 +08:00
|
|
|
return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
|
|
|
|
}
|
2019-07-24 04:40:30 +08:00
|
|
|
|
|
|
|
std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue(
|
|
|
|
llvm::StringRef value) {
|
|
|
|
std::string result;
|
|
|
|
for (const char &c : value) {
|
|
|
|
switch (c) {
|
|
|
|
case '\'':
|
|
|
|
result += "'";
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
result += """;
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
result += "<";
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
result += ">";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result += c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2019-09-17 17:31:00 +08:00
|
|
|
}
|
2021-03-30 19:25:06 +08:00
|
|
|
|
2021-04-09 05:15:38 +08:00
|
|
|
std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
|
|
|
|
const llvm::ArrayRef<llvm::StringRef> client_features) {
|
2021-04-09 06:59:22 +08:00
|
|
|
std::vector<std::string> ret =
|
2021-04-09 05:15:38 +08:00
|
|
|
GDBRemoteCommunicationServerCommon::HandleFeatures(client_features);
|
|
|
|
ret.insert(ret.end(), {
|
2021-04-25 04:36:20 +08:00
|
|
|
"QThreadSuffixSupported+",
|
|
|
|
"QListThreadsInStopReply+",
|
|
|
|
"qXfer:features:read+",
|
2022-04-12 22:21:09 +08:00
|
|
|
"QNonStop+",
|
2021-04-25 04:36:20 +08:00
|
|
|
});
|
2021-04-09 06:59:22 +08:00
|
|
|
|
2021-04-25 04:36:20 +08:00
|
|
|
// report server-only features
|
2021-04-09 06:59:22 +08:00
|
|
|
using Extension = NativeProcessProtocol::Extension;
|
2021-04-25 04:36:20 +08:00
|
|
|
Extension plugin_features = m_process_factory.GetSupportedExtensions();
|
|
|
|
if (bool(plugin_features & Extension::pass_signals))
|
|
|
|
ret.push_back("QPassSignals+");
|
|
|
|
if (bool(plugin_features & Extension::auxv))
|
|
|
|
ret.push_back("qXfer:auxv:read+");
|
|
|
|
if (bool(plugin_features & Extension::libraries_svr4))
|
|
|
|
ret.push_back("qXfer:libraries-svr4:read+");
|
2022-01-12 03:28:37 +08:00
|
|
|
if (bool(plugin_features & Extension::siginfo_read))
|
|
|
|
ret.push_back("qXfer:siginfo:read+");
|
2021-02-19 23:32:09 +08:00
|
|
|
if (bool(plugin_features & Extension::memory_tagging))
|
|
|
|
ret.push_back("memory-tagging+");
|
2021-04-26 19:47:02 +08:00
|
|
|
if (bool(plugin_features & Extension::savecore))
|
|
|
|
ret.push_back("qSaveCore+");
|
2021-04-25 04:36:20 +08:00
|
|
|
|
|
|
|
// check for client features
|
2021-04-09 06:59:22 +08:00
|
|
|
m_extensions_supported = {};
|
|
|
|
for (llvm::StringRef x : client_features)
|
|
|
|
m_extensions_supported |=
|
|
|
|
llvm::StringSwitch<Extension>(x)
|
|
|
|
.Case("multiprocess+", Extension::multiprocess)
|
|
|
|
.Case("fork-events+", Extension::fork)
|
|
|
|
.Case("vfork-events+", Extension::vfork)
|
|
|
|
.Default({});
|
2021-04-25 04:36:20 +08:00
|
|
|
|
|
|
|
m_extensions_supported &= plugin_features;
|
2021-04-09 06:59:22 +08:00
|
|
|
|
|
|
|
// fork & vfork require multiprocess
|
|
|
|
if (!bool(m_extensions_supported & Extension::multiprocess))
|
|
|
|
m_extensions_supported &= ~(Extension::fork | Extension::vfork);
|
|
|
|
|
|
|
|
// report only if actually supported
|
|
|
|
if (bool(m_extensions_supported & Extension::multiprocess))
|
|
|
|
ret.push_back("multiprocess+");
|
|
|
|
if (bool(m_extensions_supported & Extension::fork))
|
|
|
|
ret.push_back("fork-events+");
|
|
|
|
if (bool(m_extensions_supported & Extension::vfork))
|
|
|
|
ret.push_back("vfork-events+");
|
|
|
|
|
2021-04-13 23:32:23 +08:00
|
|
|
for (auto &x : m_debugged_processes)
|
2022-07-13 23:33:28 +08:00
|
|
|
SetEnabledExtensions(*x.second.process_up);
|
2021-04-09 05:15:38 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2021-04-09 06:59:22 +08:00
|
|
|
|
|
|
|
void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions(
|
|
|
|
NativeProcessProtocol &process) {
|
|
|
|
NativeProcessProtocol::Extension flags = m_extensions_supported;
|
|
|
|
assert(!bool(flags & ~m_process_factory.GetSupportedExtensions()));
|
|
|
|
process.SetEnabledExtensions(flags);
|
|
|
|
}
|
2021-10-22 23:42:23 +08:00
|
|
|
|
2022-04-12 22:21:09 +08:00
|
|
|
GDBRemoteCommunication::PacketResult
|
|
|
|
GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() {
|
2022-07-01 02:24:04 +08:00
|
|
|
if (m_non_stop)
|
|
|
|
return SendOKResponse();
|
2022-06-10 21:53:11 +08:00
|
|
|
StartSTDIOForwarding();
|
2022-07-01 02:24:04 +08:00
|
|
|
return PacketResult::Success;
|
2022-04-12 22:21:09 +08:00
|
|
|
}
|
|
|
|
|
2022-06-22 14:32:05 +08:00
|
|
|
void GDBRemoteCommunicationServerLLGS::AppendThreadIDToResponse(
|
|
|
|
Stream &response, lldb::pid_t pid, lldb::tid_t tid) {
|
|
|
|
if (bool(m_extensions_supported &
|
|
|
|
NativeProcessProtocol::Extension::multiprocess))
|
|
|
|
response.Format("p{0:x-}.", pid);
|
|
|
|
response.Format("{0:x-}", tid);
|
|
|
|
}
|
|
|
|
|
2021-10-22 23:42:23 +08:00
|
|
|
std::string
|
|
|
|
lldb_private::process_gdb_remote::LLGSArgToURL(llvm::StringRef url_arg,
|
|
|
|
bool reverse_connect) {
|
|
|
|
// Try parsing the argument as URL.
|
|
|
|
if (llvm::Optional<URI> url = URI::Parse(url_arg)) {
|
|
|
|
if (reverse_connect)
|
|
|
|
return url_arg.str();
|
|
|
|
|
|
|
|
// Translate the scheme from LLGS notation to ConnectionFileDescriptor.
|
|
|
|
// If the scheme doesn't match any, pass it through to support using CFD
|
|
|
|
// schemes directly.
|
|
|
|
std::string new_url = llvm::StringSwitch<std::string>(url->scheme)
|
|
|
|
.Case("tcp", "listen")
|
|
|
|
.Case("unix", "unix-accept")
|
|
|
|
.Case("unix-abstract", "unix-abstract-accept")
|
|
|
|
.Default(url->scheme.str());
|
|
|
|
llvm::append_range(new_url, url_arg.substr(url->scheme.size()));
|
|
|
|
return new_url;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string host_port = url_arg.str();
|
|
|
|
// If host_and_port starts with ':', default the host to be "localhost" and
|
|
|
|
// expect the remainder to be the port.
|
|
|
|
if (url_arg.startswith(":"))
|
|
|
|
host_port.insert(0, "localhost");
|
|
|
|
|
|
|
|
// Try parsing the (preprocessed) argument as host:port pair.
|
2021-10-27 23:52:45 +08:00
|
|
|
if (!llvm::errorToBool(Socket::DecodeHostAndPort(host_port).takeError()))
|
2021-10-22 23:42:23 +08:00
|
|
|
return (reverse_connect ? "connect://" : "listen://") + host_port;
|
|
|
|
|
|
|
|
// If none of the above applied, interpret the argument as UNIX socket path.
|
|
|
|
return (reverse_connect ? "unix-connect://" : "unix-accept://") +
|
|
|
|
url_arg.str();
|
|
|
|
}
|