diff options
Diffstat (limited to 'llvm/lib/Object/Minidump.cpp')
-rw-r--r-- | llvm/lib/Object/Minidump.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/llvm/lib/Object/Minidump.cpp b/llvm/lib/Object/Minidump.cpp new file mode 100644 index 00000000000..d0d49b4e8d3 --- /dev/null +++ b/llvm/lib/Object/Minidump.cpp @@ -0,0 +1,77 @@ +//===- Minidump.cpp - Minidump object file implementation -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Minidump.h" +#include "llvm/Object/Error.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::minidump; + +Optional<ArrayRef<uint8_t>> +MinidumpFile::getRawStream(minidump::StreamType Type) const { + auto It = StreamMap.find(Type); + if (It != StreamMap.end()) + return getRawStream(Streams[It->second]); + return None; +} + +Expected<ArrayRef<uint8_t>> +MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) { + // Check for overflow. + if (Offset + Size < Offset || Offset + Size < Size || + Offset + Size > Data.size()) + return createEOFError(); + return Data.slice(Offset, Size); +} + +Expected<std::unique_ptr<MinidumpFile>> +MinidumpFile::create(MemoryBufferRef Source) { + ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer()); + auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1); + if (!ExpectedHeader) + return ExpectedHeader.takeError(); + + const minidump::Header &Hdr = (*ExpectedHeader)[0]; + if (Hdr.Signature != Header::MagicSignature) + return createError("Invalid signature"); + if ((Hdr.Version & 0xffff) != Header::MagicVersion) + return createError("Invalid version"); + + auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA, + Hdr.NumberOfStreams); + if (!ExpectedStreams) + return ExpectedStreams.takeError(); + + DenseMap<StreamType, std::size_t> StreamMap; + for (const auto &Stream : llvm::enumerate(*ExpectedStreams)) { + StreamType Type = Stream.value().Type; + const LocationDescriptor &Loc = Stream.value().Location; + + auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize); + if (!ExpectedStream) + return ExpectedStream.takeError(); + + if (Type == StreamType::Unused && Loc.DataSize == 0) { + // Ignore dummy streams. This is technically ill-formed, but a number of + // existing minidumps seem to contain such streams. + continue; + } + + if (Type == DenseMapInfo<StreamType>::getEmptyKey() || + Type == DenseMapInfo<StreamType>::getTombstoneKey()) + return createError("Cannot handle one of the minidump streams"); + + // Update the directory map, checking for duplicate stream types. + if (!StreamMap.try_emplace(Type, Stream.index()).second) + return createError("Duplicate stream type"); + } + + return std::unique_ptr<MinidumpFile>( + new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap))); +} |