1//===-- ReproducerInstrumentation.h -----------------------------*- C++ -*-===//
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
8#ifndef LLDB_UTILITY_REPRODUCER_INSTRUMENTATION_H
9#define LLDB_UTILITY_REPRODUCER_INSTRUMENTATION_H
10
11#include "lldb/Utility/FileSpec.h"
12#include "lldb/Utility/Log.h"
13#include "lldb/Utility/Logging.h"
14
15#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/ErrorHandling.h"
18
19#include <iostream>
20#include <map>
21#include <type_traits>
22
23template <typename T,
24          typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
25inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
26  ss << t;
27}
28
29template <typename T, typename std::enable_if<!std::is_fundamental<T>::value,
30                                              int>::type = 0>
31inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
32  ss << &t;
33}
34
35template <typename T>
36inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) {
37  ss << reinterpret_cast<const void *>(t);
38}
39
40template <>
41inline void stringify_append<char>(llvm::raw_string_ostream &ss,
42                                   const char *t) {
43  ss << '\"' << t << '\"';
44}
45
46template <typename Head>
47inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) {
48  stringify_append(ss, head);
49}
50
51template <typename Head, typename... Tail>
52inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head,
53                             const Tail &... tail) {
54  stringify_append(ss, head);
55  ss << ", ";
56  stringify_helper(ss, tail...);
57}
58
59template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
60  std::string buffer;
61  llvm::raw_string_ostream ss(buffer);
62  stringify_helper(ss, ts...);
63  return ss.str();
64}
65
66// Define LLDB_REPRO_INSTR_TRACE to trace to stderr instead of LLDB's log
67// infrastructure. This is useful when you need to see traces before the logger
68// is initialized or enabled.
69// #define LLDB_REPRO_INSTR_TRACE
70
71#define LLDB_REGISTER_CONSTRUCTOR(Class, Signature)                            \
72  R.Register<Class * Signature>(&construct<Class Signature>::doit, "", #Class, \
73                                #Class, #Signature)
74#define LLDB_REGISTER_METHOD(Result, Class, Method, Signature)                 \
75  R.Register(                                                                  \
76      &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::doit,     \
77      #Result, #Class, #Method, #Signature)
78#define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature)           \
79  R.Register(&invoke<Result(Class::*) Signature const>::method_const<(         \
80                 &Class::Method)>::doit,                                       \
81             #Result, #Class, #Method, #Signature)
82#define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature)          \
83  R.Register<Result Signature>(                                                \
84      static_cast<Result(*) Signature>(&Class::Method), #Result, #Class,       \
85      #Method, #Signature)
86
87#define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...)                         \
88  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION,              \
89                                            stringify_args(__VA_ARGS__));      \
90  if (lldb_private::repro::InstrumentationData data =                          \
91          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
92    sb_recorder.Record(data.GetSerializer(), data.GetRegistry(),               \
93                       &lldb_private::repro::construct<Class Signature>::doit, \
94                       __VA_ARGS__);                                           \
95    sb_recorder.RecordResult(this);                                            \
96  }
97
98#define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class)                                 \
99  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION);             \
100  if (lldb_private::repro::InstrumentationData data =                          \
101          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
102    sb_recorder.Record(data.GetSerializer(), data.GetRegistry(),               \
103                       &lldb_private::repro::construct<Class()>::doit);        \
104    sb_recorder.RecordResult(this);                                            \
105  }
106
107#define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...)              \
108  lldb_private::repro::Recorder sb_recorder(                                   \
109      LLVM_PRETTY_FUNCTION, stringify_args(*this, __VA_ARGS__));               \
110  if (lldb_private::repro::InstrumentationData data =                          \
111          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
112    sb_recorder.Record(                                                        \
113        data.GetSerializer(), data.GetRegistry(),                              \
114        &lldb_private::repro::invoke<Result(Class::*) Signature>::method<(     \
115            &Class::Method)>::doit,                                            \
116        this, __VA_ARGS__);                                                    \
117  }
118
119#define LLDB_RECORD_METHOD_CONST(Result, Class, Method, Signature, ...)        \
120  lldb_private::repro::Recorder sb_recorder(                                   \
121      LLVM_PRETTY_FUNCTION, stringify_args(*this, __VA_ARGS__));               \
122  if (lldb_private::repro::InstrumentationData data =                          \
123          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
124    sb_recorder.Record(                                                        \
125        data.GetSerializer(), data.GetRegistry(),                              \
126        &lldb_private::repro::invoke<Result(                                   \
127            Class::*) Signature const>::method_const<(&Class::Method)>::doit,  \
128        this, __VA_ARGS__);                                                    \
129  }
130
131#define LLDB_RECORD_METHOD_NO_ARGS(Result, Class, Method)                      \
132  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION,              \
133                                            stringify_args(*this));            \
134  if (lldb_private::repro::InstrumentationData data =                          \
135          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
136    sb_recorder.Record(data.GetSerializer(), data.GetRegistry(),               \
137                       &lldb_private::repro::invoke<Result (                   \
138                           Class::*)()>::method<(&Class::Method)>::doit,       \
139                       this);                                                  \
140  }
141
142#define LLDB_RECORD_METHOD_CONST_NO_ARGS(Result, Class, Method)                \
143  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION,              \
144                                            stringify_args(*this));            \
145  if (lldb_private::repro::InstrumentationData data =                          \
146          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
147    sb_recorder.Record(                                                        \
148        data.GetSerializer(), data.GetRegistry(),                              \
149        &lldb_private::repro::invoke<Result (                                  \
150            Class::*)() const>::method_const<(&Class::Method)>::doit,          \
151        this);                                                                 \
152  }
153
154#define LLDB_RECORD_STATIC_METHOD(Result, Class, Method, Signature, ...)       \
155  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION,              \
156                                            stringify_args(__VA_ARGS__));      \
157  if (lldb_private::repro::InstrumentationData data =                          \
158          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
159    sb_recorder.Record(data.GetSerializer(), data.GetRegistry(),               \
160                       static_cast<Result(*) Signature>(&Class::Method),       \
161                       __VA_ARGS__);                                           \
162  }
163
164#define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method)               \
165  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION);             \
166  if (lldb_private::repro::InstrumentationData data =                          \
167          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
168    sb_recorder.Record(data.GetSerializer(), data.GetRegistry(),               \
169                       static_cast<Result (*)()>(&Class::Method));             \
170  }
171
172#define LLDB_RECORD_RESULT(Result) sb_recorder.RecordResult(Result);
173
174/// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record
175/// anything. It's used to track API boundaries when we cannot record for
176/// technical reasons.
177#define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...)               \
178  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION,              \
179                                            stringify_args(__VA_ARGS__));
180#define LLDB_RECORD_DUMMY_NO_ARGS(Result, Class, Method)                       \
181  lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION);
182
183namespace lldb_private {
184namespace repro {
185
186/// Mapping between serialized indices and their corresponding objects.
187///
188/// This class is used during replay to map indices back to in-memory objects.
189///
190/// When objects are constructed, they are added to this mapping using
191/// AddObjectForIndex.
192///
193/// When an object is passed to a function, its index is deserialized and
194/// AddObjectForIndex returns the corresponding object. If there is no object
195/// for the given index, a nullptr is returend. The latter is valid when custom
196/// replay code is in place and the actual object is ignored.
197class IndexToObject {
198public:
199  /// Returns an object as a pointer for the given index or nullptr if not
200  /// present in the map.
201  template <typename T> T *GetObjectForIndex(unsigned idx) {
202    assert(idx != 0 && "Cannot get object for sentinel");
203    void *object = GetObjectForIndexImpl(idx);
204    return static_cast<T *>(object);
205  }
206
207  /// Adds a pointer to an object to the mapping for the given index.
208  template <typename T> void AddObjectForIndex(unsigned idx, T *object) {
209    AddObjectForIndexImpl(
210        idx, static_cast<void *>(
211                 const_cast<typename std::remove_const<T>::type *>(object)));
212  }
213
214  /// Adds a reference to an object to the mapping for the given index.
215  template <typename T> void AddObjectForIndex(unsigned idx, T &object) {
216    AddObjectForIndexImpl(
217        idx, static_cast<void *>(
218                 const_cast<typename std::remove_const<T>::type *>(&object)));
219  }
220
221private:
222  /// Helper method that does the actual lookup. The void* result is later cast
223  /// by the caller.
224  void *GetObjectForIndexImpl(unsigned idx);
225
226  /// Helper method that does the actual insertion.
227  void AddObjectForIndexImpl(unsigned idx, void *object);
228
229  /// Keeps a mapping between indices and their corresponding object.
230  llvm::DenseMap<unsigned, void *> m_mapping;
231};
232
233/// We need to differentiate between pointers to fundamental and
234/// non-fundamental types. See the corresponding Deserializer::Read method
235/// for the reason why.
236struct PointerTag {};
237struct ReferenceTag {};
238struct ValueTag {};
239struct FundamentalPointerTag {};
240struct FundamentalReferenceTag {};
241struct NotImplementedTag {};
242
243/// Return the deserialization tag for the given type T.
244template <class T> struct serializer_tag {
245  typedef typename std::conditional<std::is_trivially_copyable<T>::value, ValueTag, NotImplementedTag>::type type;
246};
247template <class T> struct serializer_tag<T *> {
248  typedef
249      typename std::conditional<std::is_fundamental<T>::value,
250                                FundamentalPointerTag, PointerTag>::type type;
251};
252template <class T> struct serializer_tag<T &> {
253  typedef typename std::conditional<std::is_fundamental<T>::value,
254                                    FundamentalReferenceTag, ReferenceTag>::type
255      type;
256};
257
258/// Deserializes data from a buffer. It is used to deserialize function indices
259/// to replay, their arguments and return values.
260///
261/// Fundamental types and strings are read by value. Objects are read by their
262/// index, which get translated by the IndexToObject mapping maintained in
263/// this class.
264///
265/// Additional bookkeeping with regards to the IndexToObject is required to
266/// deserialize objects. When a constructor is run or an object is returned by
267/// value, we need to capture the object and add it to the index together with
268/// its index. This is the job of HandleReplayResult(Void).
269class Deserializer {
270public:
271  Deserializer(llvm::StringRef buffer) : m_buffer(buffer) {}
272
273  /// Returns true when the buffer has unread data.
274  bool HasData(unsigned size) { return size <= m_buffer.size(); }
275
276  /// Deserialize and interpret value as T.
277  template <typename T> T Deserialize() {
278#ifdef LLDB_REPRO_INSTR_TRACE
279    llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << "\n";
280#endif
281    return Read<T>(typename serializer_tag<T>::type());
282  }
283
284  /// Store the returned value in the index-to-object mapping.
285  template <typename T> void HandleReplayResult(const T &t) {
286    unsigned result = Deserialize<unsigned>();
287    if (std::is_fundamental<T>::value)
288      return;
289    // We need to make a copy as the original object might go out of scope.
290    m_index_to_object.AddObjectForIndex(result, new T(t));
291  }
292
293  /// Store the returned value in the index-to-object mapping.
294  template <typename T> void HandleReplayResult(T *t) {
295    unsigned result = Deserialize<unsigned>();
296    if (std::is_fundamental<T>::value)
297      return;
298    m_index_to_object.AddObjectForIndex(result, t);
299  }
300
301  /// All returned types are recorded, even when the function returns a void.
302  /// The latter requires special handling.
303  void HandleReplayResultVoid() {
304    unsigned result = Deserialize<unsigned>();
305    assert(result == 0);
306    (void)result;
307  }
308
309private:
310  template <typename T> T Read(NotImplementedTag) {
311    m_buffer = m_buffer.drop_front(sizeof(T));
312    return T();
313  }
314
315  template <typename T> T Read(ValueTag) {
316    assert(HasData(sizeof(T)));
317    T t;
318    std::memcpy(reinterpret_cast<char *>(&t), m_buffer.data(), sizeof(T));
319    m_buffer = m_buffer.drop_front(sizeof(T));
320    return t;
321  }
322
323  template <typename T> T Read(PointerTag) {
324    typedef typename std::remove_pointer<T>::type UnderlyingT;
325    return m_index_to_object.template GetObjectForIndex<UnderlyingT>(
326        Deserialize<unsigned>());
327  }
328
329  template <typename T> T Read(ReferenceTag) {
330    typedef typename std::remove_reference<T>::type UnderlyingT;
331    // If this is a reference to a fundamental type we just read its value.
332    return *m_index_to_object.template GetObjectForIndex<UnderlyingT>(
333        Deserialize<unsigned>());
334  }
335
336  /// This method is used to parse references to fundamental types. Because
337  /// they're not recorded in the object table we have serialized their value.
338  /// We read its value, allocate a copy on the heap, and return a pointer to
339  /// the copy.
340  template <typename T> T Read(FundamentalPointerTag) {
341    typedef typename std::remove_pointer<T>::type UnderlyingT;
342    return new UnderlyingT(Deserialize<UnderlyingT>());
343  }
344
345  /// This method is used to parse references to fundamental types. Because
346  /// they're not recorded in the object table we have serialized their value.
347  /// We read its value, allocate a copy on the heap, and return a reference to
348  /// the copy.
349  template <typename T> T Read(FundamentalReferenceTag) {
350    // If this is a reference to a fundamental type we just read its value.
351    typedef typename std::remove_reference<T>::type UnderlyingT;
352    return *(new UnderlyingT(Deserialize<UnderlyingT>()));
353  }
354
355  /// Mapping of indices to objects.
356  IndexToObject m_index_to_object;
357
358  /// Buffer containing the serialized data.
359  llvm::StringRef m_buffer;
360};
361
362/// Partial specialization for C-style strings. We read the string value
363/// instead of treating it as pointer.
364template <> const char *Deserializer::Deserialize<const char *>();
365template <> char *Deserializer::Deserialize<char *>();
366
367/// Helpers to auto-synthesize function replay code. It deserializes the replay
368/// function's arguments one by one and finally calls the corresponding
369/// function.
370template <typename... Remaining> struct DeserializationHelper;
371
372template <typename Head, typename... Tail>
373struct DeserializationHelper<Head, Tail...> {
374  template <typename Result, typename... Deserialized> struct deserialized {
375    static Result doit(Deserializer &deserializer,
376                       Result (*f)(Deserialized..., Head, Tail...),
377                       Deserialized... d) {
378      return DeserializationHelper<Tail...>::
379          template deserialized<Result, Deserialized..., Head>::doit(
380              deserializer, f, d..., deserializer.Deserialize<Head>());
381    }
382  };
383};
384
385template <> struct DeserializationHelper<> {
386  template <typename Result, typename... Deserialized> struct deserialized {
387    static Result doit(Deserializer &deserializer, Result (*f)(Deserialized...),
388                       Deserialized... d) {
389      return f(d...);
390    }
391  };
392};
393
394/// The replayer interface.
395struct Replayer {
396  virtual ~Replayer() {}
397  virtual void operator()(Deserializer &deserializer) const = 0;
398};
399
400/// The default replayer deserializes the arguments and calls the function.
401template <typename Signature> struct DefaultReplayer;
402template <typename Result, typename... Args>
403struct DefaultReplayer<Result(Args...)> : public Replayer {
404  DefaultReplayer(Result (*f)(Args...)) : Replayer(), f(f) {}
405
406  void operator()(Deserializer &deserializer) const override {
407    deserializer.HandleReplayResult(
408        DeserializationHelper<Args...>::template deserialized<Result>::doit(
409            deserializer, f));
410  }
411
412  Result (*f)(Args...);
413};
414
415/// Partial specialization for function returning a void type. It ignores the
416/// (absent) return value.
417template <typename... Args>
418struct DefaultReplayer<void(Args...)> : public Replayer {
419  DefaultReplayer(void (*f)(Args...)) : Replayer(), f(f) {}
420
421  void operator()(Deserializer &deserializer) const override {
422    DeserializationHelper<Args...>::template deserialized<void>::doit(
423        deserializer, f);
424    deserializer.HandleReplayResultVoid();
425  }
426
427  void (*f)(Args...);
428};
429
430/// The registry contains a unique mapping between functions and their ID. The
431/// IDs can be serialized and deserialized to replay a function. Functions need
432/// to be registered with the registry for this to work.
433class Registry {
434private:
435  struct SignatureStr {
436    SignatureStr(llvm::StringRef result = {}, llvm::StringRef scope = {},
437                 llvm::StringRef name = {}, llvm::StringRef args = {})
438        : result(result), scope(scope), name(name), args(args) {}
439
440    std::string ToString() const;
441
442    llvm::StringRef result;
443    llvm::StringRef scope;
444    llvm::StringRef name;
445    llvm::StringRef args;
446  };
447
448public:
449  Registry() = default;
450  virtual ~Registry() = default;
451
452  /// Register a default replayer for a function.
453  template <typename Signature>
454  void Register(Signature *f, llvm::StringRef result = {},
455                llvm::StringRef scope = {}, llvm::StringRef name = {},
456                llvm::StringRef args = {}) {
457    DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(f),
458               SignatureStr(result, scope, name, args));
459  }
460
461  /// Register a replayer that invokes a custom function with the same
462  /// signature as the replayed function.
463  template <typename Signature>
464  void Register(Signature *f, Signature *g, llvm::StringRef result = {},
465                llvm::StringRef scope = {}, llvm::StringRef name = {},
466                llvm::StringRef args = {}) {
467    DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(g),
468               SignatureStr(result, scope, name, args));
469  }
470
471  /// Replay functions from a file.
472  bool Replay(const FileSpec &file);
473
474  /// Replay functions from a buffer.
475  bool Replay(llvm::StringRef buffer);
476
477  /// Returns the ID for a given function address.
478  unsigned GetID(uintptr_t addr);
479
480protected:
481  /// Register the given replayer for a function (and the ID mapping).
482  void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
483                  SignatureStr signature);
484
485private:
486  std::string GetSignature(unsigned id);
487  Replayer *GetReplayer(unsigned id);
488
489  /// Mapping of function addresses to replayers and their ID.
490  std::map<uintptr_t, std::pair<std::unique_ptr<Replayer>, unsigned>>
491      m_replayers;
492
493  /// Mapping of IDs to replayer instances.
494  std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids;
495};
496
497/// To be used as the "Runtime ID" of a constructor. It also invokes the
498/// constructor when called.
499template <typename Signature> struct construct;
500template <typename Class, typename... Args> struct construct<Class(Args...)> {
501  static Class *doit(Args... args) { return new Class(args...); }
502};
503
504/// To be used as the "Runtime ID" of a member function. It also invokes the
505/// member function when called.
506template <typename Signature> struct invoke;
507template <typename Result, typename Class, typename... Args>
508struct invoke<Result (Class::*)(Args...)> {
509  template <Result (Class::*m)(Args...)> struct method {
510    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
511  };
512};
513
514template <typename Result, typename Class, typename... Args>
515struct invoke<Result (Class::*)(Args...) const> {
516  template <Result (Class::*m)(Args...) const> struct method_const {
517    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
518  };
519};
520
521template <typename Class, typename... Args>
522struct invoke<void (Class::*)(Args...)> {
523  template <void (Class::*m)(Args...)> struct method {
524    static void doit(Class *c, Args... args) { (c->*m)(args...); }
525  };
526};
527
528/// Maps an object to an index for serialization. Indices are unique and
529/// incremented for every new object.
530///
531/// Indices start at 1 in order to differentiate with an invalid index (0) in
532/// the serialized buffer.
533class ObjectToIndex {
534public:
535  template <typename T> unsigned GetIndexForObject(T *t) {
536    return GetIndexForObjectImpl(static_cast<const void *>(t));
537  }
538
539private:
540  unsigned GetIndexForObjectImpl(const void *object);
541
542  llvm::DenseMap<const void *, unsigned> m_mapping;
543};
544
545/// Serializes functions, their arguments and their return type to a stream.
546class Serializer {
547public:
548  Serializer(llvm::raw_ostream &stream = llvm::outs()) : m_stream(stream) {}
549
550  /// Recursively serialize all the given arguments.
551  template <typename Head, typename... Tail>
552  void SerializeAll(const Head &head, const Tail &... tail) {
553    Serialize(head);
554    SerializeAll(tail...);
555  }
556
557  void SerializeAll() { m_stream.flush(); }
558
559private:
560  /// Serialize pointers. We need to differentiate between pointers to
561  /// fundamental types (in which case we serialize its value) and pointer to
562  /// objects (in which case we serialize their index).
563  template <typename T> void Serialize(T *t) {
564    if (std::is_fundamental<T>::value) {
565      Serialize(*t);
566    } else {
567      unsigned idx = m_tracker.GetIndexForObject(t);
568      Serialize(idx);
569    }
570  }
571
572  /// Serialize references. We need to differentiate between references to
573  /// fundamental types (in which case we serialize its value) and references
574  /// to objects (in which case we serialize their index).
575  template <typename T> void Serialize(T &t) {
576    if (std::is_fundamental<T>::value) {
577      m_stream.write(reinterpret_cast<const char *>(&t), sizeof(T));
578    } else {
579      unsigned idx = m_tracker.GetIndexForObject(&t);
580      Serialize(idx);
581    }
582  }
583
584  void Serialize(void *v) {
585    // FIXME: Support void*
586    llvm_unreachable("void* is currently unsupported.");
587  }
588
589  void Serialize(const char *t) {
590    m_stream << t;
591    m_stream.write(0x0);
592  }
593
594  /// Serialization stream.
595  llvm::raw_ostream &m_stream;
596
597  /// Mapping of objects to indices.
598  ObjectToIndex m_tracker;
599};
600
601class InstrumentationData {
602public:
603  InstrumentationData() : m_serializer(nullptr), m_registry(nullptr){};
604  InstrumentationData(Serializer &serializer, Registry &registry)
605      : m_serializer(&serializer), m_registry(&registry){};
606
607  Serializer &GetSerializer() { return *m_serializer; }
608  Registry &GetRegistry() { return *m_registry; }
609
610  operator bool() { return m_serializer != nullptr && m_registry != nullptr; }
611
612private:
613  Serializer *m_serializer;
614  Registry *m_registry;
615};
616
617/// RAII object that records function invocations and their return value.
618///
619/// API calls are only captured when the API boundary is crossed. Once we're in
620/// the API layer, and another API function is called, it doesn't need to be
621/// recorded.
622///
623/// When a call is recored, its result is always recorded as well, even if the
624/// function returns a void. For functions that return by value, RecordResult
625/// should be used. Otherwise a sentinel value (0) will be serialized.
626///
627/// Because of the functional overlap between logging and recording API calls,
628/// this class is also used for logging.
629class Recorder {
630public:
631  Recorder(llvm::StringRef pretty_func = {}, std::string &&pretty_args = {});
632  ~Recorder();
633
634  /// Records a single function call.
635  template <typename Result, typename... FArgs, typename... RArgs>
636  void Record(Serializer &serializer, Registry &registry, Result (*f)(FArgs...),
637              const RArgs &... args) {
638    m_serializer = &serializer;
639    if (!ShouldCapture())
640      return;
641
642    unsigned id = registry.GetID(uintptr_t(f));
643
644#ifdef LLDB_REPRO_INSTR_TRACE
645    Log(id);
646#endif
647
648    serializer.SerializeAll(id);
649    serializer.SerializeAll(args...);
650
651    if (std::is_class<typename std::remove_pointer<
652            typename std::remove_reference<Result>::type>::type>::value) {
653      m_result_recorded = false;
654    } else {
655      serializer.SerializeAll(0);
656      m_result_recorded = true;
657    }
658  }
659
660  /// Records a single function call.
661  template <typename... Args>
662  void Record(Serializer &serializer, Registry &registry, void (*f)(Args...),
663              const Args &... args) {
664    m_serializer = &serializer;
665    if (!ShouldCapture())
666      return;
667
668    unsigned id = registry.GetID(uintptr_t(f));
669
670#ifdef LLDB_REPRO_INSTR_TRACE
671    Log(id);
672#endif
673
674    serializer.SerializeAll(id);
675    serializer.SerializeAll(args...);
676
677    // Record result.
678    serializer.SerializeAll(0);
679    m_result_recorded = true;
680  }
681
682  /// Record the result of a function call.
683  template <typename Result> Result RecordResult(Result &&r) {
684    UpdateBoundary();
685    if (m_serializer && ShouldCapture()) {
686      assert(!m_result_recorded);
687      m_serializer->SerializeAll(r);
688      m_result_recorded = true;
689    }
690    return std::forward<Result>(r);
691  }
692
693private:
694  void UpdateBoundary() {
695    if (m_local_boundary)
696      g_global_boundary = false;
697  }
698
699  bool ShouldCapture() { return m_local_boundary; }
700
701#ifdef LLDB_REPRO_INSTR_TRACE
702  void Log(unsigned id) {
703    llvm::errs() << "Recording " << id << ": " << m_pretty_func << " ("
704                 << m_pretty_args << ")\n";
705  }
706#endif
707
708  Serializer *m_serializer;
709
710  /// Pretty function for logging.
711  llvm::StringRef m_pretty_func;
712  std::string m_pretty_args;
713
714  /// Whether this function call was the one crossing the API boundary.
715  bool m_local_boundary;
716
717  /// Whether the return value was recorded explicitly.
718  bool m_result_recorded;
719
720  /// Whether we're currently across the API boundary.
721  static bool g_global_boundary;
722};
723
724} // namespace repro
725} // namespace lldb_private
726
727#endif // LLDB_UTILITY_REPRODUCER_INSTRUMENTATION_H
728