blob: d0d49b4e8d33d580328f8cb82b0c02f74bd4dbe5 [file] [log] [blame]
Pavel Labath581d79a2019-03-21 09:18:59 +00001//===- Minidump.cpp - Minidump object file implementation -----------------===//
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#include "llvm/Object/Minidump.h"
10#include "llvm/Object/Error.h"
11
12using namespace llvm;
13using namespace llvm::object;
14using namespace llvm::minidump;
15
16Optional<ArrayRef<uint8_t>>
17MinidumpFile::getRawStream(minidump::StreamType Type) const {
18 auto It = StreamMap.find(Type);
19 if (It != StreamMap.end())
20 return getRawStream(Streams[It->second]);
21 return None;
22}
23
24Expected<ArrayRef<uint8_t>>
25MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
26 // Check for overflow.
27 if (Offset + Size < Offset || Offset + Size < Size ||
28 Offset + Size > Data.size())
29 return createEOFError();
30 return Data.slice(Offset, Size);
31}
32
33Expected<std::unique_ptr<MinidumpFile>>
34MinidumpFile::create(MemoryBufferRef Source) {
35 ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer());
36 auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1);
37 if (!ExpectedHeader)
38 return ExpectedHeader.takeError();
39
40 const minidump::Header &Hdr = (*ExpectedHeader)[0];
41 if (Hdr.Signature != Header::MagicSignature)
42 return createError("Invalid signature");
43 if ((Hdr.Version & 0xffff) != Header::MagicVersion)
44 return createError("Invalid version");
45
46 auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA,
47 Hdr.NumberOfStreams);
48 if (!ExpectedStreams)
49 return ExpectedStreams.takeError();
50
51 DenseMap<StreamType, std::size_t> StreamMap;
52 for (const auto &Stream : llvm::enumerate(*ExpectedStreams)) {
53 StreamType Type = Stream.value().Type;
54 const LocationDescriptor &Loc = Stream.value().Location;
55
56 auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize);
57 if (!ExpectedStream)
58 return ExpectedStream.takeError();
59
60 if (Type == StreamType::Unused && Loc.DataSize == 0) {
61 // Ignore dummy streams. This is technically ill-formed, but a number of
62 // existing minidumps seem to contain such streams.
63 continue;
64 }
65
66 if (Type == DenseMapInfo<StreamType>::getEmptyKey() ||
67 Type == DenseMapInfo<StreamType>::getTombstoneKey())
68 return createError("Cannot handle one of the minidump streams");
69
70 // Update the directory map, checking for duplicate stream types.
71 if (!StreamMap.try_emplace(Type, Stream.index()).second)
72 return createError("Duplicate stream type");
73 }
74
75 return std::unique_ptr<MinidumpFile>(
76 new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
77}