1111
1212#include " llvm/ADT/DenseMap.h"
1313#include " llvm/ADT/StringExtras.h"
14+ #include " llvm/ADT/fallible_iterator.h"
1415#include " llvm/ADT/iterator.h"
1516#include " llvm/BinaryFormat/Minidump.h"
1617#include " llvm/Object/Binary.h"
@@ -103,6 +104,13 @@ class MinidumpFile : public Binary {
103104 minidump::StreamType::MemoryList);
104105 }
105106
107+ // / Returns the header to the memory 64 list stream. An error is returned if
108+ // / the file does not contain this stream.
109+ Expected<minidump::Memory64ListHeader> getMemoryList64Header () const {
110+ return getStream<minidump::Memory64ListHeader>(
111+ minidump::StreamType::Memory64List);
112+ }
113+
106114 class MemoryInfoIterator
107115 : public iterator_facade_base<MemoryInfoIterator,
108116 std::forward_iterator_tag,
@@ -132,6 +140,90 @@ class MinidumpFile : public Binary {
132140 size_t Stride;
133141 };
134142
143+ // / Class the provides an iterator over the memory64 memory ranges. Only the
144+ // / the first descriptor is validated as readable beforehand.
145+ class Memory64Iterator {
146+ public:
147+ static Memory64Iterator
148+ begin (ArrayRef<uint8_t > Storage,
149+ ArrayRef<minidump::MemoryDescriptor_64> Descriptors) {
150+ return Memory64Iterator (Storage, Descriptors);
151+ }
152+
153+ static Memory64Iterator end () { return Memory64Iterator (); }
154+
155+ bool operator ==(const Memory64Iterator &R) const {
156+ return IsEnd == R.IsEnd ;
157+ }
158+
159+ bool operator !=(const Memory64Iterator &R) const { return !(*this == R); }
160+
161+ const std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t >> &
162+ operator *() {
163+ return Current;
164+ }
165+
166+ const std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t >> *
167+ operator ->() {
168+ return &Current;
169+ }
170+
171+ Error inc () {
172+ if (Descriptors.empty ()) {
173+ IsEnd = true ;
174+ return Error::success ();
175+ }
176+
177+ // Drop front gives us an array ref, so we need to call .front() as well.
178+ const minidump::MemoryDescriptor_64 &Descriptor = Descriptors.front ();
179+ if (Descriptor.DataSize > Storage.size ()) {
180+ IsEnd = true ;
181+ return make_error<GenericBinaryError>(
182+ " Memory64 Descriptor exceeds end of file." ,
183+ object_error::unexpected_eof);
184+ }
185+
186+ ArrayRef<uint8_t > Content = Storage.take_front (Descriptor.DataSize );
187+ Current = std::make_pair (Descriptor, Content);
188+
189+ Storage = Storage.drop_front (Descriptor.DataSize );
190+ Descriptors = Descriptors.drop_front ();
191+
192+ return Error::success ();
193+ }
194+
195+ private:
196+ // This constructor expects that the first descriptor is readable.
197+ Memory64Iterator (ArrayRef<uint8_t > Storage,
198+ ArrayRef<minidump::MemoryDescriptor_64> Descriptors)
199+ : Storage(Storage), Descriptors(Descriptors), IsEnd(false ) {
200+ assert (!Descriptors.empty () &&
201+ Storage.size () >= Descriptors.front ().DataSize );
202+ minidump::MemoryDescriptor_64 Descriptor = Descriptors.front ();
203+ ArrayRef<uint8_t > Content = Storage.take_front (Descriptor.DataSize );
204+ Current = std::make_pair (Descriptor, Content);
205+ this ->Descriptors = Descriptors.drop_front ();
206+ this ->Storage = Storage.drop_front (Descriptor.DataSize );
207+ }
208+
209+ Memory64Iterator ()
210+ : Storage(ArrayRef<uint8_t >()),
211+ Descriptors (ArrayRef<minidump::MemoryDescriptor_64>()), IsEnd(true ) {}
212+
213+ std::pair<minidump::MemoryDescriptor_64, ArrayRef<uint8_t >> Current;
214+ ArrayRef<uint8_t > Storage;
215+ ArrayRef<minidump::MemoryDescriptor_64> Descriptors;
216+ bool IsEnd;
217+ };
218+
219+ using FallibleMemory64Iterator = llvm::fallible_iterator<Memory64Iterator>;
220+
221+ // / Returns an iterator that pairs each descriptor with it's respective
222+ // / content from the Memory64List stream. An error is returned if the file
223+ // / does not contain a Memory64List stream, or if the descriptor data is
224+ // / unreadable.
225+ iterator_range<FallibleMemory64Iterator> getMemory64List (Error &Err) const ;
226+
135227 // / Returns the list of descriptors embedded in the MemoryInfoList stream. The
136228 // / descriptors provide properties (e.g. permissions) of interesting regions
137229 // / of memory at the time the minidump was taken. An error is returned if the
@@ -152,15 +244,15 @@ class MinidumpFile : public Binary {
152244 }
153245
154246 // / Return a slice of the given data array, with bounds checking.
155- static Expected<ArrayRef<uint8_t >> getDataSlice (ArrayRef< uint8_t > Data,
156- size_t Offset, size_t Size);
247+ static Expected<ArrayRef<uint8_t >>
248+ getDataSlice (ArrayRef< uint8_t > Data, uint64_t Offset, uint64_t Size);
157249
158250 // / Return the slice of the given data array as an array of objects of the
159251 // / given type. The function checks that the input array is large enough to
160252 // / contain the correct number of objects of the given type.
161253 template <typename T>
162254 static Expected<ArrayRef<T>> getDataSliceAs (ArrayRef<uint8_t > Data,
163- size_t Offset, size_t Count);
255+ uint64_t Offset, uint64_t Count);
164256
165257 MinidumpFile (MemoryBufferRef Source, const minidump::Header &Header,
166258 ArrayRef<minidump::Directory> Streams,
@@ -199,15 +291,16 @@ Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const {
199291
200292template <typename T>
201293Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs (ArrayRef<uint8_t > Data,
202- size_t Offset,
203- size_t Count) {
294+ uint64_t Offset,
295+ uint64_t Count) {
204296 // Check for overflow.
205- if (Count > std::numeric_limits<size_t >::max () / sizeof (T))
297+ if (Count > std::numeric_limits<uint64_t >::max () / sizeof (T))
206298 return createEOFError ();
207299 Expected<ArrayRef<uint8_t >> Slice =
208300 getDataSlice (Data, Offset, sizeof (T) * Count);
209301 if (!Slice)
210302 return Slice.takeError ();
303+
211304 return ArrayRef<T>(reinterpret_cast <const T *>(Slice->data ()), Count);
212305}
213306
0 commit comments