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 
9 #include "lldb/Utility/ReproducerInstrumentation.h"
10 #include "lldb/Utility/Reproducer.h"
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 
GetObjectForIndexImpl(unsigned idx)19 void *IndexToObject::GetObjectForIndexImpl(unsigned idx) {
20   return m_mapping.lookup(idx);
21 }
22 
AddObjectForIndexImpl(unsigned idx,void * object)23 void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) {
24   assert(idx != 0 && "Cannot add object for sentinel");
25   m_mapping[idx] = object;
26 }
27 
GetAllObjects() const28 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 
Deserialize()47 template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>() {
48   return Deserialize<uint8_t *>();
49 }
50 
Deserialize()51 template <> void *Deserializer::Deserialize<void *>() {
52   return const_cast<void *>(Deserialize<const void *>());
53 }
54 
Deserialize()55 template <> const void *Deserializer::Deserialize<const void *>() {
56   return nullptr;
57 }
58 
Deserialize()59 template <> char *Deserializer::Deserialize<char *>() {
60   return const_cast<char *>(Deserialize<const char *>());
61 }
62 
Deserialize()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 
Deserialize()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 
CheckSequence(unsigned sequence)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 
Replay(const FileSpec & file)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 
Replay(llvm::StringRef buffer)106 bool Registry::Replay(llvm::StringRef buffer) {
107   Deserializer deserializer(buffer);
108   return Replay(deserializer);
109 }
110 
Replay(Deserializer & deserializer)111 bool Registry::Replay(Deserializer &deserializer) {
112 #ifndef LLDB_REPRO_INSTR_TRACE
113   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API);
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 
DoRegister(uintptr_t RunID,std::unique_ptr<Replayer> replayer,SignatureStr signature)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 
GetID(uintptr_t addr)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 
GetSignature(unsigned id)156 std::string Registry::GetSignature(unsigned id) {
157   assert(m_ids.count(id) != 0 && "ID not in registry");
158   return m_ids[id].second.ToString();
159 }
160 
CheckID(unsigned expected,unsigned actual)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 
GetReplayer(unsigned id)177 Replayer *Registry::GetReplayer(unsigned id) {
178   assert(m_ids.count(id) != 0 && "ID not in registry");
179   return m_ids[id].first;
180 }
181 
ToString() const182 std::string Registry::SignatureStr::ToString() const {
183   return (result + (result.empty() ? "" : " ") + scope + "::" + name + args)
184       .str();
185 }
186 
GetIndexForObjectImpl(const void * object)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 
Recorder()195 Recorder::Recorder()
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;
202     m_sequence = GetNextSequenceNumber();
203   }
204 }
205 
Recorder(llvm::StringRef pretty_func,std::string && pretty_args)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;
214     m_sequence = GetNextSequenceNumber();
215     LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})",
216              m_pretty_func, m_pretty_args);
217   }
218 }
219 
~Recorder()220 Recorder::~Recorder() {
221   assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?");
222   UpdateBoundary();
223 }
224 
GetSequenceNumber() const225 unsigned Recorder::GetSequenceNumber() const {
226   assert(m_sequence != std::numeric_limits<unsigned>::max());
227   return m_sequence;
228 }
229 
Initialize(Serializer & serializer,Registry & registry)230 void InstrumentationData::Initialize(Serializer &serializer,
231                                      Registry &registry) {
232   InstanceImpl().emplace(serializer, registry);
233 }
234 
Initialize(Deserializer & deserializer,Registry & registry)235 void InstrumentationData::Initialize(Deserializer &deserializer,
236                                      Registry &registry) {
237   InstanceImpl().emplace(deserializer, registry);
238 }
239 
Instance()240 InstrumentationData &InstrumentationData::Instance() {
241   if (!InstanceImpl())
242     InstanceImpl().emplace();
243   return *InstanceImpl();
244 }
245 
InstanceImpl()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;
253 std::mutex lldb_private::repro::Recorder::g_mutex;
254