1//===-- ReproducerInstrumentation.cpp ---------------------------*- C++ -*-===//
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
12using namespace lldb_private;
13using namespace lldb_private::repro;
14
15void *IndexToObject::GetObjectForIndexImpl(unsigned idx) {
16  return m_mapping.lookup(idx);
17}
18
19void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) {
20  assert(idx != 0 && "Cannot add object for sentinel");
21  m_mapping[idx] = object;
22}
23
24template <> char *Deserializer::Deserialize<char *>() {
25  return const_cast<char *>(Deserialize<const char *>());
26}
27
28template <> const char *Deserializer::Deserialize<const char *>() {
29  auto pos = m_buffer.find('\0');
30  if (pos == llvm::StringRef::npos)
31    return nullptr;
32  const char *str = m_buffer.data();
33  m_buffer = m_buffer.drop_front(pos + 1);
34  return str;
35}
36
37bool Registry::Replay(const FileSpec &file) {
38  auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
39  if (auto err = error_or_file.getError())
40    return false;
41
42  return Replay((*error_or_file)->getBuffer());
43}
44
45bool Registry::Replay(llvm::StringRef buffer) {
46#ifndef LLDB_REPRO_INSTR_TRACE
47  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API);
48#endif
49
50  Deserializer deserializer(buffer);
51  while (deserializer.HasData(1)) {
52    unsigned id = deserializer.Deserialize<unsigned>();
53
54#ifndef LLDB_REPRO_INSTR_TRACE
55    LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id));
56#else
57    llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
58#endif
59
60    GetReplayer(id)->operator()(deserializer);
61  }
62
63  return true;
64}
65
66void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
67                          SignatureStr signature) {
68  const unsigned id = m_replayers.size() + 1;
69  assert(m_replayers.find(RunID) == m_replayers.end());
70  m_replayers[RunID] = std::make_pair(std::move(replayer), id);
71  m_ids[id] =
72      std::make_pair(m_replayers[RunID].first.get(), std::move(signature));
73}
74
75unsigned Registry::GetID(uintptr_t addr) {
76  unsigned id = m_replayers[addr].second;
77  assert(id != 0 && "Forgot to add function to registry?");
78  return id;
79}
80
81std::string Registry::GetSignature(unsigned id) {
82  assert(m_ids.count(id) != 0 && "ID not in registry");
83  return m_ids[id].second.ToString();
84}
85
86Replayer *Registry::GetReplayer(unsigned id) {
87  assert(m_ids.count(id) != 0 && "ID not in registry");
88  return m_ids[id].first;
89}
90
91std::string Registry::SignatureStr::ToString() const {
92  return (result + (result.empty() ? "" : " ") + scope + "::" + name + args)
93      .str();
94}
95
96unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {
97  unsigned index = m_mapping.size() + 1;
98  auto it = m_mapping.find(object);
99  if (it == m_mapping.end())
100    m_mapping[object] = index;
101  return m_mapping[object];
102}
103
104Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args)
105    : m_serializer(nullptr), m_pretty_func(pretty_func),
106      m_pretty_args(pretty_args), m_local_boundary(false),
107      m_result_recorded(true) {
108  if (!g_global_boundary) {
109    g_global_boundary = true;
110    m_local_boundary = true;
111
112    LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})",
113             m_pretty_func, m_pretty_args);
114  }
115}
116
117Recorder::~Recorder() {
118  assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?");
119  UpdateBoundary();
120}
121
122bool lldb_private::repro::Recorder::g_global_boundary;
123