1 //===- Minidump.h - Minidump object file implementation ---------*- 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 #ifndef LLVM_OBJECT_MINIDUMP_H 10 #define LLVM_OBJECT_MINIDUMP_H 11 12 #include "llvm/ADT/DenseMap.h" 13 #include "llvm/ADT/StringExtras.h" 14 #include "llvm/ADT/iterator.h" 15 #include "llvm/BinaryFormat/Minidump.h" 16 #include "llvm/Object/Binary.h" 17 #include "llvm/Support/Error.h" 18 19 namespace llvm { 20 namespace object { 21 22 /// A class providing access to the contents of a minidump file. 23 class MinidumpFile : public Binary { 24 public: 25 /// Construct a new MinidumpFile object from the given memory buffer. Returns 26 /// an error if this file cannot be identified as a minidump file, or if its 27 /// contents are badly corrupted (i.e. we cannot read the stream directory). 28 static Expected<std::unique_ptr<MinidumpFile>> create(MemoryBufferRef Source); 29 30 static bool classof(const Binary *B) { return B->isMinidump(); } 31 32 /// Returns the contents of the minidump header. 33 const minidump::Header &header() const { return Header; } 34 35 /// Returns the list of streams (stream directory entries) in this file. 36 ArrayRef<minidump::Directory> streams() const { return Streams; } 37 38 /// Returns the raw contents of the stream given by the directory entry. 39 ArrayRef<uint8_t> getRawStream(const minidump::Directory &Stream) const { 40 return getData().slice(Stream.Location.RVA, Stream.Location.DataSize); 41 } 42 43 /// Returns the raw contents of the stream of the given type, or None if the 44 /// file does not contain a stream of this type. 45 Optional<ArrayRef<uint8_t>> getRawStream(minidump::StreamType Type) const; 46 47 /// Returns the raw contents of an object given by the LocationDescriptor. An 48 /// error is returned if the descriptor points outside of the minidump file. 49 Expected<ArrayRef<uint8_t>> 50 getRawData(minidump::LocationDescriptor Desc) const { 51 return getDataSlice(getData(), Desc.RVA, Desc.DataSize); 52 } 53 54 /// Returns the minidump string at the given offset. An error is returned if 55 /// we fail to parse the string, or the string is invalid UTF16. 56 Expected<std::string> getString(size_t Offset) const; 57 58 /// Returns the contents of the SystemInfo stream, cast to the appropriate 59 /// type. An error is returned if the file does not contain this stream, or 60 /// the stream is smaller than the size of the SystemInfo structure. The 61 /// internal consistency of the stream is not checked in any way. 62 Expected<const minidump::SystemInfo &> getSystemInfo() const { 63 return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo); 64 } 65 66 /// Returns the module list embedded in the ModuleList stream. An error is 67 /// returned if the file does not contain this stream, or if the stream is 68 /// not large enough to contain the number of modules declared in the stream 69 /// header. The consistency of the Module entries themselves is not checked in 70 /// any way. 71 Expected<ArrayRef<minidump::Module>> getModuleList() const { 72 return getListStream<minidump::Module>(minidump::StreamType::ModuleList); 73 } 74 75 /// Returns the thread list embedded in the ThreadList stream. An error is 76 /// returned if the file does not contain this stream, or if the stream is 77 /// not large enough to contain the number of threads declared in the stream 78 /// header. The consistency of the Thread entries themselves is not checked in 79 /// any way. 80 Expected<ArrayRef<minidump::Thread>> getThreadList() const { 81 return getListStream<minidump::Thread>(minidump::StreamType::ThreadList); 82 } 83 84 /// Returns the contents of the Exception stream. An error is returned if the 85 /// file does not contain this stream, or the stream is smaller than the size 86 /// of the ExceptionStream structure. The internal consistency of the stream 87 /// is not checked in any way. 88 Expected<const minidump::ExceptionStream &> getExceptionStream() const { 89 return getStream<minidump::ExceptionStream>( 90 minidump::StreamType::Exception); 91 } 92 93 /// Returns the list of descriptors embedded in the MemoryList stream. The 94 /// descriptors provide the content of interesting regions of memory at the 95 /// time the minidump was taken. An error is returned if the file does not 96 /// contain this stream, or if the stream is not large enough to contain the 97 /// number of memory descriptors declared in the stream header. The 98 /// consistency of the MemoryDescriptor entries themselves is not checked in 99 /// any way. 100 Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const { 101 return getListStream<minidump::MemoryDescriptor>( 102 minidump::StreamType::MemoryList); 103 } 104 105 class MemoryInfoIterator 106 : public iterator_facade_base<MemoryInfoIterator, 107 std::forward_iterator_tag, 108 minidump::MemoryInfo> { 109 public: 110 MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride) 111 : Storage(Storage), Stride(Stride) { 112 assert(Storage.size() % Stride == 0); 113 } 114 115 bool operator==(const MemoryInfoIterator &R) const { 116 return Storage.size() == R.Storage.size(); 117 } 118 119 const minidump::MemoryInfo &operator*() const { 120 assert(Storage.size() >= sizeof(minidump::MemoryInfo)); 121 return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data()); 122 } 123 124 MemoryInfoIterator &operator++() { 125 Storage = Storage.drop_front(Stride); 126 return *this; 127 } 128 129 private: 130 ArrayRef<uint8_t> Storage; 131 size_t Stride; 132 }; 133 134 /// Returns the list of descriptors embedded in the MemoryInfoList stream. The 135 /// descriptors provide properties (e.g. permissions) of interesting regions 136 /// of memory at the time the minidump was taken. An error is returned if the 137 /// file does not contain this stream, or if the stream is not large enough to 138 /// contain the number of memory descriptors declared in the stream header. 139 /// The consistency of the MemoryInfoList entries themselves is not checked 140 /// in any way. 141 Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const; 142 143 private: 144 static Error createError(StringRef Str) { 145 return make_error<GenericBinaryError>(Str, object_error::parse_failed); 146 } 147 148 static Error createEOFError() { 149 return make_error<GenericBinaryError>("Unexpected EOF", 150 object_error::unexpected_eof); 151 } 152 153 /// Return a slice of the given data array, with bounds checking. 154 static Expected<ArrayRef<uint8_t>> getDataSlice(ArrayRef<uint8_t> Data, 155 size_t Offset, size_t Size); 156 157 /// Return the slice of the given data array as an array of objects of the 158 /// given type. The function checks that the input array is large enough to 159 /// contain the correct number of objects of the given type. 160 template <typename T> 161 static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data, 162 size_t Offset, size_t Count); 163 164 MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header, 165 ArrayRef<minidump::Directory> Streams, 166 DenseMap<minidump::StreamType, std::size_t> StreamMap) 167 : Binary(ID_Minidump, Source), Header(Header), Streams(Streams), 168 StreamMap(std::move(StreamMap)) {} 169 170 ArrayRef<uint8_t> getData() const { 171 return arrayRefFromStringRef(Data.getBuffer()); 172 } 173 174 /// Return the stream of the given type, cast to the appropriate type. Checks 175 /// that the stream is large enough to hold an object of this type. 176 template <typename T> 177 Expected<const T &> getStream(minidump::StreamType Stream) const; 178 179 /// Return the contents of a stream which contains a list of fixed-size items, 180 /// prefixed by the list size. 181 template <typename T> 182 Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const; 183 184 const minidump::Header &Header; 185 ArrayRef<minidump::Directory> Streams; 186 DenseMap<minidump::StreamType, std::size_t> StreamMap; 187 }; 188 189 template <typename T> 190 Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const { 191 if (Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) { 192 if (Stream->size() >= sizeof(T)) 193 return *reinterpret_cast<const T *>(Stream->data()); 194 return createEOFError(); 195 } 196 return createError("No such stream"); 197 } 198 199 template <typename T> 200 Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data, 201 size_t Offset, 202 size_t Count) { 203 // Check for overflow. 204 if (Count > std::numeric_limits<size_t>::max() / sizeof(T)) 205 return createEOFError(); 206 Expected<ArrayRef<uint8_t>> Slice = 207 getDataSlice(Data, Offset, sizeof(T) * Count); 208 if (!Slice) 209 return Slice.takeError(); 210 return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count); 211 } 212 213 } // end namespace object 214 } // end namespace llvm 215 216 #endif // LLVM_OBJECT_MINIDUMP_H 217