diff options
Diffstat (limited to 'lldb/source/Utility/ReproducerInstrumentation.cpp')
-rw-r--r-- | lldb/source/Utility/ReproducerInstrumentation.cpp | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/lldb/source/Utility/ReproducerInstrumentation.cpp b/lldb/source/Utility/ReproducerInstrumentation.cpp index 473786ef4d3e3..09aea69d83138 100644 --- a/lldb/source/Utility/ReproducerInstrumentation.cpp +++ b/lldb/source/Utility/ReproducerInstrumentation.cpp @@ -1,4 +1,4 @@ -//===-- ReproducerInstrumentation.cpp ---------------------------*- C++ -*-===// +//===-- ReproducerInstrumentation.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,6 +8,9 @@ #include "lldb/Utility/ReproducerInstrumentation.h" #include "lldb/Utility/Reproducer.h" +#include <stdio.h> +#include <stdlib.h> +#include <thread> using namespace lldb_private; using namespace lldb_private::repro; @@ -21,19 +24,66 @@ void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) { m_mapping[idx] = object; } +std::vector<void *> IndexToObject::GetAllObjects() const { + std::vector<std::pair<unsigned, void *>> pairs; + for (auto &e : m_mapping) { + pairs.emplace_back(e.first, e.second); + } + + // Sort based on index. + std::sort(pairs.begin(), pairs.end(), + [](auto &lhs, auto &rhs) { return lhs.first < rhs.first; }); + + std::vector<void *> objects; + objects.reserve(pairs.size()); + for (auto &p : pairs) { + objects.push_back(p.second); + } + + return objects; +} + +template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>() { + return Deserialize<uint8_t *>(); +} + +template <> void *Deserializer::Deserialize<void *>() { + return const_cast<void *>(Deserialize<const void *>()); +} + +template <> const void *Deserializer::Deserialize<const void *>() { + return nullptr; +} + template <> char *Deserializer::Deserialize<char *>() { return const_cast<char *>(Deserialize<const char *>()); } template <> const char *Deserializer::Deserialize<const char *>() { - auto pos = m_buffer.find('\0'); - if (pos == llvm::StringRef::npos) + const size_t size = Deserialize<size_t>(); + if (size == std::numeric_limits<size_t>::max()) return nullptr; + assert(HasData(size + 1)); const char *str = m_buffer.data(); - m_buffer = m_buffer.drop_front(pos + 1); + m_buffer = m_buffer.drop_front(size + 1); +#ifdef LLDB_REPRO_INSTR_TRACE + llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> \"" + << str << "\"\n"; +#endif return str; } +template <> const char **Deserializer::Deserialize<const char **>() { + const size_t size = Deserialize<size_t>(); + if (size == 0) + return nullptr; + const char **r = + reinterpret_cast<const char **>(calloc(size + 1, sizeof(char *))); + for (size_t i = 0; i < size; ++i) + r[i] = Deserialize<const char *>(); + return r; +} + bool Registry::Replay(const FileSpec &file) { auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); if (auto err = error_or_file.getError()) @@ -43,11 +93,19 @@ bool Registry::Replay(const FileSpec &file) { } bool Registry::Replay(llvm::StringRef buffer) { + Deserializer deserializer(buffer); + return Replay(deserializer); +} + +bool Registry::Replay(Deserializer &deserializer) { #ifndef LLDB_REPRO_INSTR_TRACE Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API); #endif - Deserializer deserializer(buffer); + // Disable buffering stdout so that we approximate the way things get flushed + // during an interactive session. + setvbuf(stdout, nullptr, _IONBF, 0); + while (deserializer.HasData(1)) { unsigned id = deserializer.Deserialize<unsigned>(); @@ -60,6 +118,10 @@ bool Registry::Replay(llvm::StringRef buffer) { GetReplayer(id)->operator()(deserializer); } + // Add a small artificial delay to ensure that all asynchronous events have + // completed before we exit. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + return true; } @@ -83,6 +145,22 @@ std::string Registry::GetSignature(unsigned id) { return m_ids[id].second.ToString(); } +void Registry::CheckID(unsigned expected, unsigned actual) { + if (expected != actual) { + llvm::errs() << "Reproducer expected signature " << expected << ": '" + << GetSignature(expected) << "'\n"; + llvm::errs() << "Reproducer actual signature " << actual << ": '" + << GetSignature(actual) << "'\n"; + llvm::report_fatal_error( + "Detected reproducer replay divergence. Refusing to continue."); + } + +#ifdef LLDB_REPRO_INSTR_TRACE + llvm::errs() << "Replaying " << actual << ": " << GetSignature(actual) + << "\n"; +#endif +} + Replayer *Registry::GetReplayer(unsigned id) { assert(m_ids.count(id) != 0 && "ID not in registry"); return m_ids[id].first; @@ -101,6 +179,15 @@ unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) { return m_mapping[object]; } +Recorder::Recorder() + : m_serializer(nullptr), m_pretty_func(), m_pretty_args(), + m_local_boundary(false), m_result_recorded(true) { + if (!g_global_boundary) { + g_global_boundary = true; + m_local_boundary = true; + } +} + Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args) : m_serializer(nullptr), m_pretty_func(pretty_func), m_pretty_args(pretty_args), m_local_boundary(false), @@ -119,4 +206,25 @@ Recorder::~Recorder() { UpdateBoundary(); } +void InstrumentationData::Initialize(Serializer &serializer, + Registry ®istry) { + InstanceImpl().emplace(serializer, registry); +} + +void InstrumentationData::Initialize(Deserializer &deserializer, + Registry ®istry) { + InstanceImpl().emplace(deserializer, registry); +} + +InstrumentationData &InstrumentationData::Instance() { + if (!InstanceImpl()) + InstanceImpl().emplace(); + return *InstanceImpl(); +} + +llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() { + static llvm::Optional<InstrumentationData> g_instrumentation_data; + return g_instrumentation_data; +} + bool lldb_private::repro::Recorder::g_global_boundary; |