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 ®istry) 605 : m_serializer(&serializer), m_registry(®istry){}; 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 ®istry, 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 ®istry, 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