Skip to content

🍒/bastille/33e3b07af3ce9595f49c75a8af559bdec5cc19fa+5861234e72c035ad39b5fd843eef78ab4039351e+ac25e8628c443cddd841c6c91d1c9e23e88969e5 #2220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 62 additions & 9 deletions lldb/include/lldb/Utility/ReproducerInstrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/Support/ErrorHandling.h"

#include <map>
#include <thread>
#include <type_traits>

template <typename T,
Expand Down Expand Up @@ -78,6 +79,13 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
// is initialized or enabled.
// #define LLDB_REPRO_INSTR_TRACE

#ifdef LLDB_REPRO_INSTR_TRACE
inline llvm::raw_ostream &this_thread_id() {
size_t tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
return llvm::errs().write_hex(tid) << " :: ";
}
#endif

#define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \
R.Register<Class * Signature>(&construct<Class Signature>::record, "", \
#Class, #Class, #Signature)
Expand Down Expand Up @@ -325,6 +333,7 @@ class Deserializer {
}

template <typename T> const T &HandleReplayResult(const T &t) {
CheckSequence(Deserialize<unsigned>());
unsigned result = Deserialize<unsigned>();
if (is_trivially_serializable<T>::value)
return t;
Expand All @@ -334,6 +343,7 @@ class Deserializer {

/// Store the returned value in the index-to-object mapping.
template <typename T> T &HandleReplayResult(T &t) {
CheckSequence(Deserialize<unsigned>());
unsigned result = Deserialize<unsigned>();
if (is_trivially_serializable<T>::value)
return t;
Expand All @@ -343,6 +353,7 @@ class Deserializer {

/// Store the returned value in the index-to-object mapping.
template <typename T> T *HandleReplayResult(T *t) {
CheckSequence(Deserialize<unsigned>());
unsigned result = Deserialize<unsigned>();
if (is_trivially_serializable<T>::value)
return t;
Expand All @@ -352,6 +363,7 @@ class Deserializer {
/// All returned types are recorded, even when the function returns a void.
/// The latter requires special handling.
void HandleReplayResultVoid() {
CheckSequence(Deserialize<unsigned>());
unsigned result = Deserialize<unsigned>();
assert(result == 0);
(void)result;
Expand All @@ -361,6 +373,10 @@ class Deserializer {
return m_index_to_object.GetAllObjects();
}

void SetExpectedSequence(unsigned sequence) {
m_expected_sequence = sequence;
}

private:
template <typename T> T Read(ValueTag) {
assert(HasData(sizeof(T)));
Expand Down Expand Up @@ -402,11 +418,17 @@ class Deserializer {
return *(new UnderlyingT(Deserialize<UnderlyingT>()));
}

/// Verify that the given sequence number matches what we expect.
void CheckSequence(unsigned sequence);

/// Mapping of indices to objects.
IndexToObject m_index_to_object;

/// Buffer containing the serialized data.
llvm::StringRef m_buffer;

/// The result's expected sequence number.
llvm::Optional<unsigned> m_expected_sequence;
};

/// Partial specialization for C-style strings. We read the string value
Expand Down Expand Up @@ -600,8 +622,8 @@ class Serializer {
/// 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";
this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
<< stringify_args(t) << "\n";
#endif
if (std::is_fundamental<T>::value) {
Serialize(*t);
Expand All @@ -616,8 +638,8 @@ class Serializer {
/// 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";
this_thread_id() << "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));
Expand All @@ -637,8 +659,8 @@ class Serializer {

void Serialize(const char *t) {
#ifdef LLDB_REPRO_INSTR_TRACE
llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
<< stringify_args(t) << "\n";
this_thread_id() << "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);
Expand Down Expand Up @@ -737,19 +759,23 @@ class Recorder {
if (!ShouldCapture())
return;

std::lock_guard<std::mutex> lock(g_mutex);
unsigned sequence = GetSequenceNumber();
unsigned id = registry.GetID(uintptr_t(f));

#ifdef LLDB_REPRO_INSTR_TRACE
Log(id);
#endif

serializer.SerializeAll(sequence);
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(sequence);
serializer.SerializeAll(0);
m_result_recorded = true;
}
Expand All @@ -763,16 +789,20 @@ class Recorder {
if (!ShouldCapture())
return;

std::lock_guard<std::mutex> lock(g_mutex);
unsigned sequence = GetSequenceNumber();
unsigned id = registry.GetID(uintptr_t(f));

#ifdef LLDB_REPRO_INSTR_TRACE
Log(id);
#endif

serializer.SerializeAll(sequence);
serializer.SerializeAll(id);
serializer.SerializeAll(args...);

// Record result.
serializer.SerializeAll(sequence);
serializer.SerializeAll(0);
m_result_recorded = true;
}
Expand All @@ -798,7 +828,9 @@ class Recorder {
if (update_boundary)
UpdateBoundary();
if (m_serializer && ShouldCapture()) {
std::lock_guard<std::mutex> lock(g_mutex);
assert(!m_result_recorded);
m_serializer->SerializeAll(GetSequenceNumber());
m_serializer->SerializeAll(r);
m_result_recorded = true;
}
Expand All @@ -808,6 +840,7 @@ class Recorder {
template <typename Result, typename T>
Result Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr,
bool update_boundary) {
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
unsigned actual_id = registry.GetID(addr);
unsigned id = deserializer.Deserialize<unsigned>();
registry.CheckID(id, actual_id);
Expand All @@ -818,6 +851,7 @@ class Recorder {
}

void Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr) {
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
unsigned actual_id = registry.GetID(addr);
unsigned id = deserializer.Deserialize<unsigned>();
registry.CheckID(id, actual_id);
Expand All @@ -833,7 +867,14 @@ class Recorder {

bool ShouldCapture() { return m_local_boundary; }

/// Mark the current thread as a private thread and pretend that everything
/// on this thread is behind happening behind the API boundary.
static void PrivateThread() { g_global_boundary = true; }

private:
static unsigned GetNextSequenceNumber() { return g_sequence++; }
unsigned GetSequenceNumber() const;

template <typename T> friend struct replay;
void UpdateBoundary() {
if (m_local_boundary)
Expand All @@ -842,8 +883,8 @@ class Recorder {

#ifdef LLDB_REPRO_INSTR_TRACE
void Log(unsigned id) {
llvm::errs() << "Recording " << id << ": " << m_pretty_func << " ("
<< m_pretty_args << ")\n";
this_thread_id() << "Recording " << id << ": " << m_pretty_func << " ("
<< m_pretty_args << ")\n";
}
#endif

Expand All @@ -859,8 +900,17 @@ class Recorder {
/// Whether the return value was recorded explicitly.
bool m_result_recorded;

/// The sequence number for this pair of function and result.
unsigned m_sequence;

/// Whether we're currently across the API boundary.
static bool g_global_boundary;
static thread_local bool g_global_boundary;

/// Global mutex to protect concurrent access.
static std::mutex g_mutex;

/// Unique, monotonically increasing sequence number.
static std::atomic<unsigned> g_sequence;
};

/// To be used as the "Runtime ID" of a constructor. It also invokes the
Expand Down Expand Up @@ -1002,6 +1052,7 @@ struct invoke_char_ptr<Result (Class::*)(Args...) const> {

static Result replay(Recorder &recorder, Deserializer &deserializer,
Registry &registry, char *str) {
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
deserializer.Deserialize<unsigned>();
Class *c = deserializer.Deserialize<Class *>();
deserializer.Deserialize<const char *>();
Expand All @@ -1023,6 +1074,7 @@ struct invoke_char_ptr<Result (Class::*)(Args...)> {

static Result replay(Recorder &recorder, Deserializer &deserializer,
Registry &registry, char *str) {
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
deserializer.Deserialize<unsigned>();
Class *c = deserializer.Deserialize<Class *>();
deserializer.Deserialize<const char *>();
Expand All @@ -1043,6 +1095,7 @@ struct invoke_char_ptr<Result (*)(Args...)> {

static Result replay(Recorder &recorder, Deserializer &deserializer,
Registry &registry, char *str) {
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
deserializer.Deserialize<unsigned>();
deserializer.Deserialize<const char *>();
size_t l = deserializer.Deserialize<size_t>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Utility/ReproducerInstrumentation.h"
#include "lldb/Utility/Timer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -430,6 +431,7 @@ ScriptInterpreterPythonImpl::Locker::Locker(
: ScriptInterpreterLocker(),
m_teardown_session((on_leave & TearDownSession) == TearDownSession),
m_python_interpreter(py_interpreter) {
repro::Recorder::PrivateThread();
DoAcquireLock();
if ((on_entry & InitSession) == InitSession) {
if (!DoInitSession(on_entry, in, out, err)) {
Expand Down
31 changes: 27 additions & 4 deletions lldb/source/Utility/ReproducerInstrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "lldb/Utility/ReproducerInstrumentation.h"
#include "lldb/Utility/Reproducer.h"
#include <limits>
#include <stdio.h>
#include <stdlib.h>
#include <thread>
Expand Down Expand Up @@ -84,6 +85,16 @@ template <> const char **Deserializer::Deserialize<const char **>() {
return r;
}

void Deserializer::CheckSequence(unsigned sequence) {
if (m_expected_sequence && *m_expected_sequence != sequence)
llvm::report_fatal_error(
"The result does not match the preceding "
"function. This is probably the result of concurrent "
"use of the SB API during capture, which is currently not "
"supported.");
m_expected_sequence.reset();
}

bool Registry::Replay(const FileSpec &file) {
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
if (auto err = error_or_file.getError())
Expand All @@ -107,6 +118,7 @@ bool Registry::Replay(Deserializer &deserializer) {
setvbuf(stdout, nullptr, _IONBF, 0);

while (deserializer.HasData(1)) {
unsigned sequence = deserializer.Deserialize<unsigned>();
unsigned id = deserializer.Deserialize<unsigned>();

#ifndef LLDB_REPRO_INSTR_TRACE
Expand All @@ -115,6 +127,7 @@ bool Registry::Replay(Deserializer &deserializer) {
llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
#endif

deserializer.SetExpectedSequence(sequence);
GetReplayer(id)->operator()(deserializer);
}

Expand Down Expand Up @@ -181,21 +194,24 @@ unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {

Recorder::Recorder()
: m_serializer(nullptr), m_pretty_func(), m_pretty_args(),
m_local_boundary(false), m_result_recorded(true) {
m_local_boundary(false), m_result_recorded(true),
m_sequence(std::numeric_limits<unsigned>::max()) {
if (!g_global_boundary) {
g_global_boundary = true;
m_local_boundary = true;
m_sequence = GetNextSequenceNumber();
}
}

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),
m_result_recorded(true) {
m_result_recorded(true),
m_sequence(std::numeric_limits<unsigned>::max()) {
if (!g_global_boundary) {
g_global_boundary = true;
m_local_boundary = true;

m_sequence = GetNextSequenceNumber();
LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})",
m_pretty_func, m_pretty_args);
}
Expand All @@ -206,6 +222,11 @@ Recorder::~Recorder() {
UpdateBoundary();
}

unsigned Recorder::GetSequenceNumber() const {
assert(m_sequence != std::numeric_limits<unsigned>::max());
return m_sequence;
}

void InstrumentationData::Initialize(Serializer &serializer,
Registry &registry) {
InstanceImpl().emplace(serializer, registry);
Expand All @@ -227,4 +248,6 @@ llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
return g_instrumentation_data;
}

bool lldb_private::repro::Recorder::g_global_boundary;
thread_local bool lldb_private::repro::Recorder::g_global_boundary = false;
std::atomic<unsigned> lldb_private::repro::Recorder::g_sequence;
std::mutex lldb_private::repro::Recorder::g_mutex;
Loading