1 //===- Minidump.h - Minidump object file implementation ---------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_OBJECT_MINIDUMP_H
10 #define LLVM_OBJECT_MINIDUMP_H
12 #include "llvm/ADT/DenseMap.h"
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/BinaryFormat/Minidump.h"
15 #include "llvm/Object/Binary.h"
16 #include "llvm/Support/Error.h"
21 /// A class providing access to the contents of a minidump file.
22 class MinidumpFile
: public Binary
{
24 /// Construct a new MinidumpFile object from the given memory buffer. Returns
25 /// an error if this file cannot be identified as a minidump file, or if its
26 /// contents are badly corrupted (i.e. we cannot read the stream directory).
27 static Expected
<std::unique_ptr
<MinidumpFile
>> create(MemoryBufferRef Source
);
29 static bool classof(const Binary
*B
) { return B
->isMinidump(); }
31 /// Returns the contents of the minidump header.
32 const minidump::Header
&header() const { return Header
; }
34 /// Returns the list of streams (stream directory entries) in this file.
35 ArrayRef
<minidump::Directory
> streams() const { return Streams
; }
37 /// Returns the raw contents of the stream given by the directory entry.
38 ArrayRef
<uint8_t> getRawStream(const minidump::Directory
&Stream
) const {
39 return getData().slice(Stream
.Location
.RVA
, Stream
.Location
.DataSize
);
42 /// Returns the raw contents of the stream of the given type, or None if the
43 /// file does not contain a stream of this type.
44 Optional
<ArrayRef
<uint8_t>> getRawStream(minidump::StreamType Type
) const;
46 /// Returns the raw contents of an object given by the LocationDescriptor. An
47 /// error is returned if the descriptor points outside of the minidump file.
48 Expected
<ArrayRef
<uint8_t>>
49 getRawData(minidump::LocationDescriptor Desc
) const {
50 return getDataSlice(getData(), Desc
.RVA
, Desc
.DataSize
);
53 /// Returns the minidump string at the given offset. An error is returned if
54 /// we fail to parse the string, or the string is invalid UTF16.
55 Expected
<std::string
> getString(size_t Offset
) const;
57 /// Returns the contents of the SystemInfo stream, cast to the appropriate
58 /// type. An error is returned if the file does not contain this stream, or
59 /// the stream is smaller than the size of the SystemInfo structure. The
60 /// internal consistency of the stream is not checked in any way.
61 Expected
<const minidump::SystemInfo
&> getSystemInfo() const {
62 return getStream
<minidump::SystemInfo
>(minidump::StreamType::SystemInfo
);
65 /// Returns the module list embedded in the ModuleList stream. An error is
66 /// returned if the file does not contain this stream, or if the stream is
67 /// not large enough to contain the number of modules declared in the stream
68 /// header. The consistency of the Module entries themselves is not checked in
70 Expected
<ArrayRef
<minidump::Module
>> getModuleList() const {
71 return getListStream
<minidump::Module
>(minidump::StreamType::ModuleList
);
74 /// Returns the thread list embedded in the ThreadList stream. An error is
75 /// returned if the file does not contain this stream, or if the stream is
76 /// not large enough to contain the number of threads declared in the stream
77 /// header. The consistency of the Thread entries themselves is not checked in
79 Expected
<ArrayRef
<minidump::Thread
>> getThreadList() const {
80 return getListStream
<minidump::Thread
>(minidump::StreamType::ThreadList
);
83 /// Returns the list of memory ranges embedded in the MemoryList stream. An
84 /// error is returned if the file does not contain this stream, or if the
85 /// stream is not large enough to contain the number of memory descriptors
86 /// declared in the stream header. The consistency of the MemoryDescriptor
87 /// entries themselves is not checked in any way.
88 Expected
<ArrayRef
<minidump::MemoryDescriptor
>> getMemoryList() const {
89 return getListStream
<minidump::MemoryDescriptor
>(
90 minidump::StreamType::MemoryList
);
94 static Error
createError(StringRef Str
) {
95 return make_error
<GenericBinaryError
>(Str
, object_error::parse_failed
);
98 static Error
createEOFError() {
99 return make_error
<GenericBinaryError
>("Unexpected EOF",
100 object_error::unexpected_eof
);
103 /// Return a slice of the given data array, with bounds checking.
104 static Expected
<ArrayRef
<uint8_t>> getDataSlice(ArrayRef
<uint8_t> Data
,
105 size_t Offset
, size_t Size
);
107 /// Return the slice of the given data array as an array of objects of the
108 /// given type. The function checks that the input array is large enough to
109 /// contain the correct number of objects of the given type.
110 template <typename T
>
111 static Expected
<ArrayRef
<T
>> getDataSliceAs(ArrayRef
<uint8_t> Data
,
112 size_t Offset
, size_t Count
);
114 MinidumpFile(MemoryBufferRef Source
, const minidump::Header
&Header
,
115 ArrayRef
<minidump::Directory
> Streams
,
116 DenseMap
<minidump::StreamType
, std::size_t> StreamMap
)
117 : Binary(ID_Minidump
, Source
), Header(Header
), Streams(Streams
),
118 StreamMap(std::move(StreamMap
)) {}
120 ArrayRef
<uint8_t> getData() const {
121 return arrayRefFromStringRef(Data
.getBuffer());
124 /// Return the stream of the given type, cast to the appropriate type. Checks
125 /// that the stream is large enough to hold an object of this type.
126 template <typename T
>
127 Expected
<const T
&> getStream(minidump::StreamType Stream
) const;
129 /// Return the contents of a stream which contains a list of fixed-size items,
130 /// prefixed by the list size.
131 template <typename T
>
132 Expected
<ArrayRef
<T
>> getListStream(minidump::StreamType Stream
) const;
134 const minidump::Header
&Header
;
135 ArrayRef
<minidump::Directory
> Streams
;
136 DenseMap
<minidump::StreamType
, std::size_t> StreamMap
;
139 template <typename T
>
140 Expected
<const T
&> MinidumpFile::getStream(minidump::StreamType Stream
) const {
141 if (auto OptionalStream
= getRawStream(Stream
)) {
142 if (OptionalStream
->size() >= sizeof(T
))
143 return *reinterpret_cast<const T
*>(OptionalStream
->data());
144 return createEOFError();
146 return createError("No such stream");
149 template <typename T
>
150 Expected
<ArrayRef
<T
>> MinidumpFile::getDataSliceAs(ArrayRef
<uint8_t> Data
,
153 // Check for overflow.
154 if (Count
> std::numeric_limits
<size_t>::max() / sizeof(T
))
155 return createEOFError();
156 auto ExpectedArray
= getDataSlice(Data
, Offset
, sizeof(T
) * Count
);
158 return ExpectedArray
.takeError();
159 return ArrayRef
<T
>(reinterpret_cast<const T
*>(ExpectedArray
->data()), Count
);
162 } // end namespace object
163 } // end namespace llvm
165 #endif // LLVM_OBJECT_MINIDUMP_H