Skip to content

Commit bec7fde

Browse files
authored
Merge pull request #53 from JDevlieghere/cherrypick/latest-reproducers
Cherrypick/latest reproducers
2 parents c6ee456 + 0cfa969 commit bec7fde

29 files changed

+766
-361
lines changed

lldb/include/lldb/Utility/GDBRemote.h

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===-- GDBRemote.h ----------------------------------------------*- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef liblldb_GDBRemote_h_
10+
#define liblldb_GDBRemote_h_
11+
12+
#include "lldb/Utility/StreamString.h"
13+
#include "lldb/lldb-enumerations.h"
14+
#include "lldb/lldb-public.h"
15+
#include "llvm/Support/YAMLTraits.h"
16+
#include "llvm/Support/raw_ostream.h"
17+
18+
#include <stddef.h>
19+
#include <stdint.h>
20+
#include <string>
21+
#include <vector>
22+
23+
namespace lldb_private {
24+
25+
class StreamGDBRemote : public StreamString {
26+
public:
27+
StreamGDBRemote();
28+
29+
StreamGDBRemote(uint32_t flags, uint32_t addr_size,
30+
lldb::ByteOrder byte_order);
31+
32+
~StreamGDBRemote() override;
33+
34+
/// Output a block of data to the stream performing GDB-remote escaping.
35+
///
36+
/// \param[in] s
37+
/// A block of data.
38+
///
39+
/// \param[in] src_len
40+
/// The amount of data to write.
41+
///
42+
/// \return
43+
/// Number of bytes written.
44+
// TODO: Convert this function to take ArrayRef<uint8_t>
45+
int PutEscapedBytes(const void *s, size_t src_len);
46+
};
47+
48+
/// GDB remote packet as used by the reproducer and the GDB remote
49+
/// communication history. Packets can be serialized to file.
50+
struct GDBRemotePacket {
51+
52+
friend llvm::yaml::MappingTraits<GDBRemotePacket>;
53+
54+
enum Type { ePacketTypeInvalid = 0, ePacketTypeSend, ePacketTypeRecv };
55+
56+
GDBRemotePacket()
57+
: packet(), type(ePacketTypeInvalid), bytes_transmitted(0), packet_idx(0),
58+
tid(LLDB_INVALID_THREAD_ID) {}
59+
60+
void Clear() {
61+
packet.data.clear();
62+
type = ePacketTypeInvalid;
63+
bytes_transmitted = 0;
64+
packet_idx = 0;
65+
tid = LLDB_INVALID_THREAD_ID;
66+
}
67+
68+
struct BinaryData {
69+
std::string data;
70+
};
71+
72+
void Serialize(llvm::raw_ostream &strm) const;
73+
void Dump(Stream &strm) const;
74+
75+
BinaryData packet;
76+
Type type;
77+
uint32_t bytes_transmitted;
78+
uint32_t packet_idx;
79+
lldb::tid_t tid;
80+
81+
private:
82+
llvm::StringRef GetTypeStr() const;
83+
};
84+
85+
} // namespace lldb_private
86+
87+
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(lldb_private::GDBRemotePacket)
88+
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(std::vector<lldb_private::GDBRemotePacket>)
89+
90+
namespace llvm {
91+
namespace yaml {
92+
93+
template <>
94+
struct ScalarEnumerationTraits<lldb_private::GDBRemotePacket::Type> {
95+
static void enumeration(IO &io, lldb_private::GDBRemotePacket::Type &value);
96+
};
97+
98+
template <> struct ScalarTraits<lldb_private::GDBRemotePacket::BinaryData> {
99+
static void output(const lldb_private::GDBRemotePacket::BinaryData &, void *,
100+
raw_ostream &);
101+
102+
static StringRef input(StringRef, void *,
103+
lldb_private::GDBRemotePacket::BinaryData &);
104+
105+
static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
106+
};
107+
108+
template <> struct MappingTraits<lldb_private::GDBRemotePacket> {
109+
static void mapping(IO &io, lldb_private::GDBRemotePacket &Packet);
110+
111+
static StringRef validate(IO &io, lldb_private::GDBRemotePacket &);
112+
};
113+
114+
} // namespace yaml
115+
} // namespace llvm
116+
117+
#endif // liblldb_GDBRemote_h_

lldb/include/lldb/Utility/Reproducer.h

+75-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
#include "lldb/Utility/FileCollector.h"
1313
#include "lldb/Utility/FileSpec.h"
14-
1514
#include "llvm/ADT/DenseMap.h"
1615
#include "llvm/Support/Error.h"
1716
#include "llvm/Support/YAMLTraits.h"
@@ -130,6 +129,27 @@ class VersionProvider : public Provider<VersionProvider> {
130129
static char ID;
131130
};
132131

132+
/// Provider for the LLDB current working directroy.
133+
///
134+
/// When the reproducer is kept, it writes lldb's current working directory to
135+
/// a file named cwd.txt in the reproducer root.
136+
class WorkingDirectoryProvider : public Provider<WorkingDirectoryProvider> {
137+
public:
138+
WorkingDirectoryProvider(const FileSpec &directory) : Provider(directory) {
139+
llvm::SmallString<128> cwd;
140+
if (std::error_code EC = llvm::sys::fs::current_path(cwd))
141+
return;
142+
m_cwd = cwd.str();
143+
}
144+
struct Info {
145+
static const char *name;
146+
static const char *file;
147+
};
148+
void Keep() override;
149+
std::string m_cwd;
150+
static char ID;
151+
};
152+
133153
class DataRecorder {
134154
public:
135155
DataRecorder(const FileSpec &filename, std::error_code &ec)
@@ -181,12 +201,39 @@ class CommandProvider : public Provider<CommandProvider> {
181201
std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
182202
};
183203

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+
184230
/// The generator is responsible for the logic needed to generate a
185231
/// reproducer. For doing so it relies on providers, who serialize data that
186232
/// is necessary for reproducing a failure.
187233
class Generator final {
234+
188235
public:
189-
Generator(const FileSpec &root);
236+
Generator(FileSpec root);
190237
~Generator();
191238

192239
/// Method to indicate we want to keep the reproducer. If reproducer
@@ -243,7 +290,7 @@ class Generator final {
243290

244291
class Loader final {
245292
public:
246-
Loader(const FileSpec &root);
293+
Loader(FileSpec root);
247294

248295
template <typename T> FileSpec GetFile() {
249296
if (!HasFile(T::file))
@@ -252,6 +299,15 @@ class Loader final {
252299
return GetRoot().CopyByAppendingPathComponent(T::file);
253300
}
254301

302+
template <typename T> llvm::Expected<std::string> LoadBuffer() {
303+
FileSpec file = GetFile<typename T::Info>();
304+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
305+
llvm::vfs::getRealFileSystem()->getBufferForFile(file.GetPath());
306+
if (!buffer)
307+
return llvm::errorCodeToError(buffer.getError());
308+
return (*buffer)->getBuffer().str();
309+
}
310+
255311
llvm::Error LoadIndex();
256312

257313
const FileSpec &GetRoot() const { return m_root; }
@@ -284,6 +340,9 @@ class Reproducer {
284340

285341
FileSpec GetReproducerPath() const;
286342

343+
bool IsCapturing() { return static_cast<bool>(m_generator); };
344+
bool IsReplaying() { return static_cast<bool>(m_loader); };
345+
287346
protected:
288347
llvm::Error SetCapture(llvm::Optional<FileSpec> root);
289348
llvm::Error SetReplay(llvm::Optional<FileSpec> root);
@@ -297,6 +356,19 @@ class Reproducer {
297356
mutable std::mutex m_mutex;
298357
};
299358

359+
/// Helper class for replaying commands through the reproducer.
360+
class CommandLoader {
361+
public:
362+
CommandLoader(std::vector<std::string> files) : m_files(files) {}
363+
364+
static std::unique_ptr<CommandLoader> Create(Loader *loader);
365+
llvm::Optional<std::string> GetNextFile();
366+
367+
private:
368+
std::vector<std::string> m_files;
369+
unsigned m_index = 0;
370+
};
371+
300372
} // namespace repro
301373
} // namespace lldb_private
302374

lldb/include/lldb/Utility/StreamGDBRemote.h

-45
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
run
22
reproducer status
3+
reproducer dump -p files
34
reproducer generate
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
run
2+
reproducer status
3+
reproducer dump -p cwd
4+
reproducer generate

lldb/lit/Reproducer/TestDump.test

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This tests the reproducer dump functionality.
2+
3+
# Generate a reproducer.
4+
# RUN: mkdir -p %t
5+
# RUN: rm -rf %t.repro
6+
# RUN: %clang %S/Inputs/simple.c -g -o %t/reproducer.out
7+
# RUN: %lldb -x -b -s %S/Inputs/FileCapture.in -o 'reproducer dump -p files' --capture --capture-path %t.repro %t/reproducer.out
8+
9+
# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES
10+
# FILES: 'reproducer.out'
11+
# FILES: 'FileCapture.in'
12+
13+
# RUN: %lldb -b -o 'reproducer dump -p version -f %t.repro' | FileCheck %s --check-prefix VERSION
14+
# VERSION: lldb version
15+
16+
# RUN: %lldb -b -o 'reproducer dump -p commands -f %t.repro' | FileCheck %s --check-prefix COMMANDS
17+
# COMMANDS: command source
18+
# COMMANDS: target create
19+
# COMMANDS: command source
20+
21+
# RUN: %lldb -b -o 'reproducer dump -p gdb -f %t.repro' | FileCheck %s --check-prefix GDB
22+
# GDB: send packet: $QStartNoAckMode#b0
23+
# GDB: read packet: $OK#9a
24+
25+
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix FILES
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This tests relative capture paths.
2+
3+
# RUN: mkdir -p %t
4+
# RUN: cd %t
5+
# RUN: rm -rf ./foo
6+
# RUN: %clang %S/Inputs/simple.c -g -o %t/reproducer.out
7+
# RUN: %lldb -x -b -s %S/Inputs/FileCapture.in -o 'reproducer dump -p files' --capture --capture-path ./foo %t/reproducer.out
8+
# RUN: %lldb --replay ./foo
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This tests relative capture paths.
2+
3+
# RUN: echo "CHECK: %t" > %t.check
4+
5+
# RUN: rm -rf %t.repro
6+
# RUN: mkdir -p %t.repro
7+
# RUN: mkdir -p %t
8+
# RUN: cd %t
9+
# RUN: %clang %S/Inputs/simple.c -g -o %t/reproducer.out
10+
# RUN: %lldb -x -b -s %S/Inputs/WorkingDir.in --capture --capture-path %t.repro %t/reproducer.out
11+
12+
# RUN: cat %t.repro/cwd.txt | FileCheck %t.check
13+
# RUN: %lldb --replay %t.repro | FileCheck %t.check

0 commit comments

Comments
 (0)