Skip to content

Commit d8e2e7d

Browse files
committed
[lldb/Reproducers] Support multiple GDB remotes
When running the test suite with always capture on, a handful of tests are failing because they have multiple targets and therefore multiple GDB remote connections. The current reproducer infrastructure is capable of dealing with that. This patch reworks the GDB remote provider to support multiple GDB remote connections, similar to how the reproducers support shadowing multiple command interpreter inputs. The provider now keeps a list of packet recorders which deal with a single GDB remote connection. During replay we rely on the order of creation to match the number of packets to the GDB remote connection. Differential revision: https://reviews.llvm.org/D71105 (cherry picked from commit e81268d)
1 parent 5f1caca commit d8e2e7d

File tree

13 files changed

+265
-147
lines changed

13 files changed

+265
-147
lines changed

lldb/include/lldb/Utility/GDBRemote.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef liblldb_GDBRemote_h_
1010
#define liblldb_GDBRemote_h_
1111

12+
#include "lldb/Utility/FileSpec.h"
13+
#include "lldb/Utility/Reproducer.h"
1214
#include "lldb/Utility/StreamString.h"
1315
#include "lldb/lldb-enumerations.h"
1416
#include "lldb/lldb-public.h"
@@ -69,7 +71,6 @@ struct GDBRemotePacket {
6971
std::string data;
7072
};
7173

72-
void Serialize(llvm::raw_ostream &strm) const;
7374
void Dump(Stream &strm) const;
7475

7576
BinaryData packet;
@@ -82,6 +83,46 @@ struct GDBRemotePacket {
8283
llvm::StringRef GetTypeStr() const;
8384
};
8485

86+
namespace repro {
87+
class PacketRecorder : public AbstractRecorder {
88+
public:
89+
PacketRecorder(const FileSpec &filename, std::error_code &ec)
90+
: AbstractRecorder(filename, ec) {}
91+
92+
static llvm::Expected<std::unique_ptr<PacketRecorder>>
93+
Create(const FileSpec &filename);
94+
95+
void Record(const GDBRemotePacket &packet);
96+
};
97+
98+
class GDBRemoteProvider : public repro::Provider<GDBRemoteProvider> {
99+
public:
100+
struct Info {
101+
static const char *name;
102+
static const char *file;
103+
};
104+
105+
GDBRemoteProvider(const FileSpec &directory) : Provider(directory) {}
106+
107+
llvm::raw_ostream *GetHistoryStream();
108+
PacketRecorder *GetNewPacketRecorder();
109+
110+
void SetCallback(std::function<void()> callback) {
111+
m_callback = std::move(callback);
112+
}
113+
114+
void Keep() override;
115+
void Discard() override;
116+
117+
static char ID;
118+
119+
private:
120+
std::function<void()> m_callback;
121+
std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
122+
std::vector<std::unique_ptr<PacketRecorder>> m_packet_recorders;
123+
};
124+
125+
} // namespace repro
85126
} // namespace lldb_private
86127

87128
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(lldb_private::GDBRemotePacket)

lldb/include/lldb/Utility/Reproducer.h

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -150,24 +150,13 @@ class WorkingDirectoryProvider : public Provider<WorkingDirectoryProvider> {
150150
static char ID;
151151
};
152152

153-
class DataRecorder {
154-
public:
155-
DataRecorder(const FileSpec &filename, std::error_code &ec)
153+
class AbstractRecorder {
154+
protected:
155+
AbstractRecorder(const FileSpec &filename, std::error_code &ec)
156156
: m_filename(filename.GetFilename().GetStringRef()),
157157
m_os(filename.GetPath(), ec, llvm::sys::fs::F_Text), m_record(true) {}
158158

159-
static llvm::Expected<std::unique_ptr<DataRecorder>>
160-
Create(const FileSpec &filename);
161-
162-
template <typename T> void Record(const T &t, bool newline = false) {
163-
if (!m_record)
164-
return;
165-
m_os << t;
166-
if (newline)
167-
m_os << '\n';
168-
m_os.flush();
169-
}
170-
159+
public:
171160
const FileSpec &GetFilename() { return m_filename; }
172161

173162
void Stop() {
@@ -177,10 +166,30 @@ class DataRecorder {
177166

178167
private:
179168
FileSpec m_filename;
169+
170+
protected:
180171
llvm::raw_fd_ostream m_os;
181172
bool m_record;
182173
};
183174

175+
class DataRecorder : public AbstractRecorder {
176+
public:
177+
DataRecorder(const FileSpec &filename, std::error_code &ec)
178+
: AbstractRecorder(filename, ec) {}
179+
180+
static llvm::Expected<std::unique_ptr<DataRecorder>>
181+
Create(const FileSpec &filename);
182+
183+
template <typename T> void Record(const T &t, bool newline = false) {
184+
if (!m_record)
185+
return;
186+
m_os << t;
187+
if (newline)
188+
m_os << '\n';
189+
m_os.flush();
190+
}
191+
};
192+
184193
class CommandProvider : public Provider<CommandProvider> {
185194
public:
186195
struct Info {
@@ -201,32 +210,6 @@ class CommandProvider : public Provider<CommandProvider> {
201210
std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
202211
};
203212

204-
class ProcessGDBRemoteProvider
205-
: public repro::Provider<ProcessGDBRemoteProvider> {
206-
public:
207-
struct Info {
208-
static const char *name;
209-
static const char *file;
210-
};
211-
212-
ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) {}
213-
214-
llvm::raw_ostream *GetHistoryStream();
215-
216-
void SetCallback(std::function<void()> callback) {
217-
m_callback = std::move(callback);
218-
}
219-
220-
void Keep() override { m_callback(); }
221-
void Discard() override { m_callback(); }
222-
223-
static char ID;
224-
225-
private:
226-
std::function<void()> m_callback;
227-
std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
228-
};
229-
230213
/// The generator is responsible for the logic needed to generate a
231214
/// reproducer. For doing so it relies on providers, who serialize data that
232215
/// is necessary for reproducing a failure.
@@ -356,13 +339,43 @@ class Reproducer {
356339
mutable std::mutex m_mutex;
357340
};
358341

359-
/// Helper class for replaying commands through the reproducer.
360-
class CommandLoader {
342+
template <typename T> class MultiLoader {
361343
public:
362-
CommandLoader(std::vector<std::string> files) : m_files(files) {}
344+
MultiLoader(std::vector<std::string> files) : m_files(files) {}
345+
346+
static std::unique_ptr<MultiLoader> Create(Loader *loader) {
347+
if (!loader)
348+
return {};
349+
350+
FileSpec file = loader->GetFile<typename T::Info>();
351+
if (!file)
352+
return {};
353+
354+
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
355+
if (auto err = error_or_file.getError())
356+
return {};
363357

364-
static std::unique_ptr<CommandLoader> Create(Loader *loader);
365-
llvm::Optional<std::string> GetNextFile();
358+
std::vector<std::string> files;
359+
llvm::yaml::Input yin((*error_or_file)->getBuffer());
360+
yin >> files;
361+
362+
if (auto err = yin.error())
363+
return {};
364+
365+
for (auto &file : files) {
366+
FileSpec absolute_path =
367+
loader->GetRoot().CopyByAppendingPathComponent(file);
368+
file = absolute_path.GetPath();
369+
}
370+
371+
return std::make_unique<MultiLoader<T>>(std::move(files));
372+
}
373+
374+
llvm::Optional<std::string> GetNextFile() {
375+
if (m_index >= m_files.size())
376+
return {};
377+
return m_files[m_index++];
378+
}
366379

367380
private:
368381
std::vector<std::string> m_files;

lldb/source/API/SBDebugger.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,9 @@ void SBDebugger::SetInputFileHandle(FILE *fh, bool transfer_ownership) {
304304
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator())
305305
recorder = g->GetOrCreate<repro::CommandProvider>().GetNewDataRecorder();
306306

307-
static std::unique_ptr<repro::CommandLoader> loader =
308-
repro::CommandLoader::Create(repro::Reproducer::Instance().GetLoader());
307+
static std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> loader =
308+
repro::MultiLoader<repro::CommandProvider>::Create(
309+
repro::Reproducer::Instance().GetLoader());
309310
if (loader) {
310311
llvm::Optional<std::string> file = loader->GetNextFile();
311312
fh = file ? FileSystem::Instance().Fopen(file->c_str(), "r") : nullptr;

lldb/source/Commands/CommandObjectReproducer.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -407,20 +407,18 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
407407
return true;
408408
}
409409
case eReproducerProviderCommands: {
410-
// Create a new command loader.
411-
std::unique_ptr<repro::CommandLoader> command_loader =
412-
repro::CommandLoader::Create(loader);
413-
if (!command_loader) {
410+
std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
411+
repro::MultiLoader<repro::CommandProvider>::Create(loader);
412+
if (!multi_loader) {
414413
SetError(result,
415414
make_error<StringError>(llvm::inconvertibleErrorCode(),
416415
"Unable to create command loader."));
417416
return false;
418417
}
419418

420419
// Iterate over the command files and dump them.
421-
while (true) {
422-
llvm::Optional<std::string> command_file =
423-
command_loader->GetNextFile();
420+
llvm::Optional<std::string> command_file;
421+
while ((command_file = multi_loader->GetNextFile())) {
424422
if (!command_file)
425423
break;
426424

@@ -436,24 +434,29 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
436434
return true;
437435
}
438436
case eReproducerProviderGDB: {
439-
FileSpec gdb_file = loader->GetFile<ProcessGDBRemoteProvider::Info>();
440-
auto error_or_file = MemoryBuffer::getFile(gdb_file.GetPath());
441-
if (auto err = error_or_file.getError()) {
442-
SetError(result, errorCodeToError(err));
443-
return false;
444-
}
437+
std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
438+
multi_loader =
439+
repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
440+
llvm::Optional<std::string> gdb_file;
441+
while ((gdb_file = multi_loader->GetNextFile())) {
442+
auto error_or_file = MemoryBuffer::getFile(*gdb_file);
443+
if (auto err = error_or_file.getError()) {
444+
SetError(result, errorCodeToError(err));
445+
return false;
446+
}
445447

446-
std::vector<GDBRemotePacket> packets;
447-
yaml::Input yin((*error_or_file)->getBuffer());
448-
yin >> packets;
448+
std::vector<GDBRemotePacket> packets;
449+
yaml::Input yin((*error_or_file)->getBuffer());
450+
yin >> packets;
449451

450-
if (auto err = yin.error()) {
451-
SetError(result, errorCodeToError(err));
452-
return false;
453-
}
452+
if (auto err = yin.error()) {
453+
SetError(result, errorCodeToError(err));
454+
return false;
455+
}
454456

455-
for (GDBRemotePacket &packet : packets) {
456-
packet.Dump(result.GetOutputStream());
457+
for (GDBRemotePacket &packet : packets) {
458+
packet.Dump(result.GetOutputStream());
459+
}
457460
}
458461

459462
result.SetStatus(eReturnStatusSuccessFinishResult);

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "lldb/Utility/FileSpec.h"
3232
#include "lldb/Utility/Log.h"
3333
#include "lldb/Utility/RegularExpression.h"
34+
#include "lldb/Utility/Reproducer.h"
3435
#include "lldb/Utility/StreamString.h"
3536
#include "llvm/ADT/SmallString.h"
3637
#include "llvm/Support/ScopedPrinter.h"
@@ -1242,8 +1243,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
12421243

12431244
void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
12441245

1245-
void GDBRemoteCommunication::SetHistoryStream(llvm::raw_ostream *strm) {
1246-
m_history.SetStream(strm);
1246+
void GDBRemoteCommunication::SetPacketRecorder(
1247+
repro::PacketRecorder *recorder) {
1248+
m_history.SetRecorder(recorder);
12471249
}
12481250

12491251
llvm::Error

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include "lldb/lldb-public.h"
2828

2929
namespace lldb_private {
30+
namespace repro {
31+
class PacketRecorder;
32+
}
3033
namespace process_gdb_remote {
3134

3235
enum GDBStoppointType {
@@ -133,7 +136,8 @@ class GDBRemoteCommunication : public Communication {
133136
// fork/exec to avoid having to connect/accept
134137

135138
void DumpHistory(Stream &strm);
136-
void SetHistoryStream(llvm::raw_ostream *strm);
139+
140+
void SetPacketRecorder(repro::PacketRecorder *recorder);
137141

138142
static llvm::Error ConnectLocally(GDBRemoteCommunication &client,
139143
GDBRemoteCommunication &server);

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ void GDBRemoteCommunicationHistory::AddPacket(char packet_char,
4040
m_packets[idx].bytes_transmitted = bytes_transmitted;
4141
m_packets[idx].packet_idx = m_total_packet_count;
4242
m_packets[idx].tid = llvm::get_threadid();
43-
if (m_stream)
44-
m_packets[idx].Serialize(*m_stream);
43+
if (m_recorder)
44+
m_recorder->Record(m_packets[idx]);
4545
}
4646

4747
void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
@@ -58,8 +58,8 @@ void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
5858
m_packets[idx].bytes_transmitted = bytes_transmitted;
5959
m_packets[idx].packet_idx = m_total_packet_count;
6060
m_packets[idx].tid = llvm::get_threadid();
61-
if (m_stream)
62-
m_packets[idx].Serialize(*m_stream);
61+
if (m_recorder)
62+
m_recorder->Record(m_packets[idx]);
6363
}
6464

6565
void GDBRemoteCommunicationHistory::Dump(Stream &strm) const {

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
#include <vector>
1414

1515
#include "lldb/Utility/GDBRemote.h"
16+
#include "lldb/Utility/Reproducer.h"
1617
#include "lldb/lldb-public.h"
1718
#include "llvm/Support/YAMLTraits.h"
1819
#include "llvm/Support/raw_ostream.h"
1920

2021
namespace lldb_private {
22+
namespace repro {
23+
class PacketRecorder;
24+
}
2125
namespace process_gdb_remote {
2226

2327
/// The history keeps a circular buffer of GDB remote packets. The history is
@@ -41,7 +45,7 @@ class GDBRemoteCommunicationHistory {
4145
void Dump(Log *log) const;
4246
bool DidDumpToLog() const { return m_dumped_to_log; }
4347

44-
void SetStream(llvm::raw_ostream *strm) { m_stream = strm; }
48+
void SetRecorder(repro::PacketRecorder *recorder) { m_recorder = recorder; }
4549

4650
private:
4751
uint32_t GetFirstSavedPacketIndex() const {
@@ -73,7 +77,7 @@ class GDBRemoteCommunicationHistory {
7377
uint32_t m_curr_idx;
7478
uint32_t m_total_packet_count;
7579
mutable bool m_dumped_to_log;
76-
llvm::raw_ostream *m_stream = nullptr;
80+
repro::PacketRecorder *m_recorder = nullptr;
7781
};
7882

7983
} // namespace process_gdb_remote

0 commit comments

Comments
 (0)