diff options
| author | Zachary Turner <zturner@google.com> | 2016-05-12 17:45:44 +0000 |
|---|---|---|
| committer | Zachary Turner <zturner@google.com> | 2016-05-12 17:45:44 +0000 |
| commit | 38cc8b3f210ec8b90c85bd8a106da44439c2d651 (patch) | |
| tree | 3e9cb41b139d997d38600130c9a1bafcf4358458 /llvm/lib/DebugInfo/CodeView | |
| parent | a23b26f4665ef99942de1d809502f1ac6d872d53 (diff) | |
| download | bcm5719-llvm-38cc8b3f210ec8b90c85bd8a106da44439c2d651.tar.gz bcm5719-llvm-38cc8b3f210ec8b90c85bd8a106da44439c2d651.zip | |
Make CodeView record serialization more generic.
This introduces a variadic template and some helper macros to
safely and correctly deserialize many types of common record
fields while maintaining error checking.
Differential Revision: http://reviews.llvm.org/D20183
Reviewed By: rnk, amccarth
llvm-svn: 269315
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp | 157 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStream.cpp | 97 |
3 files changed, 158 insertions, 98 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 2be582f8c1a..cdca673474d 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -4,10 +4,10 @@ add_llvm_library(LLVMDebugInfoCodeView ListRecordBuilder.cpp MemoryTypeTableBuilder.cpp MethodListRecordBuilder.cpp + RecordSerialization.cpp TypeDumper.cpp TypeRecordBuilder.cpp TypeTableBuilder.cpp - TypeStream.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView diff --git a/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp b/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp new file mode 100644 index 00000000000..c142a01ef33 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp @@ -0,0 +1,157 @@ +//===-- RecordSerialization.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Utilities for serializing and deserializing CodeView records. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::support; + +/// Reinterpret a byte array as an array of characters. Does not interpret as +/// a C string, as StringRef has several helpers (split) that make that easy. +StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { + return StringRef(reinterpret_cast<const char *>(LeafData.data()), + LeafData.size()); +} + +StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { + return getBytesAsCharacters(LeafData).split('\0').first; +} + +std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) { + // Used to avoid overload ambiguity on APInt construtor. + bool FalseVal = false; + if (Data.size() < 2) + return std::make_error_code(std::errc::illegal_byte_sequence); + uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data()); + Data = Data.drop_front(2); + if (Short < LF_NUMERIC) { + Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), + /*isUnsigned=*/true); + return std::error_code(); + } + switch (Short) { + case LF_CHAR: + Num = APSInt(APInt(/*numBits=*/8, + *reinterpret_cast<const int8_t *>(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(1); + return std::error_code(); + case LF_SHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast<const little16_t *>(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(2); + return std::error_code(); + case LF_USHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast<const ulittle16_t *>(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(2); + return std::error_code(); + case LF_LONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast<const little32_t *>(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(4); + return std::error_code(); + case LF_ULONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast<const ulittle32_t *>(Data.data()), + /*isSigned=*/FalseVal), + /*isUnsigned=*/true); + Data = Data.drop_front(4); + return std::error_code(); + case LF_QUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast<const little64_t *>(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(8); + return std::error_code(); + case LF_UQUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast<const ulittle64_t *>(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(8); + return std::error_code(); + } + return std::make_error_code(std::errc::illegal_byte_sequence); +} + +std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) { + ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); + auto EC = consume(Bytes, Num); + Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); + return EC; +} + +/// Decode a numeric leaf value that is known to be a uint64_t. +std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data, + uint64_t &Num) { + APSInt N; + if (auto EC = consume(Data, N)) + return EC; + if (N.isSigned() || !N.isIntN(64)) + return std::make_error_code(std::errc::illegal_byte_sequence); + Num = N.getLimitedValue(); + return std::error_code(); +} + +std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, + uint32_t &Item) { + const support::ulittle32_t *IntPtr; + if (auto EC = consumeObject(Data, IntPtr)) + return EC; + Item = *IntPtr; + return std::error_code(); +} + +std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) { + ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); + auto EC = consume(Bytes, Item); + Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); + return EC; +} + +std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, + int32_t &Item) { + const support::little32_t *IntPtr; + if (auto EC = consumeObject(Data, IntPtr)) + return EC; + Item = *IntPtr; + return std::error_code(); +} + +std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, + StringRef &Item) { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + StringRef Rest; + std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0'); + // We expect this to be null terminated. If it was not, it is an error. + if (Data.size() == Item.size()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end()); + return std::error_code(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeStream.cpp b/llvm/lib/DebugInfo/CodeView/TypeStream.cpp deleted file mode 100644 index 82d3f4d7e86..00000000000 --- a/llvm/lib/DebugInfo/CodeView/TypeStream.cpp +++ /dev/null @@ -1,97 +0,0 @@ -//===-- TypeStream.cpp ----------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Utilities for parsing CodeView type streams. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::support; - -bool llvm::codeview::decodeNumericLeaf(ArrayRef<uint8_t> &Data, APSInt &Num) { - // Used to avoid overload ambiguity on APInt construtor. - bool FalseVal = false; - if (Data.size() < 2) - return false; - uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data()); - Data = Data.drop_front(2); - if (Short < LF_NUMERIC) { - Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), - /*isUnsigned=*/true); - return true; - } - switch (Short) { - case LF_CHAR: - Num = APSInt(APInt(/*numBits=*/8, - *reinterpret_cast<const int8_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(1); - return true; - case LF_SHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast<const little16_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(2); - return true; - case LF_USHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast<const ulittle16_t *>(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(2); - return true; - case LF_LONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast<const little32_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(4); - return true; - case LF_ULONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast<const ulittle32_t *>(Data.data()), - /*isSigned=*/FalseVal), - /*isUnsigned=*/true); - Data = Data.drop_front(4); - return true; - case LF_QUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast<const little64_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(8); - return true; - case LF_UQUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast<const ulittle64_t *>(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(8); - return true; - } - return false; -} - -/// Decode a numeric leaf value that is known to be a uint32_t. -bool llvm::codeview::decodeUIntLeaf(ArrayRef<uint8_t> &Data, uint64_t &Num) { - APSInt N; - if (!decodeNumericLeaf(Data, N)) - return false; - if (N.isSigned() || !N.isIntN(64)) - return false; - Num = N.getLimitedValue(); - return true; -} |

