File indexing completed on 2026-05-10 08:44:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_OBJECT_MINIDUMP_H
0010 #define LLVM_OBJECT_MINIDUMP_H
0011
0012 #include "llvm/ADT/DenseMap.h"
0013 #include "llvm/ADT/StringExtras.h"
0014 #include "llvm/ADT/fallible_iterator.h"
0015 #include "llvm/ADT/iterator.h"
0016 #include "llvm/BinaryFormat/Minidump.h"
0017 #include "llvm/Object/Binary.h"
0018 #include "llvm/Support/Error.h"
0019
0020 namespace llvm {
0021 namespace object {
0022
0023
0024 class MinidumpFile : public Binary {
0025 public:
0026
0027
0028
0029 static Expected<std::unique_ptr<MinidumpFile>> create(MemoryBufferRef Source);
0030
0031 static bool classof(const Binary *B) { return B->isMinidump(); }
0032
0033
0034 const minidump::Header &header() const { return Header; }
0035
0036
0037 ArrayRef<minidump::Directory> streams() const { return Streams; }
0038
0039
0040 ArrayRef<uint8_t> getRawStream(const minidump::Directory &Stream) const {
0041 return getData().slice(Stream.Location.RVA, Stream.Location.DataSize);
0042 }
0043
0044
0045
0046 std::optional<ArrayRef<uint8_t>>
0047 getRawStream(minidump::StreamType Type) const;
0048
0049
0050
0051 Expected<ArrayRef<uint8_t>>
0052 getRawData(minidump::LocationDescriptor Desc) const {
0053 return getDataSlice(getData(), Desc.RVA, Desc.DataSize);
0054 }
0055
0056
0057
0058 Expected<std::string> getString(size_t Offset) const;
0059
0060
0061
0062
0063
0064 Expected<const minidump::SystemInfo &> getSystemInfo() const {
0065 return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo);
0066 }
0067
0068
0069
0070
0071
0072
0073 Expected<ArrayRef<minidump::Module>> getModuleList() const {
0074 return getListStream<minidump::Module>(minidump::StreamType::ModuleList);
0075 }
0076
0077
0078
0079
0080
0081
0082 Expected<ArrayRef<minidump::Thread>> getThreadList() const {
0083 return getListStream<minidump::Thread>(minidump::StreamType::ThreadList);
0084 }
0085
0086
0087
0088
0089 Expected<const minidump::ExceptionStream &>
0090 getExceptionStream(minidump::Directory Directory) const {
0091 if (Directory.Type != minidump::StreamType::Exception) {
0092 return createError("Not an exception stream");
0093 }
0094
0095 return getStreamFromDirectory<minidump::ExceptionStream>(Directory);
0096 }
0097
0098
0099
0100
0101 Expected<const minidump::ExceptionStream &> getExceptionStream() const {
0102 auto it = getExceptionStreams();
0103 if (it.begin() == it.end())
0104 return createError("No exception streams");
0105 return *it.begin();
0106 }
0107
0108
0109
0110
0111
0112
0113
0114
0115 Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const {
0116 return getListStream<minidump::MemoryDescriptor>(
0117 minidump::StreamType::MemoryList);
0118 }
0119
0120
0121
0122 Expected<minidump::Memory64ListHeader> getMemoryList64Header() const {
0123 return getStream<minidump::Memory64ListHeader>(
0124 minidump::StreamType::Memory64List);
0125 }
0126
0127 class MemoryInfoIterator
0128 : public iterator_facade_base<MemoryInfoIterator,
0129 std::forward_iterator_tag,
0130 minidump::MemoryInfo> {
0131 public:
0132 MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride)
0133 : Storage(Storage), Stride(Stride) {
0134 assert(Storage.size() % Stride == 0);
0135 }
0136
0137 bool operator==(const MemoryInfoIterator &R) const {
0138 return Storage.size() == R.Storage.size();
0139 }
0140
0141 const minidump::MemoryInfo &operator*() const {
0142 assert(Storage.size() >= sizeof(minidump::MemoryInfo));
0143 return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data());
0144 }
0145
0146 MemoryInfoIterator &operator++() {
0147 Storage = Storage.drop_front(Stride);
0148 return *this;
0149 }
0150
0151 private:
0152 ArrayRef<uint8_t> Storage;
0153 size_t Stride;
0154 };
0155
0156
0157
0158 class Memory64Iterator {
0159 public:
0160 static Memory64Iterator
0161 begin(ArrayRef<uint8_t> Storage,
0162 ArrayRef<minidump::MemoryDescriptor_64> Descriptors) {
0163 return Memory64Iterator(Storage, Descriptors);
0164 }
0165
0166 static Memory64Iterator end() { return Memory64Iterator(); }
0167
0168 bool operator==(const Memory64Iterator &R) const {
0169 return IsEnd == R.IsEnd;
0170 }
0171
0172 bool operator!=(const Memory64Iterator &R) const { return !(*this == R); }
0173
0174 const std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t>> &
0175 operator*() {
0176 return Current;
0177 }
0178
0179 const std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t>> *
0180 operator->() {
0181 return &Current;
0182 }
0183
0184 Error inc() {
0185 if (Descriptors.empty()) {
0186 IsEnd = true;
0187 return Error::success();
0188 }
0189
0190
0191 const minidump::MemoryDescriptor_64 &Descriptor = Descriptors.front();
0192 if (Descriptor.DataSize > Storage.size()) {
0193 IsEnd = true;
0194 return make_error<GenericBinaryError>(
0195 "Memory64 Descriptor exceeds end of file.",
0196 object_error::unexpected_eof);
0197 }
0198
0199 ArrayRef<uint8_t> Content = Storage.take_front(Descriptor.DataSize);
0200 Current = std::make_pair(Descriptor, Content);
0201
0202 Storage = Storage.drop_front(Descriptor.DataSize);
0203 Descriptors = Descriptors.drop_front();
0204
0205 return Error::success();
0206 }
0207
0208 private:
0209
0210 Memory64Iterator(ArrayRef<uint8_t> Storage,
0211 ArrayRef<minidump::MemoryDescriptor_64> Descriptors)
0212 : Storage(Storage), Descriptors(Descriptors), IsEnd(false) {
0213 assert(!Descriptors.empty() &&
0214 Storage.size() >= Descriptors.front().DataSize);
0215 minidump::MemoryDescriptor_64 Descriptor = Descriptors.front();
0216 ArrayRef<uint8_t> Content = Storage.take_front(Descriptor.DataSize);
0217 Current = std::make_pair(Descriptor, Content);
0218 this->Descriptors = Descriptors.drop_front();
0219 this->Storage = Storage.drop_front(Descriptor.DataSize);
0220 }
0221
0222 Memory64Iterator()
0223 : Storage(ArrayRef<uint8_t>()),
0224 Descriptors(ArrayRef<minidump::MemoryDescriptor_64>()), IsEnd(true) {}
0225
0226 std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t>> Current;
0227 ArrayRef<uint8_t> Storage;
0228 ArrayRef<minidump::MemoryDescriptor_64> Descriptors;
0229 bool IsEnd;
0230 };
0231
0232 class ExceptionStreamsIterator {
0233 public:
0234 ExceptionStreamsIterator(ArrayRef<minidump::Directory> Streams,
0235 const MinidumpFile *File)
0236 : Streams(Streams), File(File) {}
0237
0238 bool operator==(const ExceptionStreamsIterator &R) const {
0239 return Streams.size() == R.Streams.size();
0240 }
0241
0242 bool operator!=(const ExceptionStreamsIterator &R) const {
0243 return !(*this == R);
0244 }
0245
0246 Expected<const minidump::ExceptionStream &> operator*() {
0247 return File->getExceptionStream(Streams.front());
0248 }
0249
0250 ExceptionStreamsIterator &operator++() {
0251 if (!Streams.empty())
0252 Streams = Streams.drop_front();
0253
0254 return *this;
0255 }
0256
0257 private:
0258 ArrayRef<minidump::Directory> Streams;
0259 const MinidumpFile *File;
0260 };
0261
0262 using FallibleMemory64Iterator = llvm::fallible_iterator<Memory64Iterator>;
0263
0264
0265
0266
0267
0268 iterator_range<ExceptionStreamsIterator> getExceptionStreams() const;
0269
0270
0271
0272
0273
0274 iterator_range<FallibleMemory64Iterator> getMemory64List(Error &Err) const;
0275
0276
0277
0278
0279
0280
0281
0282
0283 Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const;
0284
0285 private:
0286 static Error createError(StringRef Str) {
0287 return make_error<GenericBinaryError>(Str, object_error::parse_failed);
0288 }
0289
0290 static Error createEOFError() {
0291 return make_error<GenericBinaryError>("Unexpected EOF",
0292 object_error::unexpected_eof);
0293 }
0294
0295
0296 static Expected<ArrayRef<uint8_t>>
0297 getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size);
0298
0299
0300
0301
0302 template <typename T>
0303 static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data,
0304 uint64_t Offset, uint64_t Count);
0305
0306 MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header,
0307 ArrayRef<minidump::Directory> Streams,
0308 DenseMap<minidump::StreamType, std::size_t> StreamMap,
0309 std::vector<minidump::Directory> ExceptionStreams)
0310 : Binary(ID_Minidump, Source), Header(Header), Streams(Streams),
0311 StreamMap(std::move(StreamMap)),
0312 ExceptionStreams(std::move(ExceptionStreams)) {}
0313
0314 ArrayRef<uint8_t> getData() const {
0315 return arrayRefFromStringRef(Data.getBuffer());
0316 }
0317
0318
0319
0320 template <typename T>
0321 Expected<const T &>
0322 getStreamFromDirectory(minidump::Directory Directory) const;
0323
0324
0325
0326 template <typename T>
0327 Expected<const T &> getStream(minidump::StreamType Stream) const;
0328
0329
0330
0331 template <typename T>
0332 Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const;
0333
0334 const minidump::Header &Header;
0335 ArrayRef<minidump::Directory> Streams;
0336 DenseMap<minidump::StreamType, std::size_t> StreamMap;
0337 std::vector<minidump::Directory> ExceptionStreams;
0338 };
0339
0340 template <typename T>
0341 Expected<const T &>
0342 MinidumpFile::getStreamFromDirectory(minidump::Directory Directory) const {
0343 ArrayRef<uint8_t> Stream = getRawStream(Directory);
0344 if (Stream.size() >= sizeof(T))
0345 return *reinterpret_cast<const T *>(Stream.data());
0346 return createEOFError();
0347 }
0348
0349 template <typename T>
0350 Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const {
0351 if (std::optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) {
0352 if (Stream->size() >= sizeof(T))
0353 return *reinterpret_cast<const T *>(Stream->data());
0354 return createEOFError();
0355 }
0356 return createError("No such stream");
0357 }
0358
0359 template <typename T>
0360 Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data,
0361 uint64_t Offset,
0362 uint64_t Count) {
0363
0364 if (Count > std::numeric_limits<uint64_t>::max() / sizeof(T))
0365 return createEOFError();
0366 Expected<ArrayRef<uint8_t>> Slice =
0367 getDataSlice(Data, Offset, sizeof(T) * Count);
0368 if (!Slice)
0369 return Slice.takeError();
0370
0371 return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count);
0372 }
0373
0374 template <typename T>
0375 Expected<ArrayRef<T>>
0376 MinidumpFile::getListStream(minidump::StreamType Type) const {
0377 std::optional<ArrayRef<uint8_t>> Stream = getRawStream(Type);
0378 if (!Stream)
0379 return createError("No such stream");
0380 auto ExpectedSize = getDataSliceAs<support::ulittle32_t>(*Stream, 0, 1);
0381 if (!ExpectedSize)
0382 return ExpectedSize.takeError();
0383
0384 size_t ListSize = ExpectedSize.get()[0];
0385
0386 size_t ListOffset = 4;
0387
0388
0389
0390 if (ListOffset + sizeof(T) * ListSize < Stream->size())
0391 ListOffset = 8;
0392
0393 return getDataSliceAs<T>(*Stream, ListOffset, ListSize);
0394 }
0395
0396 }
0397 }
0398
0399 #endif