LLDB  mainline
ReproducerInstrumentation.cpp
Go to the documentation of this file.
1 //===-- ReproducerInstrumentation.cpp -------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 #include <cstdio>
12 #include <cstdlib>
13 #include <limits>
14 #include <thread>
15 
16 using namespace lldb_private;
17 using namespace lldb_private::repro;
18 
20  return m_mapping.lookup(idx);
21 }
22 
23 void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) {
24  assert(idx != 0 && "Cannot add object for sentinel");
25  m_mapping[idx] = object;
26 }
27 
28 std::vector<void *> IndexToObject::GetAllObjects() const {
29  std::vector<std::pair<unsigned, void *>> pairs;
30  for (auto &e : m_mapping) {
31  pairs.emplace_back(e.first, e.second);
32  }
33 
34  // Sort based on index.
35  std::sort(pairs.begin(), pairs.end(),
36  [](auto &lhs, auto &rhs) { return lhs.first < rhs.first; });
37 
38  std::vector<void *> objects;
39  objects.reserve(pairs.size());
40  for (auto &p : pairs) {
41  objects.push_back(p.second);
42  }
43 
44  return objects;
45 }
46 
47 template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>() {
48  return Deserialize<uint8_t *>();
49 }
50 
51 template <> void *Deserializer::Deserialize<void *>() {
52  return const_cast<void *>(Deserialize<const void *>());
53 }
54 
55 template <> const void *Deserializer::Deserialize<const void *>() {
56  return nullptr;
57 }
58 
59 template <> char *Deserializer::Deserialize<char *>() {
60  return const_cast<char *>(Deserialize<const char *>());
61 }
62 
63 template <> const char *Deserializer::Deserialize<const char *>() {
64  const size_t size = Deserialize<size_t>();
65  if (size == std::numeric_limits<size_t>::max())
66  return nullptr;
67  assert(HasData(size + 1));
68  const char *str = m_buffer.data();
69  m_buffer = m_buffer.drop_front(size + 1);
70 #ifdef LLDB_REPRO_INSTR_TRACE
71  llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> \""
72  << str << "\"\n";
73 #endif
74  return str;
75 }
76 
77 template <> const char **Deserializer::Deserialize<const char **>() {
78  const size_t size = Deserialize<size_t>();
79  if (size == 0)
80  return nullptr;
81  const char **r =
82  reinterpret_cast<const char **>(calloc(size + 1, sizeof(char *)));
83  for (size_t i = 0; i < size; ++i)
84  r[i] = Deserialize<const char *>();
85  return r;
86 }
87 
88 void Deserializer::CheckSequence(unsigned sequence) {
89  if (m_expected_sequence && *m_expected_sequence != sequence)
90  llvm::report_fatal_error(
91  "The result does not match the preceding "
92  "function. This is probably the result of concurrent "
93  "use of the SB API during capture, which is currently not "
94  "supported.");
95  m_expected_sequence.reset();
96 }
97 
98 bool Registry::Replay(const FileSpec &file) {
99  auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
100  if (auto err = error_or_file.getError())
101  return false;
102 
103  return Replay((*error_or_file)->getBuffer());
104 }
105 
106 bool Registry::Replay(llvm::StringRef buffer) {
107  Deserializer deserializer(buffer);
108  return Replay(deserializer);
109 }
110 
111 bool Registry::Replay(Deserializer &deserializer) {
112 #ifndef LLDB_REPRO_INSTR_TRACE
114 #endif
115 
116  // Disable buffering stdout so that we approximate the way things get flushed
117  // during an interactive session.
118  setvbuf(stdout, nullptr, _IONBF, 0);
119 
120  while (deserializer.HasData(1)) {
121  unsigned sequence = deserializer.Deserialize<unsigned>();
122  unsigned id = deserializer.Deserialize<unsigned>();
123 
124 #ifndef LLDB_REPRO_INSTR_TRACE
125  LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id));
126 #else
127  llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
128 #endif
129 
130  deserializer.SetExpectedSequence(sequence);
131  GetReplayer(id)->operator()(deserializer);
132  }
133 
134  // Add a small artificial delay to ensure that all asynchronous events have
135  // completed before we exit.
136  std::this_thread::sleep_for(std::chrono::milliseconds(100));
137 
138  return true;
139 }
140 
141 void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
142  SignatureStr signature) {
143  const unsigned id = m_replayers.size() + 1;
144  assert(m_replayers.find(RunID) == m_replayers.end());
145  m_replayers[RunID] = std::make_pair(std::move(replayer), id);
146  m_ids[id] =
147  std::make_pair(m_replayers[RunID].first.get(), std::move(signature));
148 }
149 
150 unsigned Registry::GetID(uintptr_t addr) {
151  unsigned id = m_replayers[addr].second;
152  assert(id != 0 && "Forgot to add function to registry?");
153  return id;
154 }
155 
157  assert(m_ids.count(id) != 0 && "ID not in registry");
158  return m_ids[id].second.ToString();
159 }
160 
161 void Registry::CheckID(unsigned expected, unsigned actual) {
162  if (expected != actual) {
163  llvm::errs() << "Reproducer expected signature " << expected << ": '"
164  << GetSignature(expected) << "'\n";
165  llvm::errs() << "Reproducer actual signature " << actual << ": '"
166  << GetSignature(actual) << "'\n";
167  llvm::report_fatal_error(
168  "Detected reproducer replay divergence. Refusing to continue.");
169  }
170 
171 #ifdef LLDB_REPRO_INSTR_TRACE
172  llvm::errs() << "Replaying " << actual << ": " << GetSignature(actual)
173  << "\n";
174 #endif
175 }
176 
178  assert(m_ids.count(id) != 0 && "ID not in registry");
179  return m_ids[id].first;
180 }
181 
183  return (result + (result.empty() ? "" : " ") + scope + "::" + name + args)
184  .str();
185 }
186 
187 unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {
188  unsigned index = m_mapping.size() + 1;
189  auto it = m_mapping.find(object);
190  if (it == m_mapping.end())
191  m_mapping[object] = index;
192  return m_mapping[object];
193 }
194 
196  : m_pretty_func(), m_pretty_args(),
197 
198  m_sequence(std::numeric_limits<unsigned>::max()) {
199  if (!g_global_boundary) {
200  g_global_boundary = true;
201  m_local_boundary = true;
203  }
204 }
205 
206 Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args)
207  : m_serializer(nullptr), m_pretty_func(pretty_func),
208  m_pretty_args(pretty_args), m_local_boundary(false),
209  m_result_recorded(true),
210  m_sequence(std::numeric_limits<unsigned>::max()) {
211  if (!g_global_boundary) {
212  g_global_boundary = true;
213  m_local_boundary = true;
217  }
218 }
219 
221  assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?");
222  UpdateBoundary();
223 }
224 
225 unsigned Recorder::GetSequenceNumber() const {
226  assert(m_sequence != std::numeric_limits<unsigned>::max());
227  return m_sequence;
228 }
229 
231  Registry &registry) {
232  InstanceImpl().emplace(serializer, registry);
233 }
234 
236  Registry &registry) {
237  InstanceImpl().emplace(deserializer, registry);
238 }
239 
241  if (!InstanceImpl())
242  InstanceImpl().emplace();
243  return *InstanceImpl();
244 }
245 
246 llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
247  static llvm::Optional<InstrumentationData> g_instrumentation_data;
248  return g_instrumentation_data;
249 }
250 
251 thread_local bool lldb_private::repro::Recorder::g_global_boundary = false;
252 std::atomic<unsigned> lldb_private::repro::Recorder::g_sequence;
lldb_private::repro::Recorder::GetSequenceNumber
unsigned GetSequenceNumber() const
Definition: ReproducerInstrumentation.cpp:225
lldb_private::repro::Recorder::m_result_recorded
bool m_result_recorded
Whether the return value was recorded explicitly.
Definition: ReproducerInstrumentation.h:900
lldb_private::repro::ObjectToIndex::GetIndexForObjectImpl
unsigned GetIndexForObjectImpl(const void *object)
Definition: ReproducerInstrumentation.cpp:187
lldb_private::repro::Deserializer::CheckSequence
void CheckSequence(unsigned sequence)
Verify that the given sequence number matches what we expect.
Definition: ReproducerInstrumentation.cpp:88
lldb_private::repro::Deserializer::HasData
bool HasData(unsigned size)
Returns true when the buffer has unread data.
Definition: ReproducerInstrumentation.h:323
LIBLLDB_LOG_API
#define LIBLLDB_LOG_API
Definition: Logging.h:30
lldb_private::repro::Deserializer
Deserializes data from a buffer.
Definition: ReproducerInstrumentation.h:318
lldb_private::repro::Registry::SignatureStr::result
llvm::StringRef result
Definition: ReproducerInstrumentation.h:526
lldb_private::repro::Recorder::m_sequence
unsigned m_sequence
The sequence number for this pair of function and result.
Definition: ReproducerInstrumentation.h:903
lldb_private::repro::Registry::SignatureStr
Definition: ReproducerInstrumentation.h:519
Reproducer.h
lldb_private::repro::Deserializer::m_buffer
llvm::StringRef m_buffer
Buffer containing the serialized data.
Definition: ReproducerInstrumentation.h:428
lldb_private::repro::Recorder::g_mutex
static std::mutex g_mutex
Global mutex to protect concurrent access.
Definition: ReproducerInstrumentation.h:909
lldb_private::repro::Registry::DoRegister
void DoRegister(uintptr_t RunID, std::unique_ptr< Replayer > replayer, SignatureStr signature)
Register the given replayer for a function (and the ID mapping).
Definition: ReproducerInstrumentation.cpp:141
lldb_private::repro::Recorder::UpdateBoundary
void UpdateBoundary()
Definition: ReproducerInstrumentation.h:878
lldb_private::repro::Registry::m_replayers
std::map< uintptr_t, std::pair< std::unique_ptr< Replayer >, unsigned > > m_replayers
Mapping of function addresses to replayers and their ID.
Definition: ReproducerInstrumentation.h:582
lldb_private::FileSpec
Definition: FileSpec.h:56
lldb_private::repro::Registry::Replay
bool Replay(const FileSpec &file)
Replay functions from a file.
Definition: ReproducerInstrumentation.cpp:98
lldb_private::repro::Deserializer::SetExpectedSequence
void SetExpectedSequence(unsigned sequence)
Definition: ReproducerInstrumentation.h:376
object
lldb_private::repro::Registry::m_ids
std::map< unsigned, std::pair< Replayer *, SignatureStr > > m_ids
Mapping of IDs to replayer instances.
Definition: ReproducerInstrumentation.h:585
lldb_private::repro::Recorder::g_sequence
static std::atomic< unsigned > g_sequence
Unique, monotonically increasing sequence number.
Definition: ReproducerInstrumentation.h:912
lldb_private::repro::InstrumentationData
Definition: ReproducerInstrumentation.h:698
lldb_private::GetLogIfAllCategoriesSet
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
lldb_private::repro::Registry::SignatureStr::ToString
std::string ToString() const
Definition: ReproducerInstrumentation.cpp:182
lldb_private::repro::InstrumentationData::Initialize
static void Initialize(Serializer &serializer, Registry &registry)
Definition: ReproducerInstrumentation.cpp:230
lldb_private::repro::Registry::GetID
unsigned GetID(uintptr_t addr)
Returns the ID for a given function address.
Definition: ReproducerInstrumentation.cpp:150
lldb_private::repro::Serializer
Serializes functions, their arguments and their return type to a stream.
Definition: ReproducerInstrumentation.h:606
lldb_private::repro::IndexToObject::GetObjectForIndexImpl
void * GetObjectForIndexImpl(unsigned idx)
Helper method that does the actual lookup.
Definition: ReproducerInstrumentation.cpp:19
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:39
lldb_private::repro::Recorder::GetNextSequenceNumber
static unsigned GetNextSequenceNumber()
Definition: ReproducerInstrumentation.h:874
ReproducerInstrumentation.h
lldb_private::repro::Recorder::m_local_boundary
bool m_local_boundary
Whether this function call was the one crossing the API boundary.
Definition: ReproducerInstrumentation.h:897
lldb_private::repro::Replayer
The replayer interface.
Definition: ReproducerInstrumentation.h:471
lldb_private::repro::Registry
The registry contains a unique mapping between functions and their ID.
Definition: ReproducerInstrumentation.h:517
lldb_private::repro::Registry::SignatureStr::name
llvm::StringRef name
Definition: ReproducerInstrumentation.h:528
lldb_private::repro::Registry::GetSignature
std::string GetSignature(unsigned id)
Definition: ReproducerInstrumentation.cpp:156
lldb_private::repro::Recorder::g_global_boundary
static thread_local bool g_global_boundary
Whether we're currently across the API boundary.
Definition: ReproducerInstrumentation.h:906
id
void * id
Definition: PlatformiOSSimulatorCoreSimulatorSupport.h:20
lldb_private::repro::Recorder::Recorder
Recorder()
Definition: ReproducerInstrumentation.cpp:195
lldb_private::repro::Registry::CheckID
void CheckID(unsigned expected, unsigned actual)
Definition: ReproducerInstrumentation.cpp:161
lldb_private::repro::Deserializer::m_expected_sequence
llvm::Optional< unsigned > m_expected_sequence
The result's expected sequence number.
Definition: ReproducerInstrumentation.h:431
lldb_private::repro
Definition: SBReproducer.h:15
lldb_private::repro::IndexToObject::GetAllObjects
std::vector< void * > GetAllObjects() const
Get all objects sorted by their index.
Definition: ReproducerInstrumentation.cpp:28
LLDB_LOG
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:242
lldb_private::repro::InstrumentationData::InstanceImpl
static llvm::Optional< InstrumentationData > & InstanceImpl()
Definition: ReproducerInstrumentation.cpp:246
lldb_private::repro::Recorder::~Recorder
~Recorder()
Definition: ReproducerInstrumentation.cpp:220
lldb_private::repro::IndexToObject::m_mapping
llvm::DenseMap< unsigned, void * > m_mapping
Keeps a mapping between indices and their corresponding object.
Definition: ReproducerInstrumentation.h:279
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::repro::InstrumentationData::Instance
static InstrumentationData & Instance()
Definition: ReproducerInstrumentation.cpp:240
lldb_private::repro::Registry::SignatureStr::args
llvm::StringRef args
Definition: ReproducerInstrumentation.h:529
lldb_private::repro::Registry::GetReplayer
Replayer * GetReplayer(unsigned id)
Get the replayer matching the given ID.
Definition: ReproducerInstrumentation.cpp:177
lldb_private::Log
Definition: Log.h:49
lldb_private::repro::Recorder::m_pretty_func
llvm::StringRef m_pretty_func
Pretty function for logging.
Definition: ReproducerInstrumentation.h:893
lldb_private::repro::Recorder::m_pretty_args
std::string m_pretty_args
Definition: ReproducerInstrumentation.h:894
lldb_private::FileSpec::GetPath
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:348
lldb_private::repro::Registry::SignatureStr::scope
llvm::StringRef scope
Definition: ReproducerInstrumentation.h:527
lldb_private::repro::IndexToObject::AddObjectForIndexImpl
void AddObjectForIndexImpl(unsigned idx, void *object)
Helper method that does the actual insertion.
Definition: ReproducerInstrumentation.cpp:23
lldb_private::repro::Deserializer::Deserialize
T Deserialize()
Deserialize and interpret value as T.
Definition: ReproducerInstrumentation.h:326