1 //===- Minidump.cpp - Minidump object file implementation -----------------===//
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 #include "llvm/Object/Minidump.h"
10 #include "llvm/Object/Error.h"
11 #include "llvm/Support/ConvertUTF.h"
14 using namespace llvm::object
;
15 using namespace llvm::minidump
;
17 Optional
<ArrayRef
<uint8_t>>
18 MinidumpFile::getRawStream(minidump::StreamType Type
) const {
19 auto It
= StreamMap
.find(Type
);
20 if (It
!= StreamMap
.end())
21 return getRawStream(Streams
[It
->second
]);
25 Expected
<std::string
> MinidumpFile::getString(size_t Offset
) const {
26 // Minidump strings consist of a 32-bit length field, which gives the size of
27 // the string in *bytes*. This is followed by the actual string encoded in
30 getDataSliceAs
<support::ulittle32_t
>(getData(), Offset
, 1);
32 return ExpectedSize
.takeError();
33 size_t Size
= (*ExpectedSize
)[0];
35 return createError("String size not even");
40 Offset
+= sizeof(support::ulittle32_t
);
42 getDataSliceAs
<support::ulittle16_t
>(getData(), Offset
, Size
);
44 return ExpectedData
.takeError();
46 SmallVector
<UTF16
, 32> WStr(Size
);
47 copy(*ExpectedData
, WStr
.begin());
50 if (!convertUTF16ToUTF8String(WStr
, Result
))
51 return createError("String decoding failed");
57 Expected
<ArrayRef
<T
>> MinidumpFile::getListStream(StreamType Stream
) const {
58 auto OptionalStream
= getRawStream(Stream
);
60 return createError("No such stream");
62 getDataSliceAs
<support::ulittle32_t
>(*OptionalStream
, 0, 1);
64 return ExpectedSize
.takeError();
66 size_t ListSize
= ExpectedSize
.get()[0];
68 size_t ListOffset
= 4;
69 // Some producers insert additional padding bytes to align the list to an
70 // 8-byte boundary. Check for that by comparing the list size with the overall
72 if (ListOffset
+ sizeof(T
) * ListSize
< OptionalStream
->size())
75 return getDataSliceAs
<T
>(*OptionalStream
, ListOffset
, ListSize
);
77 template Expected
<ArrayRef
<Module
>>
78 MinidumpFile::getListStream(StreamType
) const;
79 template Expected
<ArrayRef
<Thread
>>
80 MinidumpFile::getListStream(StreamType
) const;
82 Expected
<ArrayRef
<uint8_t>>
83 MinidumpFile::getDataSlice(ArrayRef
<uint8_t> Data
, size_t Offset
, size_t Size
) {
84 // Check for overflow.
85 if (Offset
+ Size
< Offset
|| Offset
+ Size
< Size
||
86 Offset
+ Size
> Data
.size())
87 return createEOFError();
88 return Data
.slice(Offset
, Size
);
91 Expected
<std::unique_ptr
<MinidumpFile
>>
92 MinidumpFile::create(MemoryBufferRef Source
) {
93 ArrayRef
<uint8_t> Data
= arrayRefFromStringRef(Source
.getBuffer());
94 auto ExpectedHeader
= getDataSliceAs
<minidump::Header
>(Data
, 0, 1);
96 return ExpectedHeader
.takeError();
98 const minidump::Header
&Hdr
= (*ExpectedHeader
)[0];
99 if (Hdr
.Signature
!= Header::MagicSignature
)
100 return createError("Invalid signature");
101 if ((Hdr
.Version
& 0xffff) != Header::MagicVersion
)
102 return createError("Invalid version");
104 auto ExpectedStreams
= getDataSliceAs
<Directory
>(Data
, Hdr
.StreamDirectoryRVA
,
105 Hdr
.NumberOfStreams
);
106 if (!ExpectedStreams
)
107 return ExpectedStreams
.takeError();
109 DenseMap
<StreamType
, std::size_t> StreamMap
;
110 for (const auto &Stream
: llvm::enumerate(*ExpectedStreams
)) {
111 StreamType Type
= Stream
.value().Type
;
112 const LocationDescriptor
&Loc
= Stream
.value().Location
;
114 auto ExpectedStream
= getDataSlice(Data
, Loc
.RVA
, Loc
.DataSize
);
116 return ExpectedStream
.takeError();
118 if (Type
== StreamType::Unused
&& Loc
.DataSize
== 0) {
119 // Ignore dummy streams. This is technically ill-formed, but a number of
120 // existing minidumps seem to contain such streams.
124 if (Type
== DenseMapInfo
<StreamType
>::getEmptyKey() ||
125 Type
== DenseMapInfo
<StreamType
>::getTombstoneKey())
126 return createError("Cannot handle one of the minidump streams");
128 // Update the directory map, checking for duplicate stream types.
129 if (!StreamMap
.try_emplace(Type
, Stream
.index()).second
)
130 return createError("Duplicate stream type");
133 return std::unique_ptr
<MinidumpFile
>(
134 new MinidumpFile(Source
, Hdr
, *ExpectedStreams
, std::move(StreamMap
)));