Skip to content

Commit

Permalink
[DWARF] NFC: Collect info used by DWARFFormValue into a helper.
Browse files Browse the repository at this point in the history
Some forms have sizes that depend on the DWARF version, DWARF format
(32/64-bit), or the size of an address.  Collect these into a struct
to simplify passing them around.  Require callers to provide one when
they query a form's size.

Differential Revision: http://reviews.llvm.org/D34570


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306315 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
pogo59 committed Jun 26, 2017
1 parent b988cd6 commit fd770ea
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 255 deletions.
20 changes: 12 additions & 8 deletions include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/DataExtractor.h"
#include <cstdint>
Expand Down Expand Up @@ -43,10 +44,10 @@ class DWARFDebugLine {
/// The size in bytes of the statement information for this compilation unit
/// (not including the total_length field itself).
uint64_t TotalLength;
/// Version identifier for the statement information format.
uint16_t Version;
/// In v5, size in bytes of an address (or segment offset).
uint8_t AddressSize;
/// Version, address size (starting in v5), and DWARF32/64 format; these
/// parameters affect interpretation of forms (used in the directory and
/// file tables starting with v5).
DWARFFormParams FormParams;
/// In v5, size in bytes of a segment selector.
uint8_t SegSelectorSize;
/// The number of bytes following the prologue_length field to the beginning
Expand All @@ -71,15 +72,18 @@ class DWARFDebugLine {
std::vector<StringRef> IncludeDirectories;
std::vector<FileNameEntry> FileNames;

bool IsDWARF64;
const DWARFFormParams getFormParams() const { return FormParams; }
uint16_t getVersion() const { return FormParams.Version; }
uint8_t getAddressSize() const { return FormParams.AddrSize; }
bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; }

uint32_t sizeofTotalLength() const { return IsDWARF64 ? 12 : 4; }
uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; }

uint32_t sizeofPrologueLength() const { return IsDWARF64 ? 8 : 4; }
uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; }

/// Length of the prologue in bytes.
uint32_t getLength() const {
return PrologueLength + sizeofTotalLength() + sizeof(Version) +
return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) +
sizeofPrologueLength();
}

Expand Down
113 changes: 53 additions & 60 deletions include/llvm/DebugInfo/DWARF/DWARFFormValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ namespace llvm {
class DWARFUnit;
class raw_ostream;

/// A helper struct for DWARFFormValue methods, providing information that
/// allows it to know the byte size of DW_FORM values that vary in size
/// depending on the DWARF version, address byte size, or DWARF32/DWARF64.
struct DWARFFormParams {
uint16_t Version;
uint8_t AddrSize;
dwarf::DwarfFormat Format;

/// The definition of the size of form DW_FORM_ref_addr depends on the
/// version. In DWARF v2 it's the size of an address; after that, it's the
/// size of a reference.
uint8_t getRefAddrByteSize() const {
if (Version == 2)
return AddrSize;
return getDwarfOffsetByteSize();
}

/// The size of a reference is determined by the DWARF 32/64-bit format.
uint8_t getDwarfOffsetByteSize() const {
switch (Format) {
case dwarf::DwarfFormat::DWARF32:
return 4;
case dwarf::DwarfFormat::DWARF64:
return 8;
}
llvm_unreachable("Invalid Format value");
}
};

class DWARFFormValue {
public:
enum FormClass {
Expand Down Expand Up @@ -104,79 +133,43 @@ class DWARFFormValue {

/// Get the fixed byte size for a given form.
///
/// If the form always has a fixed valid byte size that doesn't depend on a
/// DWARFUnit, then an Optional with a value will be returned. If the form
/// can vary in size depending on the DWARFUnit (DWARF version, address byte
/// size, or DWARF 32/64) and the DWARFUnit is valid, then an Optional with a
/// valid value is returned. If the form is always encoded using a variable
/// length storage format (ULEB or SLEB numbers or blocks) or the size
/// depends on a DWARFUnit and the DWARFUnit is NULL, then None will be
/// returned.
/// \param Form The DWARF form to get the fixed byte size for
/// \param U The DWARFUnit that can be used to help determine the byte size.
///
/// \returns Optional<uint8_t> value with the fixed byte size or None if
/// \p Form doesn't have a fixed byte size or a DWARFUnit wasn't supplied
/// and was needed to calculate the byte size.
static Optional<uint8_t> getFixedByteSize(dwarf::Form Form,
const DWARFUnit *U = nullptr);

/// Get the fixed byte size for a given form.
///
/// If the form has a fixed byte size given a valid DWARF version and address
/// byte size, then an Optional with a valid value is returned. If the form
/// is always encoded using a variable length storage format (ULEB or SLEB
/// numbers or blocks) then None will be returned.
/// If the form has a fixed byte size, then an Optional with a value will be
/// returned. If the form is always encoded using a variable length storage
/// format (ULEB or SLEB numbers or blocks) then None will be returned.
///
/// \param Form DWARF form to get the fixed byte size for
/// \param Version DWARF version number.
/// \param AddrSize size of an address in bytes.
/// \param Format enum value from llvm::dwarf::DwarfFormat.
/// \param Form DWARF form to get the fixed byte size for.
/// \param FormParams DWARF parameters to help interpret forms.
/// \returns Optional<uint8_t> value with the fixed byte size or None if
/// \p Form doesn't have a fixed byte size.
static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, uint16_t Version,
uint8_t AddrSize,
llvm::dwarf::DwarfFormat Format);
static Optional<uint8_t> getFixedByteSize(dwarf::Form Form,
const DWARFFormParams &FormParams);

/// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr.
/// Skip a form's value in \p DebugInfoData at the offset specified by
/// \p OffsetPtr.
///
/// Skips the bytes for this form in the debug info and updates the offset.
/// Skips the bytes for the current form and updates the offset.
///
/// \param DebugInfoData the .debug_info data to use to skip the value.
/// \param OffsetPtr a reference to the offset that will be updated.
/// \param U the DWARFUnit to use when skipping the form in case the form
/// size differs according to data in the DWARFUnit.
/// \param DebugInfoData The data where we want to skip the value.
/// \param OffsetPtr A reference to the offset that will be updated.
/// \param Params DWARF parameters to help interpret forms.
/// \returns true on success, false if the form was not skipped.
bool skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr,
const DWARFUnit *U) const;

/// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr.
///
/// Skips the bytes for this form in the debug info and updates the offset.
///
/// \param Form the DW_FORM enumeration that indicates the form to skip.
/// \param DebugInfoData the .debug_info data to use to skip the value.
/// \param OffsetPtr a reference to the offset that will be updated.
/// \param U the DWARFUnit to use when skipping the form in case the form
/// size differs according to data in the DWARFUnit.
/// \returns true on success, false if the form was not skipped.
static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
uint32_t *OffsetPtr, const DWARFUnit *U);
const DWARFFormParams &Params) const {
return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params);
}

/// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr.
/// Skip a form's value in \p DebugInfoData at the offset specified by
/// \p OffsetPtr.
///
/// Skips the bytes for this form in the debug info and updates the offset.
/// Skips the bytes for the specified form and updates the offset.
///
/// \param Form the DW_FORM enumeration that indicates the form to skip.
/// \param DebugInfoData the .debug_info data to use to skip the value.
/// \param OffsetPtr a reference to the offset that will be updated.
/// \param Version DWARF version number.
/// \param AddrSize size of an address in bytes.
/// \param Format enum value from llvm::dwarf::DwarfFormat.
/// \param Form The DW_FORM enumeration that indicates the form to skip.
/// \param DebugInfoData The data where we want to skip the value.
/// \param OffsetPtr A reference to the offset that will be updated.
/// \param FormParams DWARF parameters to help interpret forms.
/// \returns true on success, false if the form was not skipped.
static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
uint32_t *OffsetPtr, uint16_t Version, uint8_t AddrSize,
llvm::dwarf::DwarfFormat Format);
uint32_t *OffsetPtr, const DWARFFormParams &FormParams);

private:
void dumpString(raw_ostream &OS) const;
Expand Down
34 changes: 14 additions & 20 deletions include/llvm/DebugInfo/DWARF/DWARFUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
Expand Down Expand Up @@ -127,12 +128,13 @@ class DWARFUnit {
bool isDWO;
const DWARFUnitSectionBase &UnitSection;

// Version, address size, and DWARF format.
DWARFFormParams FormParams;

uint32_t Offset;
uint32_t Length;
const DWARFAbbreviationDeclarationSet *Abbrevs;
uint16_t Version;
uint8_t UnitType;
uint8_t AddrSize;
uint64_t BaseAddr;
/// The compile unit debug information entry items.
std::vector<DWARFDebugInfoEntry> DieArray;
Expand All @@ -159,7 +161,7 @@ class DWARFUnit {
virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr);

/// Size in bytes of the unit header.
virtual uint32_t getHeaderSize() const { return Version <= 4 ? 11 : 12; }
virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; }

public:
DWARFUnit(DWARFContext &Context, const DWARFSection &Section,
Expand Down Expand Up @@ -197,7 +199,8 @@ class DWARFUnit {
uint64_t getStringOffsetSectionRelocation(uint32_t Index) const;

DataExtractor getDebugInfoExtractor() const {
return DataExtractor(InfoSection.Data, isLittleEndian, AddrSize);
return DataExtractor(InfoSection.Data, isLittleEndian,
getAddressByteSize());
}

DataExtractor getStringExtractor() const {
Expand All @@ -220,30 +223,21 @@ class DWARFUnit {
uint32_t getOffset() const { return Offset; }
uint32_t getNextUnitOffset() const { return Offset + Length + 4; }
uint32_t getLength() const { return Length; }
uint16_t getVersion() const { return Version; }

dwarf::DwarfFormat getFormat() const {
return dwarf::DwarfFormat::DWARF32; // FIXME: Support DWARF64.
const DWARFFormParams &getFormParams() const { return FormParams; }
uint16_t getVersion() const { return FormParams.Version; }
dwarf::DwarfFormat getFormat() const { return FormParams.Format; }
uint8_t getAddressByteSize() const { return FormParams.AddrSize; }
uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); }
uint8_t getDwarfOffsetByteSize() const {
return FormParams.getDwarfOffsetByteSize();
}

const DWARFAbbreviationDeclarationSet *getAbbreviations() const {
return Abbrevs;
}

uint8_t getUnitType() const { return UnitType; }
uint8_t getAddressByteSize() const { return AddrSize; }

uint8_t getRefAddrByteSize() const {
if (Version == 2)
return AddrSize;
return getDwarfOffsetByteSize();
}

uint8_t getDwarfOffsetByteSize() const {
if (getFormat() == dwarf::DwarfFormat::DWARF64)
return 8;
return 4;
}

uint64_t getBaseAddress() const { return BaseAddr; }

Expand Down
80 changes: 44 additions & 36 deletions lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,46 +65,52 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data,
if (A && F) {
Optional<int64_t> V;
bool IsImplicitConst = (F == DW_FORM_implicit_const);
if (IsImplicitConst)
if (IsImplicitConst) {
V = Data.getSLEB128(OffsetPtr);
else if (auto Size = DWARFFormValue::getFixedByteSize(F))
V = *Size;
AttributeSpecs.push_back(AttributeSpec(A, F, V));
if (IsImplicitConst)
AttributeSpecs.push_back(AttributeSpec(A, F, V));
continue;
}
// If this abbrevation still has a fixed byte size, then update the
// FixedAttributeSize as needed.
if (FixedAttributeSize) {
if (V)
FixedAttributeSize->NumBytes += *V;
else {
switch (F) {
case DW_FORM_addr:
++FixedAttributeSize->NumAddrs;
break;

case DW_FORM_ref_addr:
++FixedAttributeSize->NumRefAddrs;
break;

case DW_FORM_strp:
case DW_FORM_GNU_ref_alt:
case DW_FORM_GNU_strp_alt:
case DW_FORM_line_strp:
case DW_FORM_sec_offset:
case DW_FORM_strp_sup:
++FixedAttributeSize->NumDwarfOffsets;
break;

default:
// Indicate we no longer have a fixed byte size for this
// abbreviation by clearing the FixedAttributeSize optional value
// so it doesn't have a value.
FixedAttributeSize.reset();
break;
}
switch (F) {
case DW_FORM_addr:
if (FixedAttributeSize)
++FixedAttributeSize->NumAddrs;
break;

case DW_FORM_ref_addr:
if (FixedAttributeSize)
++FixedAttributeSize->NumRefAddrs;
break;

case DW_FORM_strp:
case DW_FORM_GNU_ref_alt:
case DW_FORM_GNU_strp_alt:
case DW_FORM_line_strp:
case DW_FORM_sec_offset:
case DW_FORM_strp_sup:
if (FixedAttributeSize)
++FixedAttributeSize->NumDwarfOffsets;
break;

default:
// The form has a byte size that doesn't depend on Params.
// If it's a fixed size, keep track of it.
if (auto Size =
DWARFFormValue::getFixedByteSize(F, DWARFFormParams())) {
V = *Size;
if (FixedAttributeSize)
FixedAttributeSize->NumBytes += *V;
break;
}
// Indicate we no longer have a fixed byte size for this
// abbreviation by clearing the FixedAttributeSize optional value
// so it doesn't have a value.
FixedAttributeSize.reset();
break;
}
// Record this attribute and its fixed size if it has one.
AttributeSpecs.push_back(AttributeSpec(A, F, V));
} else if (A == 0 && F == 0) {
// We successfully reached the end of this abbreviation declaration
// since both attribute and form are zero.
Expand Down Expand Up @@ -186,7 +192,8 @@ Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue(
if (auto FixedSize = Spec.getByteSize(U))
Offset += *FixedSize;
else
DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U);
DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset,
U.getFormParams());
++AttrIndex;
}
return None;
Expand All @@ -211,7 +218,8 @@ Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
if (ByteSizeOrValue)
return ByteSizeOrValue;
Optional<int64_t> S;
auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, &U);
auto FixedByteSize =
DWARFFormValue::getFixedByteSize(Form, U.getFormParams());
if (FixedByteSize)
S = *FixedByteSize;
return S;
Expand Down
2 changes: 1 addition & 1 deletion lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr,
// Attribute byte size if fixed, just add the size to the offset.
*OffsetPtr += *FixedSize;
} else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData,
OffsetPtr, &U)) {
OffsetPtr, U.getFormParams())) {
// We failed to skip this attribute's value, restore the original offset
// and return the failure status.
*OffsetPtr = Offset;
Expand Down
Loading

0 comments on commit fd770ea

Please sign in to comment.