Skip to content

Commit b5ec0cd

Browse files
authored
Merge pull request #635 from JDevlieghere/🍒/e81268d03e73aef4f9c7bd8ece8ad02f5b017dcf
[lldb/Reproducers] Support multiple GDB remotes
2 parents 1bea469 + d8e2e7d commit b5ec0cd

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.
@@ -365,13 +348,43 @@ class Reproducer {
365348
mutable std::mutex m_mutex;
366349
};
367350

368-
/// Helper class for replaying commands through the reproducer.
369-
class CommandLoader {
351+
template <typename T> class MultiLoader {
370352
public:
371-
CommandLoader(std::vector<std::string> files) : m_files(files) {}
353+
MultiLoader(std::vector<std::string> files) : m_files(files) {}
354+
355+
static std::unique_ptr<MultiLoader> Create(Loader *loader) {
356+
if (!loader)
357+
return {};
358+
359+
FileSpec file = loader->GetFile<typename T::Info>();
360+
if (!file)
361+
return {};
362+
363+
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
364+
if (auto err = error_or_file.getError())
365+
return {};
372366

373-
static std::unique_ptr<CommandLoader> Create(Loader *loader);
374-
llvm::Optional<std::string> GetNextFile();
367+
std::vector<std::string> files;
368+
llvm::yaml::Input yin((*error_or_file)->getBuffer());
369+
yin >> files;
370+
371+
if (auto err = yin.error())
372+
return {};
373+
374+
for (auto &file : files) {
375+
FileSpec absolute_path =
376+
loader->GetRoot().CopyByAppendingPathComponent(file);
377+
file = absolute_path.GetPath();
378+
}
379+
380+
return std::make_unique<MultiLoader<T>>(std::move(files));
381+
}
382+
383+
llvm::Optional<std::string> GetNextFile() {
384+
if (m_index >= m_files.size())
385+
return {};
386+
return m_files[m_index++];
387+
}
375388

376389
private:
377390
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
@@ -419,20 +419,18 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
419419
return true;
420420
}
421421
case eReproducerProviderCommands: {
422-
// Create a new command loader.
423-
std::unique_ptr<repro::CommandLoader> command_loader =
424-
repro::CommandLoader::Create(loader);
425-
if (!command_loader) {
422+
std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
423+
repro::MultiLoader<repro::CommandProvider>::Create(loader);
424+
if (!multi_loader) {
426425
SetError(result,
427426
make_error<StringError>(llvm::inconvertibleErrorCode(),
428427
"Unable to create command loader."));
429428
return false;
430429
}
431430

432431
// Iterate over the command files and dump them.
433-
while (true) {
434-
llvm::Optional<std::string> command_file =
435-
command_loader->GetNextFile();
432+
llvm::Optional<std::string> command_file;
433+
while ((command_file = multi_loader->GetNextFile())) {
436434
if (!command_file)
437435
break;
438436

@@ -448,24 +446,29 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
448446
return true;
449447
}
450448
case eReproducerProviderGDB: {
451-
FileSpec gdb_file = loader->GetFile<ProcessGDBRemoteProvider::Info>();
452-
auto error_or_file = MemoryBuffer::getFile(gdb_file.GetPath());
453-
if (auto err = error_or_file.getError()) {
454-
SetError(result, errorCodeToError(err));
455-
return false;
456-
}
449+
std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
450+
multi_loader =
451+
repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
452+
llvm::Optional<std::string> gdb_file;
453+
while ((gdb_file = multi_loader->GetNextFile())) {
454+
auto error_or_file = MemoryBuffer::getFile(*gdb_file);
455+
if (auto err = error_or_file.getError()) {
456+
SetError(result, errorCodeToError(err));
457+
return false;
458+
}
457459

458-
std::vector<GDBRemotePacket> packets;
459-
yaml::Input yin((*error_or_file)->getBuffer());
460-
yin >> packets;
460+
std::vector<GDBRemotePacket> packets;
461+
yaml::Input yin((*error_or_file)->getBuffer());
462+
yin >> packets;
461463

462-
if (auto err = yin.error()) {
463-
SetError(result, errorCodeToError(err));
464-
return false;
465-
}
464+
if (auto err = yin.error()) {
465+
SetError(result, errorCodeToError(err));
466+
return false;
467+
}
466468

467-
for (GDBRemotePacket &packet : packets) {
468-
packet.Dump(result.GetOutputStream());
469+
for (GDBRemotePacket &packet : packets) {
470+
packet.Dump(result.GetOutputStream());
471+
}
469472
}
470473

471474
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)