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 19 void *IndexToObject::GetObjectForIndexImpl(unsigned idx) { 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 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 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 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 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 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 182 std::string Registry::SignatureStr::ToString() const { 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 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 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 220 Recorder::~Recorder() { 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 230 void InstrumentationData::Initialize(Serializer &serializer, 231 Registry ®istry) { 232 InstanceImpl().emplace(serializer, registry); 233 } 234 235 void InstrumentationData::Initialize(Deserializer &deserializer, 236 Registry ®istry) { 237 InstanceImpl().emplace(deserializer, registry); 238 } 239 240 InstrumentationData &InstrumentationData::Instance() { 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; 253 std::mutex lldb_private::repro::Recorder::g_mutex; 254