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 <stdio.h>
12 #include <stdlib.h>
13 #include <thread>
14 
15 using namespace lldb_private;
16 using namespace lldb_private::repro;
17 
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
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 
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(llvm::StringRef pretty_func, std::string &&pretty_args)
183  : m_serializer(nullptr), m_pretty_func(pretty_func),
184  m_pretty_args(pretty_args), m_local_boundary(false),
185  m_result_recorded(true) {
186  if (!g_global_boundary) {
187  g_global_boundary = true;
188  m_local_boundary = true;
189 
192  }
193 }
194 
196  assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?");
197  UpdateBoundary();
198 }
199 
201  Registry &registry) {
202  InstanceImpl().emplace(serializer, registry);
203 }
204 
206  Registry &registry) {
207  InstanceImpl().emplace(deserializer, registry);
208 }
209 
211  if (!InstanceImpl())
212  InstanceImpl().emplace();
213  return *InstanceImpl();
214 }
215 
216 llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
217  static llvm::Optional<InstrumentationData> g_instrumentation_data;
218  return g_instrumentation_data;
219 }
220 
The registry contains a unique mapping between functions and their ID.
void * GetObjectForIndexImpl(unsigned idx)
Helper method that does the actual lookup.
A class that represents a running process on the host machine.
static bool g_global_boundary
Whether we&#39;re currently across the API boundary.
A file utility class.
Definition: FileSpec.h:56
bool Replay(const FileSpec &file)
Replay functions from a file.
Replayer * GetReplayer(unsigned id)
Get the replayer matching the given ID.
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:242
void DoRegister(uintptr_t RunID, std::unique_ptr< Replayer > replayer, SignatureStr signature)
Register the given replayer for a function (and the ID mapping).
void CheckID(unsigned expected, unsigned actual)
#define LIBLLDB_LOG_API
Definition: Logging.h:30
Recorder(llvm::StringRef pretty_func={}, std::string &&pretty_args={})
static void Initialize(Serializer &serializer, Registry &registry)
static llvm::Optional< InstrumentationData > & InstanceImpl()
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
unsigned GetIndexForObjectImpl(const void *object)
llvm::StringRef m_pretty_func
Pretty function for logging.
Deserializes data from a buffer.
unsigned GetID(uintptr_t addr)
Returns the ID for a given function address.
bool m_local_boundary
Whether this function call was the one crossing the API boundary.
bool m_result_recorded
Whether the return value was recorded explicitly.
llvm::DenseMap< unsigned, void * > m_mapping
Keeps a mapping between indices and their corresponding object.
std::vector< void * > GetAllObjects() const
Get all objects sorted by their index.
T Deserialize()
Deserialize and interpret value as T.
bool HasData(unsigned size)
Returns true when the buffer has unread data.
void AddObjectForIndexImpl(unsigned idx, void *object)
Helper method that does the actual insertion.
Serializes functions, their arguments and their return type to a stream.
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