llvm-project

Форк
0
310 строк · 9.8 Кб
1
//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
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 "DebugMap.h"
10
#include "BinaryHolder.h"
11
#include "llvm/ADT/SmallString.h"
12
#include "llvm/ADT/StringMap.h"
13
#include "llvm/ADT/StringRef.h"
14
#include "llvm/BinaryFormat/MachO.h"
15
#include "llvm/Object/ObjectFile.h"
16
#include "llvm/Support/Chrono.h"
17
#include "llvm/Support/Error.h"
18
#include "llvm/Support/Format.h"
19
#include "llvm/Support/MemoryBuffer.h"
20
#include "llvm/Support/Path.h"
21
#include "llvm/Support/WithColor.h"
22
#include "llvm/Support/YAMLTraits.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include "llvm/TargetParser/Triple.h"
25
#include <algorithm>
26
#include <cinttypes>
27
#include <cstdint>
28
#include <memory>
29
#include <optional>
30
#include <string>
31
#include <utility>
32
#include <vector>
33

34
namespace llvm {
35

36
namespace dsymutil {
37

38
using namespace llvm::object;
39

40
DebugMapObject::DebugMapObject(StringRef ObjectFilename,
41
                               sys::TimePoint<std::chrono::seconds> Timestamp,
42
                               uint8_t Type)
43
    : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
44

45
bool DebugMapObject::addSymbol(StringRef Name,
46
                               std::optional<uint64_t> ObjectAddress,
47
                               uint64_t LinkedAddress, uint32_t Size) {
48
  if (Symbols.count(Name)) {
49
    // Symbol was previously added.
50
    return true;
51
  }
52

53
  auto InsertResult = Symbols.insert(
54
      std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
55

56
  if (ObjectAddress && InsertResult.second)
57
    AddressToMapping[*ObjectAddress] = &*InsertResult.first;
58
  return InsertResult.second;
59
}
60

61
void DebugMapObject::setRelocationMap(dsymutil::RelocationMap &RM) {
62
  RelocMap.emplace(RM);
63
}
64

65
void DebugMapObject::setInstallName(StringRef IN) { InstallName.emplace(IN); }
66

67
void DebugMapObject::print(raw_ostream &OS) const {
68
  OS << getObjectFilename() << ":\n";
69
  // Sort the symbols in alphabetical order, like llvm-nm (and to get
70
  // deterministic output for testing).
71
  using Entry = std::pair<StringRef, SymbolMapping>;
72
  std::vector<Entry> Entries;
73
  Entries.reserve(Symbols.getNumItems());
74
  for (const auto &Sym : Symbols)
75
    Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
76
  llvm::sort(Entries, llvm::less_first());
77
  for (const auto &Sym : Entries) {
78
    if (Sym.second.ObjectAddress)
79
      OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
80
    else
81
      OS << "\t????????????????";
82
    OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
83
                 uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
84
                 Sym.first.data());
85
  }
86
  OS << '\n';
87
}
88

89
#ifndef NDEBUG
90
void DebugMapObject::dump() const { print(errs()); }
91
#endif
92

93
DebugMapObject &
94
DebugMap::addDebugMapObject(StringRef ObjectFilePath,
95
                            sys::TimePoint<std::chrono::seconds> Timestamp,
96
                            uint8_t Type) {
97
  Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
98
  return *Objects.back();
99
}
100

101
const DebugMapObject::DebugMapEntry *
102
DebugMapObject::lookupSymbol(StringRef SymbolName) const {
103
  StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
104
  if (Sym == Symbols.end())
105
    return nullptr;
106
  return &*Sym;
107
}
108

109
const DebugMapObject::DebugMapEntry *
110
DebugMapObject::lookupObjectAddress(uint64_t Address) const {
111
  auto Mapping = AddressToMapping.find(Address);
112
  if (Mapping == AddressToMapping.end())
113
    return nullptr;
114
  return Mapping->getSecond();
115
}
116

117
void DebugMap::print(raw_ostream &OS) const {
118
  yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
119
  yout << const_cast<DebugMap &>(*this);
120
}
121

122
#ifndef NDEBUG
123
void DebugMap::dump() const { print(errs()); }
124
#endif
125

126
namespace {
127

128
struct YAMLContext {
129
  StringRef PrependPath;
130
  Triple BinaryTriple;
131
};
132

133
} // end anonymous namespace
134

135
ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
136
DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
137
                            bool Verbose) {
138
  auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
139
  if (auto Err = ErrOrFile.getError())
140
    return Err;
141

142
  YAMLContext Ctxt;
143

144
  Ctxt.PrependPath = PrependPath;
145

146
  std::unique_ptr<DebugMap> Res;
147
  yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
148
  yin >> Res;
149

150
  if (auto EC = yin.error())
151
    return EC;
152
  std::vector<std::unique_ptr<DebugMap>> Result;
153
  Result.push_back(std::move(Res));
154
  return std::move(Result);
155
}
156

157
} // end namespace dsymutil
158

159
namespace yaml {
160

161
// Normalize/Denormalize between YAML and a DebugMapObject.
162
struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
163
  YamlDMO(IO &io) { Timestamp = 0; }
164
  YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
165
  dsymutil::DebugMapObject denormalize(IO &IO);
166

167
  std::string Filename;
168
  int64_t Timestamp;
169
  std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
170
};
171

172
void MappingTraits<std::pair<std::string, SymbolMapping>>::mapping(
173
    IO &io, std::pair<std::string, SymbolMapping> &s) {
174
  io.mapRequired("sym", s.first);
175
  io.mapOptional("objAddr", s.second.ObjectAddress);
176
  io.mapRequired("binAddr", s.second.BinaryAddress);
177
  io.mapOptional("size", s.second.Size);
178
}
179

180
void MappingTraits<dsymutil::DebugMapObject>::mapping(
181
    IO &io, dsymutil::DebugMapObject &DMO) {
182
  MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
183
  io.mapRequired("filename", Norm->Filename);
184
  io.mapOptional("timestamp", Norm->Timestamp);
185
  io.mapRequired("symbols", Norm->Entries);
186
}
187

188
void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {
189
  out << val.str();
190
}
191

192
StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
193
  value = Triple(scalar);
194
  return StringRef();
195
}
196

197
size_t
198
SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
199
    IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
200
  return seq.size();
201
}
202

203
dsymutil::DebugMapObject &
204
SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
205
    IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
206
    size_t index) {
207
  if (index >= seq.size()) {
208
    seq.resize(index + 1);
209
    seq[index].reset(new dsymutil::DebugMapObject);
210
  }
211
  return *seq[index];
212
}
213

214
void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
215
                                                dsymutil::DebugMap &DM) {
216
  io.mapRequired("triple", DM.BinaryTriple);
217
  io.mapOptional("binary-path", DM.BinaryPath);
218
  if (void *Ctxt = io.getContext())
219
    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
220
  io.mapOptional("objects", DM.Objects);
221
}
222

223
void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
224
    IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
225
  if (!DM)
226
    DM.reset(new DebugMap());
227
  io.mapRequired("triple", DM->BinaryTriple);
228
  io.mapOptional("binary-path", DM->BinaryPath);
229
  if (void *Ctxt = io.getContext())
230
    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
231
  io.mapOptional("objects", DM->Objects);
232
}
233

234
MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
235
    IO &io, dsymutil::DebugMapObject &Obj) {
236
  Filename = Obj.Filename;
237
  Timestamp = sys::toTimeT(Obj.getTimestamp());
238
  Entries.reserve(Obj.Symbols.size());
239
  for (auto &Entry : Obj.Symbols)
240
    Entries.push_back(
241
        std::make_pair(std::string(Entry.getKey()), Entry.getValue()));
242
  llvm::sort(Entries, llvm::less_first());
243
}
244

245
dsymutil::DebugMapObject
246
MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
247
  BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
248
  const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
249
  SmallString<80> Path(Ctxt.PrependPath);
250
  StringMap<uint64_t> SymbolAddresses;
251

252
  sys::path::append(Path, Filename);
253

254
  auto ObjectEntry = BinHolder.getObjectEntry(Path);
255
  if (!ObjectEntry) {
256
    auto Err = ObjectEntry.takeError();
257
    WithColor::warning() << "Unable to open " << Path << " "
258
                         << toString(std::move(Err)) << '\n';
259
  } else {
260
    auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);
261
    if (!Object) {
262
      auto Err = Object.takeError();
263
      WithColor::warning() << "Unable to open " << Path << " "
264
                           << toString(std::move(Err)) << '\n';
265
    } else {
266
      for (const auto &Sym : Object->symbols()) {
267
        Expected<uint64_t> AddressOrErr = Sym.getValue();
268
        if (!AddressOrErr) {
269
          // TODO: Actually report errors helpfully.
270
          consumeError(AddressOrErr.takeError());
271
          continue;
272
        }
273
        Expected<StringRef> Name = Sym.getName();
274
        Expected<uint32_t> FlagsOrErr = Sym.getFlags();
275
        if (!Name || !FlagsOrErr ||
276
            (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
277
          // TODO: Actually report errors helpfully.
278
          if (!FlagsOrErr)
279
            consumeError(FlagsOrErr.takeError());
280
          if (!Name)
281
            consumeError(Name.takeError());
282
          continue;
283
        }
284
        SymbolAddresses[*Name] = *AddressOrErr;
285
      }
286
    }
287
  }
288

289
  uint8_t Type = MachO::N_OSO;
290
  if (Path.ends_with(".dylib")) {
291
    // FIXME: find a more resilient way
292
    Type = MachO::N_LIB;
293
  }
294
  dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), Type);
295

296
  for (auto &Entry : Entries) {
297
    auto &Mapping = Entry.second;
298
    std::optional<uint64_t> ObjAddress;
299
    if (Mapping.ObjectAddress)
300
      ObjAddress = *Mapping.ObjectAddress;
301
    auto AddressIt = SymbolAddresses.find(Entry.first);
302
    if (AddressIt != SymbolAddresses.end())
303
      ObjAddress = AddressIt->getValue();
304
    Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
305
  }
306
  return Res;
307
}
308

309
} // end namespace yaml
310
} // end namespace llvm
311

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.