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 <stdio.h> 12 #include <stdlib.h> 13 #include <thread> 14 15 using namespace lldb_private; 16 using namespace lldb_private::repro; 17 18 void *IndexToObject::GetObjectForIndexImpl(unsigned idx) { 19 return m_mapping.lookup(idx); 20 } 21 22 void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) { 23 assert(idx != 0 && "Cannot add object for sentinel"); 24 m_mapping[idx] = object; 25 } 26 27 std::vector<void *> IndexToObject::GetAllObjects() const { 28 std::vector<std::pair<unsigned, void *>> pairs; 29 for (auto &e : m_mapping) { 30 pairs.emplace_back(e.first, e.second); 31 } 32 33 // Sort based on index. 34 std::sort(pairs.begin(), pairs.end(), 35 [](auto &lhs, auto &rhs) { return lhs.first < rhs.first; }); 36 37 std::vector<void *> objects; 38 objects.reserve(pairs.size()); 39 for (auto &p : pairs) { 40 objects.push_back(p.second); 41 } 42 43 return objects; 44 } 45 46 template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>() { 47 return Deserialize<uint8_t *>(); 48 } 49 50 template <> void *Deserializer::Deserialize<void *>() { 51 return const_cast<void *>(Deserialize<const void *>()); 52 } 53 54 template <> const void *Deserializer::Deserialize<const void *>() { 55 return nullptr; 56 } 57 58 template <> char *Deserializer::Deserialize<char *>() { 59 return const_cast<char *>(Deserialize<const char *>()); 60 } 61 62 template <> const char *Deserializer::Deserialize<const char *>() { 63 const size_t size = Deserialize<size_t>(); 64 if (size == std::numeric_limits<size_t>::max()) 65 return nullptr; 66 assert(HasData(size + 1)); 67 const char *str = m_buffer.data(); 68 m_buffer = m_buffer.drop_front(size + 1); 69 #ifdef LLDB_REPRO_INSTR_TRACE 70 llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> \"" 71 << str << "\"\n"; 72 #endif 73 return str; 74 } 75 76 template <> const char **Deserializer::Deserialize<const char **>() { 77 const size_t size = Deserialize<size_t>(); 78 if (size == 0) 79 return nullptr; 80 const char **r = 81 reinterpret_cast<const char **>(calloc(size + 1, sizeof(char *))); 82 for (size_t i = 0; i < size; ++i) 83 r[i] = Deserialize<const char *>(); 84 return r; 85 } 86 87 bool Registry::Replay(const FileSpec &file) { 88 auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); 89 if (auto err = error_or_file.getError()) 90 return false; 91 92 return Replay((*error_or_file)->getBuffer()); 93 } 94 95 bool Registry::Replay(llvm::StringRef buffer) { 96 Deserializer deserializer(buffer); 97 return Replay(deserializer); 98 } 99 100 bool Registry::Replay(Deserializer &deserializer) { 101 #ifndef LLDB_REPRO_INSTR_TRACE 102 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API); 103 #endif 104 105 // Disable buffering stdout so that we approximate the way things get flushed 106 // during an interactive session. 107 setvbuf(stdout, nullptr, _IONBF, 0); 108 109 while (deserializer.HasData(1)) { 110 unsigned id = deserializer.Deserialize<unsigned>(); 111 112 #ifndef LLDB_REPRO_INSTR_TRACE 113 LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id)); 114 #else 115 llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n"; 116 #endif 117 118 GetReplayer(id)->operator()(deserializer); 119 } 120 121 // Add a small artificial delay to ensure that all asynchronous events have 122 // completed before we exit. 123 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 124 125 return true; 126 } 127 128 void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer, 129 SignatureStr signature) { 130 const unsigned id = m_replayers.size() + 1; 131 assert(m_replayers.find(RunID) == m_replayers.end()); 132 m_replayers[RunID] = std::make_pair(std::move(replayer), id); 133 m_ids[id] = 134 std::make_pair(m_replayers[RunID].first.get(), std::move(signature)); 135 } 136 137 unsigned Registry::GetID(uintptr_t addr) { 138 unsigned id = m_replayers[addr].second; 139 assert(id != 0 && "Forgot to add function to registry?"); 140 return id; 141 } 142 143 std::string Registry::GetSignature(unsigned id) { 144 assert(m_ids.count(id) != 0 && "ID not in registry"); 145 return m_ids[id].second.ToString(); 146 } 147 148 void Registry::CheckID(unsigned expected, unsigned actual) { 149 if (expected != actual) { 150 llvm::errs() << "Reproducer expected signature " << expected << ": '" 151 << GetSignature(expected) << "'\n"; 152 llvm::errs() << "Reproducer actual signature " << actual << ": '" 153 << GetSignature(actual) << "'\n"; 154 llvm::report_fatal_error( 155 "Detected reproducer replay divergence. Refusing to continue."); 156 } 157 158 #ifdef LLDB_REPRO_INSTR_TRACE 159 llvm::errs() << "Replaying " << actual << ": " << GetSignature(actual) 160 << "\n"; 161 #endif 162 } 163 164 Replayer *Registry::GetReplayer(unsigned id) { 165 assert(m_ids.count(id) != 0 && "ID not in registry"); 166 return m_ids[id].first; 167 } 168 169 std::string Registry::SignatureStr::ToString() const { 170 return (result + (result.empty() ? "" : " ") + scope + "::" + name + args) 171 .str(); 172 } 173 174 unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) { 175 unsigned index = m_mapping.size() + 1; 176 auto it = m_mapping.find(object); 177 if (it == m_mapping.end()) 178 m_mapping[object] = index; 179 return m_mapping[object]; 180 } 181 182 Recorder::Recorder() 183 : m_serializer(nullptr), m_pretty_func(), m_pretty_args(), 184 m_local_boundary(false), m_result_recorded(true) { 185 if (!g_global_boundary) { 186 g_global_boundary = true; 187 m_local_boundary = true; 188 } 189 } 190 191 Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args) 192 : m_serializer(nullptr), m_pretty_func(pretty_func), 193 m_pretty_args(pretty_args), m_local_boundary(false), 194 m_result_recorded(true) { 195 if (!g_global_boundary) { 196 g_global_boundary = true; 197 m_local_boundary = true; 198 199 LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", 200 m_pretty_func, m_pretty_args); 201 } 202 } 203 204 Recorder::~Recorder() { 205 assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?"); 206 UpdateBoundary(); 207 } 208 209 void InstrumentationData::Initialize(Serializer &serializer, 210 Registry ®istry) { 211 InstanceImpl().emplace(serializer, registry); 212 } 213 214 void InstrumentationData::Initialize(Deserializer &deserializer, 215 Registry ®istry) { 216 InstanceImpl().emplace(deserializer, registry); 217 } 218 219 InstrumentationData &InstrumentationData::Instance() { 220 if (!InstanceImpl()) 221 InstanceImpl().emplace(); 222 return *InstanceImpl(); 223 } 224 225 llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() { 226 static llvm::Optional<InstrumentationData> g_instrumentation_data; 227 return g_instrumentation_data; 228 } 229 230 bool lldb_private::repro::Recorder::g_global_boundary; 231