[llvm] 3c36d8d - Introduce DWARFDataExtractor::getInitialLength
Pavel Labath via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 26 08:09:26 PST 2020
Author: Pavel Labath
Date: 2020-02-26T17:07:58+01:00
New Revision: 3c36d8dad57712f6616a197632e754541e71edf4
URL: https://github.com/llvm/llvm-project/commit/3c36d8dad57712f6616a197632e754541e71edf4
DIFF: https://github.com/llvm/llvm-project/commit/3c36d8dad57712f6616a197632e754541e71edf4.diff
LOG: Introduce DWARFDataExtractor::getInitialLength
Summary:
This patch introduces a function to house the code needed to do the
DWARF64 detection dance. The function decodes the initial length field
and returns it as a pair containing the actual length, and the DWARF
encoding.
This patch does _not_ attempt to handle the problem of detecting lengths
which extend past the size of the section, or cases when reads of a
single contribution accidentally escape beyond its specified length, but
I think it's useful in its own right.
Reviewers: dblaikie, jhenderson, ikudrin
Subscribers: hiraditya, probinson, aprantl, JDevlieghere, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D74560
Added:
llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
Modified:
llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
index c4ba982ce808..1e5ed09b57b3 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
@@ -9,6 +9,7 @@
#ifndef LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H
#define LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/Support/DataExtractor.h"
@@ -38,11 +39,27 @@ class DWARFDataExtractor : public DataExtractor {
StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()),
IsLittleEndian, AddressSize) {}
+ /// Extracts the DWARF "initial length" field, which can either be a 32-bit
+ /// value smaller than 0xfffffff0, or the value 0xffffffff followed by a
+ /// 64-bit length. Returns the actual length, and the DWARF format which is
+ /// encoded in the field. In case of errors, it returns {0, DWARF32} and
+ /// leaves the offset unchanged.
+ std::pair<uint64_t, dwarf::DwarfFormat>
+ getInitialLength(uint64_t *Off, Error *Err = nullptr) const;
+
+ std::pair<uint64_t, dwarf::DwarfFormat> getInitialLength(Cursor &C) const {
+ return getInitialLength(&getOffset(C), &getError(C));
+ }
+
/// Extracts a value and applies a relocation to the result if
/// one exists for the given offset.
uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
uint64_t *SectionIndex = nullptr,
Error *Err = nullptr) const;
+ uint64_t getRelocatedValue(Cursor &C, uint32_t Size,
+ uint64_t *SectionIndex = nullptr) const {
+ return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C));
+ }
/// Extracts an address-sized value and applies a relocation to the result if
/// one exists for the given offset.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
index 53e676bc7031..18b86b28ccab 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
@@ -7,11 +7,42 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
-#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
using namespace llvm;
+std::pair<uint64_t, dwarf::DwarfFormat>
+DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const {
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (Err && *Err)
+ return {0, dwarf::DWARF32};
+
+ Cursor C(*Off);
+ uint64_t Length = getRelocatedValue(C, 4);
+ dwarf::DwarfFormat Format = dwarf::DWARF32;
+ if (Length == dwarf::DW_LENGTH_DWARF64) {
+ Length = getRelocatedValue(C, 8);
+ Format = dwarf::DWARF64;
+ } else if (Length >= dwarf::DW_LENGTH_lo_reserved) {
+ cantFail(C.takeError());
+ if (Err)
+ *Err = createStringError(
+ errc::invalid_argument,
+ "unsupported reserved unit length of value 0x%8.8" PRIx64, Length);
+ return {0, dwarf::DWARF32};
+ }
+
+ if (C) {
+ *Off = C.tell();
+ return {Length, Format};
+ }
+ if (Err)
+ *Err = C.takeError();
+ else
+ consumeError(C.takeError());
+ return {0, dwarf::DWARF32};
+}
+
uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off,
uint64_t *SecNdx,
Error *Err) const {
diff --git a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
index 68d7840b6e6d..bb032314aaa3 100644
--- a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_unittest(DebugInfoDWARFTests
DwarfGenerator.cpp
DwarfUtils.cpp
DWARFAcceleratorTableTest.cpp
+ DWARFDataExtractorTest.cpp
DWARFDebugArangeSetTest.cpp
DWARFDebugInfoTest.cpp
DWARFDebugLineTest.cpp
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
new file mode 100644
index 000000000000..589ae3ff12b1
--- /dev/null
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
@@ -0,0 +1,95 @@
+//===- DWARFDataExtractorTest.cpp -----------------------------------------===//
+//
+// 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/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(DWARFDataExtractorTest, getInitialLength) {
+ auto GetWithError = [](ArrayRef<uint8_t> Bytes)
+ -> Expected<std::tuple<uint64_t, dwarf::DwarfFormat, uint64_t>> {
+ DWARFDataExtractor Data(Bytes, /*IsLittleEndian=*/false, /*AddressSize=*/8);
+ DWARFDataExtractor::Cursor C(0);
+ uint64_t Length;
+ dwarf::DwarfFormat Format;
+ std::tie(Length, Format) = Data.getInitialLength(C);
+ if (C)
+ return std::make_tuple(Length, Format, C.tell());
+
+ EXPECT_EQ(Length, 0u);
+ EXPECT_EQ(Format, dwarf::DWARF32);
+ EXPECT_EQ(C.tell(), 0u);
+ return C.takeError();
+ };
+ auto GetWithoutError = [](ArrayRef<uint8_t> Bytes) {
+ DWARFDataExtractor Data(Bytes, /*IsLittleEndian=*/false, /*AddressSize=*/8);
+ uint64_t Offset = 0;
+ uint64_t Length;
+ dwarf::DwarfFormat Format;
+ std::tie(Length, Format) = Data.getInitialLength(&Offset);
+ return std::make_tuple(Length, Format, Offset);
+ };
+ auto ErrorResult = std::make_tuple(0, dwarf::DWARF32, 0);
+
+ // Empty data.
+ EXPECT_THAT_EXPECTED(GetWithError({}),
+ FailedWithMessage("unexpected end of data"));
+ EXPECT_EQ(GetWithoutError({}), ErrorResult);
+
+ // Not long enough for the U32 field.
+ EXPECT_THAT_EXPECTED(GetWithError({0x00, 0x01, 0x02}),
+ FailedWithMessage("unexpected end of data"));
+ EXPECT_EQ(GetWithoutError({0x00, 0x01, 0x02}), ErrorResult);
+
+ EXPECT_THAT_EXPECTED(
+ GetWithError({0x00, 0x01, 0x02, 0x03}),
+ HasValue(std::make_tuple(0x00010203, dwarf::DWARF32, 4)));
+ EXPECT_EQ(GetWithoutError({0x00, 0x01, 0x02, 0x03}),
+ std::make_tuple(0x00010203, dwarf::DWARF32, 4));
+
+ // Zeroes are not an error, but without the Error object it is hard to tell
+ // them apart from a failed read.
+ EXPECT_THAT_EXPECTED(
+ GetWithError({0x00, 0x00, 0x00, 0x00}),
+ HasValue(std::make_tuple(0x00000000, dwarf::DWARF32, 4)));
+ EXPECT_EQ(GetWithoutError({0x00, 0x00, 0x00, 0x00}),
+ std::make_tuple(0x00000000, dwarf::DWARF32, 4));
+
+ // Smallest invalid value.
+ EXPECT_THAT_EXPECTED(
+ GetWithError({0xff, 0xff, 0xff, 0xf0}),
+ FailedWithMessage(
+ "unsupported reserved unit length of value 0xfffffff0"));
+ EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xf0}), ErrorResult);
+
+ // DWARF64 marker without the subsequent length field.
+ EXPECT_THAT_EXPECTED(GetWithError({0xff, 0xff, 0xff, 0xff}),
+ FailedWithMessage("unexpected end of data"));
+ EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff}), ErrorResult);
+
+ // Not enough data for the U64 length.
+ EXPECT_THAT_EXPECTED(
+ GetWithError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}),
+ FailedWithMessage("unexpected end of data"));
+ EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}),
+ ErrorResult);
+
+ EXPECT_THAT_EXPECTED(
+ GetWithError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07}),
+ HasValue(std::make_tuple(0x0001020304050607, dwarf::DWARF64, 12)));
+ EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07}),
+ std::make_tuple(0x0001020304050607, dwarf::DWARF64, 12));
+}
+
+} // namespace
More information about the llvm-commits
mailing list