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