mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-15 04:29:42 +00:00
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
This commit is contained in:
parent
07eb82fc06
commit
3c36d8dad5
@ -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 @@ public:
|
||||
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.
|
||||
|
@ -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 {
|
||||
|
@ -12,6 +12,7 @@ add_llvm_unittest(DebugInfoDWARFTests
|
||||
DwarfGenerator.cpp
|
||||
DwarfUtils.cpp
|
||||
DWARFAcceleratorTableTest.cpp
|
||||
DWARFDataExtractorTest.cpp
|
||||
DWARFDebugArangeSetTest.cpp
|
||||
DWARFDebugInfoTest.cpp
|
||||
DWARFDebugLineTest.cpp
|
||||
|
95
llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
Normal file
95
llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user