Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Utility/ReproducerProvider.h
Line
Count
Source (jump to first uncovered line)
1
//===-- Reproducer.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 LLDB_UTILITY_REPRODUCER_PROVIDER_H
10
#define LLDB_UTILITY_REPRODUCER_PROVIDER_H
11
12
#include "lldb/Utility/FileSpec.h"
13
#include "lldb/Utility/ProcessInfo.h"
14
#include "lldb/Utility/Reproducer.h"
15
#include "lldb/Utility/UUID.h"
16
#include "llvm/ADT/StringRef.h"
17
#include "llvm/Support/Error.h"
18
#include "llvm/Support/FileCollector.h"
19
#include "llvm/Support/YAMLTraits.h"
20
21
#include <string>
22
#include <utility>
23
#include <vector>
24
25
namespace lldb_private {
26
namespace repro {
27
28
/// The recorder is a small object handed out by a provider to record data. It
29
/// is commonly used in combination with a MultiProvider which is meant to
30
/// record information for multiple instances of the same source of data.
31
class AbstractRecorder {
32
protected:
33
  AbstractRecorder(const FileSpec &filename, std::error_code &ec)
34
      : m_filename(filename.GetFilename().GetStringRef()),
35
        m_os(filename.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF),
36
50
        m_record(true) {}
37
38
public:
39
41
  const FileSpec &GetFilename() { return m_filename; }
40
41
33
  void Stop() {
42
33
    assert(m_record);
43
0
    m_record = false;
44
33
  }
45
46
private:
47
  FileSpec m_filename;
48
49
protected:
50
  llvm::raw_fd_ostream m_os;
51
  bool m_record;
52
};
53
54
/// Recorder that records its data as text to a file.
55
class DataRecorder : public AbstractRecorder {
56
public:
57
  DataRecorder(const FileSpec &filename, std::error_code &ec)
58
38
      : AbstractRecorder(filename, ec) {}
59
60
  static llvm::Expected<std::unique_ptr<DataRecorder>>
61
  Create(const FileSpec &filename);
62
63
69
  template <typename T> void Record(const T &t, bool newline = false) {
64
69
    if (!m_record)
65
1
      return;
66
68
    m_os << t;
67
68
    if (newline)
68
68
      m_os << '\n';
69
68
    m_os.flush();
70
68
  }
71
};
72
73
/// Recorder that records its data as YAML to a file.
74
class YamlRecorder : public AbstractRecorder {
75
public:
76
  YamlRecorder(const FileSpec &filename, std::error_code &ec)
77
2
      : AbstractRecorder(filename, ec) {}
78
79
  static llvm::Expected<std::unique_ptr<YamlRecorder>>
80
  Create(const FileSpec &filename);
81
82
  template <typename T> void Record(const T &t) {
83
    if (!m_record)
84
      return;
85
    llvm::yaml::Output yout(m_os);
86
    // The YAML traits are defined as non-const because they are used for
87
    // serialization and deserialization. The cast is safe because
88
    // serialization doesn't modify the object.
89
    yout << const_cast<T &>(t);
90
    m_os.flush();
91
  }
92
};
93
94
class FlushingFileCollector : public llvm::FileCollectorBase {
95
public:
96
  FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path,
97
                        std::error_code &ec);
98
99
protected:
100
  void addFileImpl(llvm::StringRef file) override;
101
102
  llvm::vfs::directory_iterator
103
  addDirectoryImpl(const llvm::Twine &dir,
104
                   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
105
                   std::error_code &dir_ec) override;
106
107
  llvm::Optional<llvm::raw_fd_ostream> m_files_os;
108
  llvm::Optional<llvm::raw_fd_ostream> m_dirs_os;
109
};
110
111
class FileProvider : public Provider<FileProvider> {
112
public:
113
  struct Info {
114
    static const char *name;
115
    static const char *file;
116
  };
117
118
19
  FileProvider(const FileSpec &directory) : Provider(directory) {
119
19
    std::error_code ec;
120
19
    m_collector = std::make_shared<FlushingFileCollector>(
121
19
        directory.CopyByAppendingPathComponent("files.txt").GetPath(),
122
19
        directory.CopyByAppendingPathComponent("dirs.txt").GetPath(), ec);
123
19
    if (ec)
124
0
      m_collector.reset();
125
19
  }
126
127
27
  std::shared_ptr<llvm::FileCollectorBase> GetFileCollector() {
128
27
    return m_collector;
129
27
  }
130
131
  void RecordInterestingDirectory(const llvm::Twine &dir);
132
  void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
133
134
  static char ID;
135
136
private:
137
  std::shared_ptr<FlushingFileCollector> m_collector;
138
};
139
140
/// Provider for the LLDB version number.
141
///
142
/// When the reproducer is kept, it writes the lldb version to a file named
143
/// version.txt in the reproducer root.
144
class VersionProvider : public Provider<VersionProvider> {
145
public:
146
19
  VersionProvider(const FileSpec &directory) : Provider(directory) {}
147
  struct Info {
148
    static const char *name;
149
    static const char *file;
150
  };
151
19
  void SetVersion(std::string version) {
152
19
    assert(m_version.empty());
153
0
    m_version = std::move(version);
154
19
  }
155
  void Keep() override;
156
  std::string m_version;
157
  static char ID;
158
};
159
160
/// Abstract provider to storing directory paths.
161
template <typename T> class DirectoryProvider : public repro::Provider<T> {
162
public:
163
48
  DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
lldb_private::repro::DirectoryProvider<lldb_private::repro::WorkingDirectoryProvider>::DirectoryProvider(lldb_private::FileSpec const&)
Line
Count
Source
163
24
  DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
lldb_private::repro::DirectoryProvider<lldb_private::repro::HomeDirectoryProvider>::DirectoryProvider(lldb_private::FileSpec const&)
Line
Count
Source
163
24
  DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
164
48
  void SetDirectory(std::string directory) {
165
48
    m_directory = std::move(directory);
166
48
  }
lldb_private::repro::DirectoryProvider<lldb_private::repro::WorkingDirectoryProvider>::SetDirectory(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Line
Count
Source
164
24
  void SetDirectory(std::string directory) {
165
24
    m_directory = std::move(directory);
166
24
  }
lldb_private::repro::DirectoryProvider<lldb_private::repro::HomeDirectoryProvider>::SetDirectory(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Line
Count
Source
164
24
  void SetDirectory(std::string directory) {
165
24
    m_directory = std::move(directory);
166
24
  }
167
38
  llvm::StringRef GetDirectory() { return m_directory; }
lldb_private::repro::DirectoryProvider<lldb_private::repro::WorkingDirectoryProvider>::GetDirectory()
Line
Count
Source
167
19
  llvm::StringRef GetDirectory() { return m_directory; }
lldb_private::repro::DirectoryProvider<lldb_private::repro::HomeDirectoryProvider>::GetDirectory()
Line
Count
Source
167
19
  llvm::StringRef GetDirectory() { return m_directory; }
168
169
32
  void Keep() override {
170
32
    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
171
32
    std::error_code ec;
172
32
    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
173
32
    if (ec)
174
0
      return;
175
32
    os << m_directory << "\n";
176
32
  }
lldb_private::repro::DirectoryProvider<lldb_private::repro::WorkingDirectoryProvider>::Keep()
Line
Count
Source
169
16
  void Keep() override {
170
16
    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
171
16
    std::error_code ec;
172
16
    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
173
16
    if (ec)
174
0
      return;
175
16
    os << m_directory << "\n";
176
16
  }
lldb_private::repro::DirectoryProvider<lldb_private::repro::HomeDirectoryProvider>::Keep()
Line
Count
Source
169
16
  void Keep() override {
170
16
    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
171
16
    std::error_code ec;
172
16
    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
173
16
    if (ec)
174
0
      return;
175
16
    os << m_directory << "\n";
176
16
  }
177
178
protected:
179
  std::string m_directory;
180
};
181
182
/// Provider for the current working directory.
183
///
184
/// When the reproducer is kept, it writes lldb's current working directory to
185
/// a file named cwd.txt in the reproducer root.
186
class WorkingDirectoryProvider
187
    : public DirectoryProvider<WorkingDirectoryProvider> {
188
public:
189
  WorkingDirectoryProvider(const FileSpec &directory)
190
24
      : DirectoryProvider(directory) {
191
24
    llvm::SmallString<128> cwd;
192
24
    if (std::error_code EC = llvm::sys::fs::current_path(cwd))
193
0
      return;
194
24
    SetDirectory(std::string(cwd));
195
24
  }
196
  struct Info {
197
    static const char *name;
198
    static const char *file;
199
  };
200
  static char ID;
201
};
202
203
/// Provider for the home directory.
204
///
205
/// When the reproducer is kept, it writes the user's home directory to a file
206
/// a file named home.txt in the reproducer root.
207
class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
208
public:
209
  HomeDirectoryProvider(const FileSpec &directory)
210
24
      : DirectoryProvider(directory) {
211
24
    llvm::SmallString<128> home_dir;
212
24
    llvm::sys::path::home_directory(home_dir);
213
24
    SetDirectory(std::string(home_dir));
214
24
  }
215
  struct Info {
216
    static const char *name;
217
    static const char *file;
218
  };
219
  static char ID;
220
};
221
222
/// Provider for mapping UUIDs to symbol and executable files.
223
class SymbolFileProvider : public Provider<SymbolFileProvider> {
224
public:
225
1
  SymbolFileProvider(const FileSpec &directory) : Provider(directory) {}
226
227
  void AddSymbolFile(const UUID *uuid, const FileSpec &module_path,
228
                     const FileSpec &symbol_path);
229
  void Keep() override;
230
231
  struct Entry {
232
2
    Entry() = default;
233
0
    Entry(std::string uuid) : uuid(std::move(uuid)) {}
234
    Entry(std::string uuid, std::string module_path, std::string symbol_path)
235
        : uuid(std::move(uuid)), module_path(std::move(module_path)),
236
1
          symbol_path(std::move(symbol_path)) {}
237
238
0
    bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; }
239
0
    bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; }
240
241
    std::string uuid;
242
    std::string module_path;
243
    std::string symbol_path;
244
  };
245
246
  struct Info {
247
    static const char *name;
248
    static const char *file;
249
  };
250
  static char ID;
251
252
private:
253
  std::vector<Entry> m_symbol_files;
254
};
255
256
/// The MultiProvider is a provider that hands out recorder which can be used
257
/// to capture data for different instances of the same object. The recorders
258
/// can be passed around or stored as an instance member.
259
///
260
/// The Info::file for the MultiProvider contains an index of files for every
261
/// recorder. Use the MultiLoader to read the index and get the individual
262
/// files.
263
template <typename T, typename V>
264
class MultiProvider : public repro::Provider<V> {
265
public:
266
19
  MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
267
268
38
  T *GetNewRecorder() {
269
38
    std::size_t i = m_recorders.size() + 1;
270
38
    std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
271
38
                            llvm::Twine(i) + llvm::Twine(".yaml"))
272
38
                               .str();
273
38
    auto recorder_or_error =
274
38
        T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
275
38
    if (!recorder_or_error) {
276
0
      llvm::consumeError(recorder_or_error.takeError());
277
0
      return nullptr;
278
0
    }
279
280
38
    m_recorders.push_back(std::move(*recorder_or_error));
281
38
    return m_recorders.back().get();
282
38
  }
283
284
15
  void Keep() override {
285
15
    std::vector<std::string> files;
286
30
    for (auto &recorder : m_recorders) {
287
30
      recorder->Stop();
288
30
      files.push_back(recorder->GetFilename().GetPath());
289
30
    }
290
291
15
    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
292
15
    std::error_code ec;
293
15
    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
294
15
    if (ec)
295
0
      return;
296
15
    llvm::yaml::Output yout(os);
297
15
    yout << files;
298
15
  }
299
300
4
  void Discard() override { m_recorders.clear(); }
301
302
private:
303
  std::vector<std::unique_ptr<T>> m_recorders;
304
};
305
306
class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
307
public:
308
  struct Info {
309
    static const char *name;
310
    static const char *file;
311
  };
312
313
  CommandProvider(const FileSpec &directory)
314
19
      : MultiProvider<DataRecorder, CommandProvider>(directory) {}
315
316
  static char ID;
317
};
318
319
class ProcessInfoRecorder : public AbstractRecorder {
320
public:
321
  ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
322
1
      : AbstractRecorder(filename, ec) {}
323
324
  static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
325
  Create(const FileSpec &filename);
326
327
  void Record(const ProcessInstanceInfoList &process_infos);
328
};
329
330
class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
331
public:
332
  struct Info {
333
    static const char *name;
334
    static const char *file;
335
  };
336
337
1
  ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
338
339
  ProcessInfoRecorder *GetNewProcessInfoRecorder();
340
341
  void Keep() override;
342
  void Discard() override;
343
344
  static char ID;
345
346
private:
347
  std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
348
  std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
349
};
350
351
/// Loader for data captured with the MultiProvider. It will read the index and
352
/// return the path to the files in the index.
353
template <typename T> class MultiLoader {
354
public:
355
3
  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
lldb_private::repro::MultiLoader<lldb_private::repro::CommandProvider>::MultiLoader(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >)
Line
Count
Source
355
1
  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
lldb_private::repro::MultiLoader<lldb_private::repro::GDBRemoteProvider>::MultiLoader(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >)
Line
Count
Source
355
1
  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
lldb_private::repro::MultiLoader<lldb_private::repro::ProcessInfoProvider>::MultiLoader(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >)
Line
Count
Source
355
1
  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
356
357
364
  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
358
364
    if (!loader)
359
359
      return {};
360
361
5
    FileSpec file = loader->GetFile<typename T::Info>();
362
5
    if (!file)
363
0
      return {};
364
365
5
    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
366
5
    if (auto err = error_or_file.getError())
367
2
      return {};
368
369
3
    std::vector<std::string> files;
370
3
    llvm::yaml::Input yin((*error_or_file)->getBuffer());
371
3
    yin >> files;
372
373
3
    if (auto err = yin.error())
374
0
      return {};
375
376
4
    
for (auto &file : files)3
{
377
4
      FileSpec absolute_path =
378
4
          loader->GetRoot().CopyByAppendingPathComponent(file);
379
4
      file = absolute_path.GetPath();
380
4
    }
381
382
3
    return std::make_unique<MultiLoader<T>>(std::move(files));
383
3
  }
lldb_private::repro::MultiLoader<lldb_private::repro::CommandProvider>::Create(lldb_private::repro::Loader*)
Line
Count
Source
357
354
  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
358
354
    if (!loader)
359
352
      return {};
360
361
2
    FileSpec file = loader->GetFile<typename T::Info>();
362
2
    if (!file)
363
0
      return {};
364
365
2
    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
366
2
    if (auto err = error_or_file.getError())
367
1
      return {};
368
369
1
    std::vector<std::string> files;
370
1
    llvm::yaml::Input yin((*error_or_file)->getBuffer());
371
1
    yin >> files;
372
373
1
    if (auto err = yin.error())
374
0
      return {};
375
376
2
    
for (auto &file : files)1
{
377
2
      FileSpec absolute_path =
378
2
          loader->GetRoot().CopyByAppendingPathComponent(file);
379
2
      file = absolute_path.GetPath();
380
2
    }
381
382
1
    return std::make_unique<MultiLoader<T>>(std::move(files));
383
1
  }
lldb_private::repro::MultiLoader<lldb_private::repro::GDBRemoteProvider>::Create(lldb_private::repro::Loader*)
Line
Count
Source
357
2
  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
358
2
    if (!loader)
359
0
      return {};
360
361
2
    FileSpec file = loader->GetFile<typename T::Info>();
362
2
    if (!file)
363
0
      return {};
364
365
2
    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
366
2
    if (auto err = error_or_file.getError())
367
1
      return {};
368
369
1
    std::vector<std::string> files;
370
1
    llvm::yaml::Input yin((*error_or_file)->getBuffer());
371
1
    yin >> files;
372
373
1
    if (auto err = yin.error())
374
0
      return {};
375
376
1
    for (auto &file : files) {
377
1
      FileSpec absolute_path =
378
1
          loader->GetRoot().CopyByAppendingPathComponent(file);
379
1
      file = absolute_path.GetPath();
380
1
    }
381
382
1
    return std::make_unique<MultiLoader<T>>(std::move(files));
383
1
  }
lldb_private::repro::MultiLoader<lldb_private::repro::ProcessInfoProvider>::Create(lldb_private::repro::Loader*)
Line
Count
Source
357
8
  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
358
8
    if (!loader)
359
7
      return {};
360
361
1
    FileSpec file = loader->GetFile<typename T::Info>();
362
1
    if (!file)
363
0
      return {};
364
365
1
    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
366
1
    if (auto err = error_or_file.getError())
367
0
      return {};
368
369
1
    std::vector<std::string> files;
370
1
    llvm::yaml::Input yin((*error_or_file)->getBuffer());
371
1
    yin >> files;
372
373
1
    if (auto err = yin.error())
374
0
      return {};
375
376
1
    for (auto &file : files) {
377
1
      FileSpec absolute_path =
378
1
          loader->GetRoot().CopyByAppendingPathComponent(file);
379
1
      file = absolute_path.GetPath();
380
1
    }
381
382
1
    return std::make_unique<MultiLoader<T>>(std::move(files));
383
1
  }
384
385
7
  llvm::Optional<std::string> GetNextFile() {
386
7
    if (m_index >= m_files.size())
387
3
      return {};
388
4
    return m_files[m_index++];
389
7
  }
lldb_private::repro::MultiLoader<lldb_private::repro::CommandProvider>::GetNextFile()
Line
Count
Source
385
3
  llvm::Optional<std::string> GetNextFile() {
386
3
    if (m_index >= m_files.size())
387
1
      return {};
388
2
    return m_files[m_index++];
389
3
  }
lldb_private::repro::MultiLoader<lldb_private::repro::GDBRemoteProvider>::GetNextFile()
Line
Count
Source
385
2
  llvm::Optional<std::string> GetNextFile() {
386
2
    if (m_index >= m_files.size())
387
1
      return {};
388
1
    return m_files[m_index++];
389
2
  }
lldb_private::repro::MultiLoader<lldb_private::repro::ProcessInfoProvider>::GetNextFile()
Line
Count
Source
385
2
  llvm::Optional<std::string> GetNextFile() {
386
2
    if (m_index >= m_files.size())
387
1
      return {};
388
1
    return m_files[m_index++];
389
2
  }
390
391
private:
392
  std::vector<std::string> m_files;
393
  unsigned m_index = 0;
394
};
395
396
class SymbolFileLoader {
397
public:
398
  SymbolFileLoader(Loader *loader);
399
  std::pair<FileSpec, FileSpec> GetPaths(const UUID *uuid) const;
400
401
private:
402
  // Sorted list of UUID to path mappings.
403
  std::vector<SymbolFileProvider::Entry> m_symbol_files;
404
};
405
406
/// Helper to read directories written by the DirectoryProvider.
407
template <typename T>
408
7
llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
409
7
  llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
410
7
  if (!dir)
411
0
    return dir.takeError();
412
7
  return std::string(llvm::StringRef(*dir).rtrim());
413
7
}
llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > lldb_private::repro::GetDirectoryFrom<lldb_private::repro::WorkingDirectoryProvider>(lldb_private::repro::Loader*)
Line
Count
Source
408
3
llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
409
3
  llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
410
3
  if (!dir)
411
0
    return dir.takeError();
412
3
  return std::string(llvm::StringRef(*dir).rtrim());
413
3
}
llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > lldb_private::repro::GetDirectoryFrom<lldb_private::repro::HomeDirectoryProvider>(lldb_private::repro::Loader*)
Line
Count
Source
408
4
llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
409
4
  llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
410
4
  if (!dir)
411
0
    return dir.takeError();
412
4
  return std::string(llvm::StringRef(*dir).rtrim());
413
4
}
414
415
} // namespace repro
416
} // namespace lldb_private
417
418
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry)
419
420
namespace llvm {
421
namespace yaml {
422
template <>
423
struct MappingTraits<lldb_private::repro::SymbolFileProvider::Entry> {
424
  static void mapping(IO &io,
425
3
                      lldb_private::repro::SymbolFileProvider::Entry &entry) {
426
3
    io.mapRequired("uuid", entry.uuid);
427
3
    io.mapRequired("module-path", entry.module_path);
428
3
    io.mapRequired("symbol-path", entry.symbol_path);
429
3
  }
430
};
431
} // namespace yaml
432
} // namespace llvm
433
434
#endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H