]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/include/lldb/Utility/ReproducerInstrumentation.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / include / lldb / Utility / ReproducerInstrumentation.h
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
23 template <typename T,
24           typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
25 inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
26   ss << t;
27 }
28
29 template <typename T, typename std::enable_if<!std::is_fundamental<T>::value,
30                                               int>::type = 0>
31 inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
32   ss << &t;
33 }
34
35 template <typename T>
36 inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) {
37   ss << reinterpret_cast<const void *>(t);
38 }
39
40 template <>
41 inline void stringify_append<char>(llvm::raw_string_ostream &ss,
42                                    const char *t) {
43   ss << '\"' << t << '\"';
44 }
45
46 template <typename Head>
47 inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) {
48   stringify_append(ss, head);
49 }
50
51 template <typename Head, typename... Tail>
52 inline 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
59 template <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
183 namespace lldb_private {
184 namespace 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.
197 class IndexToObject {
198 public:
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
221 private:
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.
236 struct PointerTag {};
237 struct ReferenceTag {};
238 struct ValueTag {};
239 struct FundamentalPointerTag {};
240 struct FundamentalReferenceTag {};
241 struct NotImplementedTag {};
242
243 /// Return the deserialization tag for the given type T.
244 template <class T> struct serializer_tag {
245   typedef typename std::conditional<std::is_trivially_copyable<T>::value, ValueTag, NotImplementedTag>::type type;
246 };
247 template <class T> struct serializer_tag<T *> {
248   typedef
249       typename std::conditional<std::is_fundamental<T>::value,
250                                 FundamentalPointerTag, PointerTag>::type type;
251 };
252 template <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).
269 class Deserializer {
270 public:
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
309 private:
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.
364 template <> const char *Deserializer::Deserialize<const char *>();
365 template <> 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.
370 template <typename... Remaining> struct DeserializationHelper;
371
372 template <typename Head, typename... Tail>
373 struct 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
385 template <> 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.
395 struct 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.
401 template <typename Signature> struct DefaultReplayer;
402 template <typename Result, typename... Args>
403 struct 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.
417 template <typename... Args>
418 struct 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.
433 class Registry {
434 private:
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
448 public:
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
480 protected:
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
485 private:
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.
499 template <typename Signature> struct construct;
500 template <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.
506 template <typename Signature> struct invoke;
507 template <typename Result, typename Class, typename... Args>
508 struct 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
514 template <typename Result, typename Class, typename... Args>
515 struct 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
521 template <typename Class, typename... Args>
522 struct 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.
533 class ObjectToIndex {
534 public:
535   template <typename T> unsigned GetIndexForObject(T *t) {
536     return GetIndexForObjectImpl(static_cast<const void *>(t));
537   }
538
539 private:
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.
546 class Serializer {
547 public:
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
559 private:
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
601 class InstrumentationData {
602 public:
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
612 private:
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.
629 class Recorder {
630 public:
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
693 private:
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