003 File Manager
Current Path:
/usr/src/contrib/llvm-project/lldb/include/lldb/Utility
usr
/
src
/
contrib
/
llvm-project
/
lldb
/
include
/
lldb
/
Utility
/
📁
..
📄
AnsiTerminal.h
(4.97 KB)
📄
ArchSpec.h
(17.08 KB)
📄
Args.h
(13.72 KB)
📄
Baton.h
(2.25 KB)
📄
Broadcaster.h
(17.55 KB)
📄
CompletionRequest.h
(9.23 KB)
📄
Connection.h
(6.42 KB)
📄
ConstString.h
(17.92 KB)
📄
DataBuffer.h
(3.39 KB)
📄
DataBufferHeap.h
(3.65 KB)
📄
DataBufferLLVM.h
(1.17 KB)
📄
DataEncoder.h
(8.45 KB)
📄
DataExtractor.h
(39.18 KB)
📄
Endian.h
(865 B)
📄
Environment.h
(2.68 KB)
📄
Event.h
(6.64 KB)
📄
FileSpec.h
(15.41 KB)
📄
Flags.h
(3.39 KB)
📄
GDBRemote.h
(4.15 KB)
📄
IOObject.h
(1.38 KB)
📄
Iterable.h
(5.5 KB)
📄
LLDBAssert.h
(911 B)
📄
Listener.h
(5.2 KB)
📄
Log.h
(10.51 KB)
📄
Logging.h
(2.27 KB)
📄
NameMatches.h
(716 B)
📄
Predicate.h
(8.08 KB)
📄
ProcessInfo.h
(7.92 KB)
📄
RangeMap.h
(23.05 KB)
📄
RegisterValue.h
(7.08 KB)
📄
RegularExpression.h
(3.2 KB)
📄
Reproducer.h
(13.25 KB)
📄
ReproducerInstrumentation.h
(39.38 KB)
📄
Scalar.h
(11.27 KB)
📄
SelectHelper.h
(2.53 KB)
📄
SharedCluster.h
(1.69 KB)
📄
State.h
(2.54 KB)
📄
Status.h
(7.31 KB)
📄
Stream.h
(14.34 KB)
📄
StreamCallback.h
(978 B)
📄
StreamString.h
(1.23 KB)
📄
StreamTee.h
(4.52 KB)
📄
StringExtractor.h
(3.13 KB)
📄
StringExtractorGDBRemote.h
(6.12 KB)
📄
StringLexer.h
(1.31 KB)
📄
StringList.h
(3.47 KB)
📄
StructuredData.h
(15.49 KB)
📄
TildeExpressionResolver.h
(2.42 KB)
📄
Timeout.h
(2.45 KB)
📄
Timer.h
(1.87 KB)
📄
TraceOptions.h
(1.79 KB)
📄
UUID.h
(3.74 KB)
📄
UriParser.h
(1.01 KB)
📄
UserID.h
(2.8 KB)
📄
UserIDResolver.h
(1.8 KB)
📄
VASPrintf.h
(636 B)
📄
VMRange.h
(3.06 KB)
📄
XcodeSDK.h
(2.85 KB)
Editing: ReproducerInstrumentation.h
//===-- ReproducerInstrumentation.h -----------------------------*- C++ -*-===// // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H #define LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include <map> #include <type_traits> template <typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0> inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) { ss << t; } template <typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0> inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) { ss << &t; } template <typename T> inline void stringify_append(llvm::raw_string_ostream &ss, T *t) { ss << reinterpret_cast<void *>(t); } template <typename T> inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) { ss << reinterpret_cast<const void *>(t); } template <> inline void stringify_append<char>(llvm::raw_string_ostream &ss, const char *t) { ss << '\"' << t << '\"'; } template <> inline void stringify_append<std::nullptr_t>(llvm::raw_string_ostream &ss, const std::nullptr_t &t) { ss << "\"nullptr\""; } template <typename Head> inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) { stringify_append(ss, head); } template <typename Head, typename... Tail> inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head, const Tail &... tail) { stringify_append(ss, head); ss << ", "; stringify_helper(ss, tail...); } template <typename... Ts> inline std::string stringify_args(const Ts &... ts) { std::string buffer; llvm::raw_string_ostream ss(buffer); stringify_helper(ss, ts...); return ss.str(); } // Define LLDB_REPRO_INSTR_TRACE to trace to stderr instead of LLDB's log // infrastructure. This is useful when you need to see traces before the logger // is initialized or enabled. // #define LLDB_REPRO_INSTR_TRACE #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \ R.Register<Class * Signature>(&construct<Class Signature>::record, "", \ #Class, #Class, #Signature) #define LLDB_REGISTER_METHOD(Result, Class, Method, Signature) \ R.Register( \ &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::record, \ #Result, #Class, #Method, #Signature) #define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature) \ R.Register(&invoke<Result(Class::*) \ Signature const>::method<(&Class::Method)>::record, \ #Result, #Class, #Method, #Signature) #define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature) \ R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::record, \ #Result, #Class, #Method, #Signature) #define LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(Result, Class, Method) \ R.Register( \ &invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::record, \ &invoke_char_ptr<Result (*)(char *, \ size_t)>::method<(&Class::Method)>::record, \ #Result, #Class, #Method, "(char*, size_t"); #define LLDB_REGISTER_CHAR_PTR_METHOD(Result, Class, Method) \ R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<( \ &Class::Method)>::record, \ &invoke_char_ptr<Result (Class::*)(char *, size_t)>::method<( \ &Class::Method)>::record, \ #Result, #Class, #Method, "(char*, size_t"); #define LLDB_REGISTER_CHAR_PTR_METHOD_CONST(Result, Class, Method) \ R.Register(&invoke<Result (Class::*)(char *, size_t) \ const>::method<(&Class::Method)>::record, \ &invoke_char_ptr<Result (Class::*)(char *, size_t) \ const>::method<(&Class::Method)>::record, \ #Result, #Class, #Method, "(char*, size_t"); #define LLDB_CONSTRUCT_(T, Class, ...) \ lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION); \ lldb_private::repro::construct<T>::handle(LLDB_GET_INSTRUMENTATION_DATA(), \ _recorder, Class, __VA_ARGS__); #define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...) \ LLDB_CONSTRUCT_(Class Signature, this, __VA_ARGS__) #define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class) \ LLDB_CONSTRUCT_(Class(), this, lldb_private::repro::EmptyArg()) #define LLDB_RECORD_(T1, T2, ...) \ lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \ stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData _data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ if (lldb_private::repro::Serializer *_serializer = \ _data.GetSerializer()) { \ _recorder.Record(*_serializer, _data.GetRegistry(), \ &lldb_private::repro::invoke<T1>::method<T2>::record, \ __VA_ARGS__); \ } else if (lldb_private::repro::Deserializer *_deserializer = \ _data.GetDeserializer()) { \ if (_recorder.ShouldCapture()) { \ return lldb_private::repro::invoke<T1>::method<T2>::replay( \ _recorder, *_deserializer, _data.GetRegistry()); \ } \ } \ } #define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...) \ LLDB_RECORD_(Result(Class::*) Signature, (&Class::Method), this, __VA_ARGS__) #define LLDB_RECORD_METHOD_CONST(Result, Class, Method, Signature, ...) \ LLDB_RECORD_(Result(Class::*) Signature const, (&Class::Method), this, \ __VA_ARGS__) #define LLDB_RECORD_METHOD_NO_ARGS(Result, Class, Method) \ LLDB_RECORD_(Result (Class::*)(), (&Class::Method), this) #define LLDB_RECORD_METHOD_CONST_NO_ARGS(Result, Class, Method) \ LLDB_RECORD_(Result (Class::*)() const, (&Class::Method), this) #define LLDB_RECORD_STATIC_METHOD(Result, Class, Method, Signature, ...) \ LLDB_RECORD_(Result(*) Signature, (&Class::Method), __VA_ARGS__) #define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method) \ LLDB_RECORD_(Result (*)(), (&Class::Method), lldb_private::repro::EmptyArg()) #define LLDB_RECORD_CHAR_PTR_(T1, T2, StrOut, ...) \ lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \ stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData _data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ if (lldb_private::repro::Serializer *_serializer = \ _data.GetSerializer()) { \ _recorder.Record(*_serializer, _data.GetRegistry(), \ &lldb_private::repro::invoke<T1>::method<(T2)>::record, \ __VA_ARGS__); \ } else if (lldb_private::repro::Deserializer *_deserializer = \ _data.GetDeserializer()) { \ if (_recorder.ShouldCapture()) { \ return lldb_private::repro::invoke_char_ptr<T1>::method<T2>::replay( \ _recorder, *_deserializer, _data.GetRegistry(), StrOut); \ } \ } \ } #define LLDB_RECORD_CHAR_PTR_METHOD(Result, Class, Method, Signature, StrOut, \ ...) \ LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature, (&Class::Method), StrOut, \ this, __VA_ARGS__) #define LLDB_RECORD_CHAR_PTR_METHOD_CONST(Result, Class, Method, Signature, \ StrOut, ...) \ LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature const, (&Class::Method), \ StrOut, this, __VA_ARGS__) #define LLDB_RECORD_CHAR_PTR_STATIC_METHOD(Result, Class, Method, Signature, \ StrOut, ...) \ LLDB_RECORD_CHAR_PTR_(Result(*) Signature, (&Class::Method), StrOut, \ __VA_ARGS__) #define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true); /// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record /// anything. It's used to track API boundaries when we cannot record for /// technical reasons. #define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...) \ lldb_private::repro::Recorder _recorder; #define LLDB_RECORD_DUMMY_NO_ARGS(Result, Class, Method) \ lldb_private::repro::Recorder _recorder; namespace lldb_private { namespace repro { template <class T> struct is_trivially_serializable : std::integral_constant<bool, std::is_fundamental<T>::value || std::is_enum<T>::value> {}; /// Mapping between serialized indices and their corresponding objects. /// /// This class is used during replay to map indices back to in-memory objects. /// /// When objects are constructed, they are added to this mapping using /// AddObjectForIndex. /// /// When an object is passed to a function, its index is deserialized and /// AddObjectForIndex returns the corresponding object. If there is no object /// for the given index, a nullptr is returend. The latter is valid when custom /// replay code is in place and the actual object is ignored. class IndexToObject { public: /// Returns an object as a pointer for the given index or nullptr if not /// present in the map. template <typename T> T *GetObjectForIndex(unsigned idx) { assert(idx != 0 && "Cannot get object for sentinel"); void *object = GetObjectForIndexImpl(idx); return static_cast<T *>(object); } /// Adds a pointer to an object to the mapping for the given index. template <typename T> T *AddObjectForIndex(unsigned idx, T *object) { AddObjectForIndexImpl( idx, static_cast<void *>( const_cast<typename std::remove_const<T>::type *>(object))); return object; } /// Adds a reference to an object to the mapping for the given index. template <typename T> T &AddObjectForIndex(unsigned idx, T &object) { AddObjectForIndexImpl( idx, static_cast<void *>( const_cast<typename std::remove_const<T>::type *>(&object))); return object; } /// Get all objects sorted by their index. std::vector<void *> GetAllObjects() const; private: /// Helper method that does the actual lookup. The void* result is later cast /// by the caller. void *GetObjectForIndexImpl(unsigned idx); /// Helper method that does the actual insertion. void AddObjectForIndexImpl(unsigned idx, void *object); /// Keeps a mapping between indices and their corresponding object. llvm::DenseMap<unsigned, void *> m_mapping; }; /// We need to differentiate between pointers to fundamental and /// non-fundamental types. See the corresponding Deserializer::Read method /// for the reason why. struct PointerTag {}; struct ReferenceTag {}; struct ValueTag {}; struct FundamentalPointerTag {}; struct FundamentalReferenceTag {}; /// Return the deserialization tag for the given type T. template <class T> struct serializer_tag { typedef typename std::conditional<std::is_trivially_copyable<T>::value, ValueTag, ReferenceTag>::type type; }; template <class T> struct serializer_tag<T *> { typedef typename std::conditional<std::is_fundamental<T>::value, FundamentalPointerTag, PointerTag>::type type; }; template <class T> struct serializer_tag<T &> { typedef typename std::conditional<std::is_fundamental<T>::value, FundamentalReferenceTag, ReferenceTag>::type type; }; /// Deserializes data from a buffer. It is used to deserialize function indices /// to replay, their arguments and return values. /// /// Fundamental types and strings are read by value. Objects are read by their /// index, which get translated by the IndexToObject mapping maintained in /// this class. /// /// Additional bookkeeping with regards to the IndexToObject is required to /// deserialize objects. When a constructor is run or an object is returned by /// value, we need to capture the object and add it to the index together with /// its index. This is the job of HandleReplayResult(Void). class Deserializer { public: Deserializer(llvm::StringRef buffer) : m_buffer(buffer) {} /// Returns true when the buffer has unread data. bool HasData(unsigned size) { return size <= m_buffer.size(); } /// Deserialize and interpret value as T. template <typename T> T Deserialize() { T t = Read<T>(typename serializer_tag<T>::type()); #ifdef LLDB_REPRO_INSTR_TRACE llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> " << stringify_args(t) << "\n"; #endif return t; } template <typename T> const T &HandleReplayResult(const T &t) { unsigned result = Deserialize<unsigned>(); if (is_trivially_serializable<T>::value) return t; // We need to make a copy as the original object might go out of scope. return *m_index_to_object.AddObjectForIndex(result, new T(t)); } /// Store the returned value in the index-to-object mapping. template <typename T> T &HandleReplayResult(T &t) { unsigned result = Deserialize<unsigned>(); if (is_trivially_serializable<T>::value) return t; // We need to make a copy as the original object might go out of scope. return *m_index_to_object.AddObjectForIndex(result, new T(t)); } /// Store the returned value in the index-to-object mapping. template <typename T> T *HandleReplayResult(T *t) { unsigned result = Deserialize<unsigned>(); if (is_trivially_serializable<T>::value) return t; return m_index_to_object.AddObjectForIndex(result, t); } /// All returned types are recorded, even when the function returns a void. /// The latter requires special handling. void HandleReplayResultVoid() { unsigned result = Deserialize<unsigned>(); assert(result == 0); (void)result; } std::vector<void *> GetAllObjects() const { return m_index_to_object.GetAllObjects(); } private: template <typename T> T Read(ValueTag) { assert(HasData(sizeof(T))); T t; std::memcpy(reinterpret_cast<char *>(&t), m_buffer.data(), sizeof(T)); m_buffer = m_buffer.drop_front(sizeof(T)); return t; } template <typename T> T Read(PointerTag) { typedef typename std::remove_pointer<T>::type UnderlyingT; return m_index_to_object.template GetObjectForIndex<UnderlyingT>( Deserialize<unsigned>()); } template <typename T> T Read(ReferenceTag) { typedef typename std::remove_reference<T>::type UnderlyingT; // If this is a reference to a fundamental type we just read its value. return *m_index_to_object.template GetObjectForIndex<UnderlyingT>( Deserialize<unsigned>()); } /// This method is used to parse references to fundamental types. Because /// they're not recorded in the object table we have serialized their value. /// We read its value, allocate a copy on the heap, and return a pointer to /// the copy. template <typename T> T Read(FundamentalPointerTag) { typedef typename std::remove_pointer<T>::type UnderlyingT; return new UnderlyingT(Deserialize<UnderlyingT>()); } /// This method is used to parse references to fundamental types. Because /// they're not recorded in the object table we have serialized their value. /// We read its value, allocate a copy on the heap, and return a reference to /// the copy. template <typename T> T Read(FundamentalReferenceTag) { // If this is a reference to a fundamental type we just read its value. typedef typename std::remove_reference<T>::type UnderlyingT; return *(new UnderlyingT(Deserialize<UnderlyingT>())); } /// Mapping of indices to objects. IndexToObject m_index_to_object; /// Buffer containing the serialized data. llvm::StringRef m_buffer; }; /// Partial specialization for C-style strings. We read the string value /// instead of treating it as pointer. template <> const char *Deserializer::Deserialize<const char *>(); template <> const char **Deserializer::Deserialize<const char **>(); template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>(); template <> const void *Deserializer::Deserialize<const void *>(); template <> char *Deserializer::Deserialize<char *>(); template <> void *Deserializer::Deserialize<void *>(); /// Helpers to auto-synthesize function replay code. It deserializes the replay /// function's arguments one by one and finally calls the corresponding /// function. template <typename... Remaining> struct DeserializationHelper; template <typename Head, typename... Tail> struct DeserializationHelper<Head, Tail...> { template <typename Result, typename... Deserialized> struct deserialized { static Result doit(Deserializer &deserializer, Result (*f)(Deserialized..., Head, Tail...), Deserialized... d) { return DeserializationHelper<Tail...>:: template deserialized<Result, Deserialized..., Head>::doit( deserializer, f, d..., deserializer.Deserialize<Head>()); } }; }; template <> struct DeserializationHelper<> { template <typename Result, typename... Deserialized> struct deserialized { static Result doit(Deserializer &deserializer, Result (*f)(Deserialized...), Deserialized... d) { return f(d...); } }; }; /// The replayer interface. struct Replayer { virtual ~Replayer() {} virtual void operator()(Deserializer &deserializer) const = 0; }; /// The default replayer deserializes the arguments and calls the function. template <typename Signature> struct DefaultReplayer; template <typename Result, typename... Args> struct DefaultReplayer<Result(Args...)> : public Replayer { DefaultReplayer(Result (*f)(Args...)) : Replayer(), f(f) {} void operator()(Deserializer &deserializer) const override { Replay(deserializer); } Result Replay(Deserializer &deserializer) const { return deserializer.HandleReplayResult( DeserializationHelper<Args...>::template deserialized<Result>::doit( deserializer, f)); } Result (*f)(Args...); }; /// Partial specialization for function returning a void type. It ignores the /// (absent) return value. template <typename... Args> struct DefaultReplayer<void(Args...)> : public Replayer { DefaultReplayer(void (*f)(Args...)) : Replayer(), f(f) {} void operator()(Deserializer &deserializer) const override { Replay(deserializer); } void Replay(Deserializer &deserializer) const { DeserializationHelper<Args...>::template deserialized<void>::doit( deserializer, f); deserializer.HandleReplayResultVoid(); } void (*f)(Args...); }; /// The registry contains a unique mapping between functions and their ID. The /// IDs can be serialized and deserialized to replay a function. Functions need /// to be registered with the registry for this to work. class Registry { private: struct SignatureStr { SignatureStr(llvm::StringRef result = {}, llvm::StringRef scope = {}, llvm::StringRef name = {}, llvm::StringRef args = {}) : result(result), scope(scope), name(name), args(args) {} std::string ToString() const; llvm::StringRef result; llvm::StringRef scope; llvm::StringRef name; llvm::StringRef args; }; public: Registry() = default; virtual ~Registry() = default; /// Register a default replayer for a function. template <typename Signature> void Register(Signature *f, llvm::StringRef result = {}, llvm::StringRef scope = {}, llvm::StringRef name = {}, llvm::StringRef args = {}) { DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(f), SignatureStr(result, scope, name, args)); } /// Register a replayer that invokes a custom function with the same /// signature as the replayed function. template <typename Signature> void Register(Signature *f, Signature *g, llvm::StringRef result = {}, llvm::StringRef scope = {}, llvm::StringRef name = {}, llvm::StringRef args = {}) { DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(g), SignatureStr(result, scope, name, args)); } /// Replay functions from a file. bool Replay(const FileSpec &file); /// Replay functions from a buffer. bool Replay(llvm::StringRef buffer); /// Replay functions from a deserializer. bool Replay(Deserializer &deserializer); /// Returns the ID for a given function address. unsigned GetID(uintptr_t addr); /// Get the replayer matching the given ID. Replayer *GetReplayer(unsigned id); std::string GetSignature(unsigned id); void CheckID(unsigned expected, unsigned actual); protected: /// Register the given replayer for a function (and the ID mapping). void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer, SignatureStr signature); private: /// Mapping of function addresses to replayers and their ID. std::map<uintptr_t, std::pair<std::unique_ptr<Replayer>, unsigned>> m_replayers; /// Mapping of IDs to replayer instances. std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids; }; /// Maps an object to an index for serialization. Indices are unique and /// incremented for every new object. /// /// Indices start at 1 in order to differentiate with an invalid index (0) in /// the serialized buffer. class ObjectToIndex { public: template <typename T> unsigned GetIndexForObject(T *t) { return GetIndexForObjectImpl(static_cast<const void *>(t)); } private: unsigned GetIndexForObjectImpl(const void *object); llvm::DenseMap<const void *, unsigned> m_mapping; }; /// Serializes functions, their arguments and their return type to a stream. class Serializer { public: Serializer(llvm::raw_ostream &stream = llvm::outs()) : m_stream(stream) {} /// Recursively serialize all the given arguments. template <typename Head, typename... Tail> void SerializeAll(const Head &head, const Tail &... tail) { Serialize(head); SerializeAll(tail...); } void SerializeAll() { m_stream.flush(); } private: /// Serialize pointers. We need to differentiate between pointers to /// fundamental types (in which case we serialize its value) and pointer to /// objects (in which case we serialize their index). template <typename T> void Serialize(T *t) { #ifdef LLDB_REPRO_INSTR_TRACE llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " << stringify_args(t) << "\n"; #endif if (std::is_fundamental<T>::value) { Serialize(*t); } else { unsigned idx = m_tracker.GetIndexForObject(t); Serialize(idx); } } /// Serialize references. We need to differentiate between references to /// fundamental types (in which case we serialize its value) and references /// to objects (in which case we serialize their index). template <typename T> void Serialize(T &t) { #ifdef LLDB_REPRO_INSTR_TRACE llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " << stringify_args(t) << "\n"; #endif if (is_trivially_serializable<T>::value) { m_stream.write(reinterpret_cast<const char *>(&t), sizeof(T)); } else { unsigned idx = m_tracker.GetIndexForObject(&t); Serialize(idx); } } void Serialize(const void *v) { // FIXME: Support void* } void Serialize(void *v) { // FIXME: Support void* } void Serialize(const char *t) { #ifdef LLDB_REPRO_INSTR_TRACE llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " << stringify_args(t) << "\n"; #endif const size_t size = t ? strlen(t) : std::numeric_limits<size_t>::max(); Serialize(size); if (t) { m_stream << t; m_stream.write(0x0); } } void Serialize(const char **t) { size_t size = 0; if (!t) { Serialize(size); return; } // Compute the size of the array. const char *const *temp = t; while (*temp++) size++; Serialize(size); // Serialize the content of the array. while (*t) Serialize(*t++); } /// Serialization stream. llvm::raw_ostream &m_stream; /// Mapping of objects to indices. ObjectToIndex m_tracker; }; // namespace repro class InstrumentationData { public: Serializer *GetSerializer() { return m_serializer; } Deserializer *GetDeserializer() { return m_deserializer; } Registry &GetRegistry() { return *m_registry; } operator bool() { return (m_serializer != nullptr || m_deserializer != nullptr) && m_registry != nullptr; } static void Initialize(Serializer &serializer, Registry ®istry); static void Initialize(Deserializer &serializer, Registry ®istry); static InstrumentationData &Instance(); protected: friend llvm::optional_detail::OptionalStorage<InstrumentationData, true>; friend llvm::Optional<InstrumentationData>; InstrumentationData() : m_serializer(nullptr), m_deserializer(nullptr), m_registry(nullptr) {} InstrumentationData(Serializer &serializer, Registry ®istry) : m_serializer(&serializer), m_deserializer(nullptr), m_registry(®istry) {} InstrumentationData(Deserializer &deserializer, Registry ®istry) : m_serializer(nullptr), m_deserializer(&deserializer), m_registry(®istry) {} private: static llvm::Optional<InstrumentationData> &InstanceImpl(); Serializer *m_serializer; Deserializer *m_deserializer; Registry *m_registry; }; struct EmptyArg {}; /// RAII object that records function invocations and their return value. /// /// API calls are only captured when the API boundary is crossed. Once we're in /// the API layer, and another API function is called, it doesn't need to be /// recorded. /// /// When a call is recored, its result is always recorded as well, even if the /// function returns a void. For functions that return by value, RecordResult /// should be used. Otherwise a sentinel value (0) will be serialized. /// /// Because of the functional overlap between logging and recording API calls, /// this class is also used for logging. class Recorder { public: Recorder(); Recorder(llvm::StringRef pretty_func, std::string &&pretty_args = {}); ~Recorder(); /// Records a single function call. template <typename Result, typename... FArgs, typename... RArgs> void Record(Serializer &serializer, Registry ®istry, Result (*f)(FArgs...), const RArgs &... args) { m_serializer = &serializer; if (!ShouldCapture()) return; unsigned id = registry.GetID(uintptr_t(f)); #ifdef LLDB_REPRO_INSTR_TRACE Log(id); #endif serializer.SerializeAll(id); serializer.SerializeAll(args...); if (std::is_class<typename std::remove_pointer< typename std::remove_reference<Result>::type>::type>::value) { m_result_recorded = false; } else { serializer.SerializeAll(0); m_result_recorded = true; } } /// Records a single function call. template <typename... Args> void Record(Serializer &serializer, Registry ®istry, void (*f)(Args...), const Args &... args) { m_serializer = &serializer; if (!ShouldCapture()) return; unsigned id = registry.GetID(uintptr_t(f)); #ifdef LLDB_REPRO_INSTR_TRACE Log(id); #endif serializer.SerializeAll(id); serializer.SerializeAll(args...); // Record result. serializer.SerializeAll(0); m_result_recorded = true; } /// Specializations for the no-argument methods. These are passed an empty /// dummy argument so the same variadic macro can be used. These methods /// strip the arguments before forwarding them. template <typename Result> void Record(Serializer &serializer, Registry ®istry, Result (*f)(), const EmptyArg &arg) { Record(serializer, registry, f); } /// Record the result of a function call. template <typename Result> Result RecordResult(Result &&r, bool update_boundary) { // When recording the result from the LLDB_RECORD_RESULT macro, we need to // update the boundary so we capture the copy constructor. However, when // called to record the this pointer of the (copy) constructor, the // boundary should not be toggled, because it is called from the // LLDB_RECORD_CONSTRUCTOR macro, which might be followed by other API // calls. if (update_boundary) UpdateBoundary(); if (m_serializer && ShouldCapture()) { assert(!m_result_recorded); m_serializer->SerializeAll(r); m_result_recorded = true; } return std::forward<Result>(r); } template <typename Result, typename T> Result Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr, bool update_boundary) { unsigned actual_id = registry.GetID(addr); unsigned id = deserializer.Deserialize<unsigned>(); registry.CheckID(id, actual_id); return ReplayResult<Result>( static_cast<DefaultReplayer<T> *>(registry.GetReplayer(id)) ->Replay(deserializer), update_boundary); } void Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr) { unsigned actual_id = registry.GetID(addr); unsigned id = deserializer.Deserialize<unsigned>(); registry.CheckID(id, actual_id); registry.GetReplayer(id)->operator()(deserializer); } template <typename Result> Result ReplayResult(Result &&r, bool update_boundary) { if (update_boundary) UpdateBoundary(); return std::forward<Result>(r); } bool ShouldCapture() { return m_local_boundary; } private: template <typename T> friend struct replay; void UpdateBoundary() { if (m_local_boundary) g_global_boundary = false; } #ifdef LLDB_REPRO_INSTR_TRACE void Log(unsigned id) { llvm::errs() << "Recording " << id << ": " << m_pretty_func << " (" << m_pretty_args << ")\n"; } #endif Serializer *m_serializer; /// Pretty function for logging. llvm::StringRef m_pretty_func; std::string m_pretty_args; /// Whether this function call was the one crossing the API boundary. bool m_local_boundary; /// Whether the return value was recorded explicitly. bool m_result_recorded; /// Whether we're currently across the API boundary. static bool g_global_boundary; }; /// To be used as the "Runtime ID" of a constructor. It also invokes the /// constructor when called. template <typename Signature> struct construct; template <typename Class, typename... Args> struct construct<Class(Args...)> { static Class *handle(lldb_private::repro::InstrumentationData data, lldb_private::repro::Recorder &recorder, Class *c, const EmptyArg &) { return handle(data, recorder, c); } static Class *handle(lldb_private::repro::InstrumentationData data, lldb_private::repro::Recorder &recorder, Class *c, Args... args) { if (!data) return nullptr; if (Serializer *serializer = data.GetSerializer()) { recorder.Record(*serializer, data.GetRegistry(), &record, args...); recorder.RecordResult(c, false); } else if (Deserializer *deserializer = data.GetDeserializer()) { if (recorder.ShouldCapture()) { replay(recorder, *deserializer, data.GetRegistry()); } } return nullptr; } static Class *record(Args... args) { return new Class(args...); } static Class *replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { return recorder.Replay<Class *, Class *(Args...)>( deserializer, registry, uintptr_t(&record), false); } }; /// To be used as the "Runtime ID" of a member function. It also invokes the /// member function when called. template <typename Signature> struct invoke; template <typename Result, typename Class, typename... Args> struct invoke<Result (Class::*)(Args...)> { template <Result (Class::*m)(Args...)> struct method { static Result record(Class *c, Args... args) { return (c->*m)(args...); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { return recorder.Replay<Result, Result(Class *, Args...)>( deserializer, registry, uintptr_t(&record), true); } }; }; template <typename Class, typename... Args> struct invoke<void (Class::*)(Args...)> { template <void (Class::*m)(Args...)> struct method { static void record(Class *c, Args... args) { (c->*m)(args...); } static void replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { recorder.Replay(deserializer, registry, uintptr_t(&record)); } }; }; template <typename Result, typename Class, typename... Args> struct invoke<Result (Class::*)(Args...) const> { template <Result (Class::*m)(Args...) const> struct method { static Result record(Class *c, Args... args) { return (c->*m)(args...); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { return recorder.Replay<Result, Result(Class *, Args...)>( deserializer, registry, uintptr_t(&record), true); } }; }; template <typename Class, typename... Args> struct invoke<void (Class::*)(Args...) const> { template <void (Class::*m)(Args...) const> struct method { static void record(Class *c, Args... args) { return (c->*m)(args...); } static void replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { recorder.Replay(deserializer, registry, uintptr_t(&record)); } }; }; template <typename Signature> struct replay; template <typename Result, typename Class, typename... Args> struct replay<Result (Class::*)(Args...)> { template <Result (Class::*m)(Args...)> struct method {}; }; template <typename Result, typename... Args> struct invoke<Result (*)(Args...)> { template <Result (*m)(Args...)> struct method { static Result record(Args... args) { return (*m)(args...); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { return recorder.Replay<Result, Result(Args...)>(deserializer, registry, uintptr_t(&record), true); } }; }; template <typename... Args> struct invoke<void (*)(Args...)> { template <void (*m)(Args...)> struct method { static void record(Args... args) { return (*m)(args...); } static void replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry) { recorder.Replay(deserializer, registry, uintptr_t(&record)); } }; }; /// Special handling for functions returning strings as (char*, size_t). /// { /// For inline replay, we ignore the arguments and use the ones from the /// serializer instead. This doesn't work for methods that use a char* and a /// size to return a string. For one these functions have a custom replayer to /// prevent override the input buffer. Furthermore, the template-generated /// deserialization is not easy to hook into. /// /// The specializations below hand-implement the serialization logic for the /// inline replay. Instead of using the function from the registry, it uses the /// one passed into the macro. template <typename Signature> struct invoke_char_ptr; template <typename Result, typename Class, typename... Args> struct invoke_char_ptr<Result (Class::*)(Args...) const> { template <Result (Class::*m)(Args...) const> struct method { static Result record(Class *c, char *s, size_t l) { char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char))); return (c->*m)(buffer, l); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { deserializer.Deserialize<unsigned>(); Class *c = deserializer.Deserialize<Class *>(); deserializer.Deserialize<const char *>(); size_t l = deserializer.Deserialize<size_t>(); return recorder.ReplayResult( std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true); } }; }; template <typename Signature> struct invoke_char_ptr; template <typename Result, typename Class, typename... Args> struct invoke_char_ptr<Result (Class::*)(Args...)> { template <Result (Class::*m)(Args...)> struct method { static Result record(Class *c, char *s, size_t l) { char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char))); return (c->*m)(buffer, l); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { deserializer.Deserialize<unsigned>(); Class *c = deserializer.Deserialize<Class *>(); deserializer.Deserialize<const char *>(); size_t l = deserializer.Deserialize<size_t>(); return recorder.ReplayResult( std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true); } }; }; template <typename Result, typename... Args> struct invoke_char_ptr<Result (*)(Args...)> { template <Result (*m)(Args...)> struct method { static Result record(char *s, size_t l) { char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char))); return (*m)(buffer, l); } static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { deserializer.Deserialize<unsigned>(); deserializer.Deserialize<const char *>(); size_t l = deserializer.Deserialize<size_t>(); return recorder.ReplayResult( std::move(deserializer.HandleReplayResult((*m)(str, l))), true); } }; }; /// } } // namespace repro } // namespace lldb_private #endif // LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H
Upload File
Create Folder