232 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- DWARFAbbreviationDeclaration.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/DWARFAbbreviationDeclaration.h"
 | 
						|
 | 
						|
#include "llvm/ADT/None.h"
 | 
						|
#include "llvm/ADT/Optional.h"
 | 
						|
#include "llvm/BinaryFormat/Dwarf.h"
 | 
						|
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 | 
						|
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
 | 
						|
#include "llvm/Support/DataExtractor.h"
 | 
						|
#include "llvm/Support/Format.h"
 | 
						|
#include "llvm/Support/FormatVariadic.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
#include <cstddef>
 | 
						|
#include <cstdint>
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace dwarf;
 | 
						|
 | 
						|
void DWARFAbbreviationDeclaration::clear() {
 | 
						|
  Code = 0;
 | 
						|
  Tag = DW_TAG_null;
 | 
						|
  CodeByteSize = 0;
 | 
						|
  HasChildren = false;
 | 
						|
  AttributeSpecs.clear();
 | 
						|
  FixedAttributeSize.reset();
 | 
						|
}
 | 
						|
 | 
						|
DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
 | 
						|
  clear();
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
DWARFAbbreviationDeclaration::extract(DataExtractor Data,
 | 
						|
                                      uint64_t* OffsetPtr) {
 | 
						|
  clear();
 | 
						|
  const uint64_t Offset = *OffsetPtr;
 | 
						|
  Code = Data.getULEB128(OffsetPtr);
 | 
						|
  if (Code == 0) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  CodeByteSize = *OffsetPtr - Offset;
 | 
						|
  Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
 | 
						|
  if (Tag == DW_TAG_null) {
 | 
						|
    clear();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  uint8_t ChildrenByte = Data.getU8(OffsetPtr);
 | 
						|
  HasChildren = (ChildrenByte == DW_CHILDREN_yes);
 | 
						|
  // Assign a value to our optional FixedAttributeSize member variable. If
 | 
						|
  // this member variable still has a value after the while loop below, then
 | 
						|
  // all attribute data in this abbreviation declaration has a fixed byte size.
 | 
						|
  FixedAttributeSize = FixedSizeInfo();
 | 
						|
 | 
						|
  // Read all of the abbreviation attributes and forms.
 | 
						|
  while (true) {
 | 
						|
    auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
 | 
						|
    auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
 | 
						|
    if (A && F) {
 | 
						|
      bool IsImplicitConst = (F == DW_FORM_implicit_const);
 | 
						|
      if (IsImplicitConst) {
 | 
						|
        int64_t V = Data.getSLEB128(OffsetPtr);
 | 
						|
        AttributeSpecs.push_back(AttributeSpec(A, F, V));
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      Optional<uint8_t> ByteSize;
 | 
						|
      // If this abbrevation still has a fixed byte size, then update the
 | 
						|
      // FixedAttributeSize as needed.
 | 
						|
      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 ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
 | 
						|
          if (FixedAttributeSize)
 | 
						|
            FixedAttributeSize->NumBytes += *ByteSize;
 | 
						|
          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, ByteSize));
 | 
						|
    } else if (A == 0 && F == 0) {
 | 
						|
      // We successfully reached the end of this abbreviation declaration
 | 
						|
      // since both attribute and form are zero.
 | 
						|
      break;
 | 
						|
    } else {
 | 
						|
      // Attribute and form pairs must either both be non-zero, in which case
 | 
						|
      // they are added to the abbreviation declaration, or both be zero to
 | 
						|
      // terminate the abbrevation declaration. In this case only one was
 | 
						|
      // zero which is an error.
 | 
						|
      clear();
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
 | 
						|
  OS << '[' << getCode() << "] ";
 | 
						|
  OS << formatv("{0}", getTag());
 | 
						|
  OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
 | 
						|
  for (const AttributeSpec &Spec : AttributeSpecs) {
 | 
						|
    OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
 | 
						|
    if (Spec.isImplicitConst())
 | 
						|
      OS << '\t' << Spec.getImplicitConstValue();
 | 
						|
    OS << '\n';
 | 
						|
  }
 | 
						|
  OS << '\n';
 | 
						|
}
 | 
						|
 | 
						|
Optional<uint32_t>
 | 
						|
DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
 | 
						|
  for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
 | 
						|
    if (AttributeSpecs[i].Attr == Attr)
 | 
						|
      return i;
 | 
						|
  }
 | 
						|
  return None;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
 | 
						|
    uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
 | 
						|
  DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
 | 
						|
 | 
						|
  // Add the byte size of ULEB that for the abbrev Code so we can start
 | 
						|
  // skipping the attribute data.
 | 
						|
  uint64_t Offset = DIEOffset + CodeByteSize;
 | 
						|
  for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
 | 
						|
    // Match Offset along until we get to the attribute we want.
 | 
						|
    if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
 | 
						|
      Offset += *FixedSize;
 | 
						|
    else
 | 
						|
      DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
 | 
						|
                                &Offset, U.getFormParams());
 | 
						|
  return Offset;
 | 
						|
}
 | 
						|
 | 
						|
Optional<DWARFFormValue>
 | 
						|
DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
 | 
						|
    uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
 | 
						|
  assert(AttributeSpecs.size() > AttrIndex &&
 | 
						|
         "Attribute Index is out of bounds.");
 | 
						|
 | 
						|
  // We have arrived at the attribute to extract, extract if from Offset.
 | 
						|
  const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
 | 
						|
  if (Spec.isImplicitConst())
 | 
						|
    return DWARFFormValue::createFromSValue(Spec.Form,
 | 
						|
                                            Spec.getImplicitConstValue());
 | 
						|
 | 
						|
  DWARFFormValue FormValue(Spec.Form);
 | 
						|
  DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
 | 
						|
  if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
 | 
						|
    return FormValue;
 | 
						|
  return None;
 | 
						|
}
 | 
						|
 | 
						|
Optional<DWARFFormValue>
 | 
						|
DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
 | 
						|
                                                const dwarf::Attribute Attr,
 | 
						|
                                                const DWARFUnit &U) const {
 | 
						|
  // Check if this abbreviation has this attribute without needing to skip
 | 
						|
  // any data so we can return quickly if it doesn't.
 | 
						|
  Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
 | 
						|
  if (!MatchAttrIndex)
 | 
						|
    return None;
 | 
						|
 | 
						|
  uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
 | 
						|
 | 
						|
  return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
 | 
						|
}
 | 
						|
 | 
						|
size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
 | 
						|
    const DWARFUnit &U) const {
 | 
						|
  size_t ByteSize = NumBytes;
 | 
						|
  if (NumAddrs)
 | 
						|
    ByteSize += NumAddrs * U.getAddressByteSize();
 | 
						|
  if (NumRefAddrs)
 | 
						|
    ByteSize += NumRefAddrs * U.getRefAddrByteSize();
 | 
						|
  if (NumDwarfOffsets)
 | 
						|
    ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
 | 
						|
  return ByteSize;
 | 
						|
}
 | 
						|
 | 
						|
Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
 | 
						|
    const DWARFUnit &U) const {
 | 
						|
  if (isImplicitConst())
 | 
						|
    return 0;
 | 
						|
  if (ByteSize.HasByteSize)
 | 
						|
    return ByteSize.ByteSize;
 | 
						|
  Optional<int64_t> S;
 | 
						|
  auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
 | 
						|
  if (FixedByteSize)
 | 
						|
    S = *FixedByteSize;
 | 
						|
  return S;
 | 
						|
}
 | 
						|
 | 
						|
Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
 | 
						|
    const DWARFUnit &U) const {
 | 
						|
  if (FixedAttributeSize)
 | 
						|
    return FixedAttributeSize->getByteSize(U);
 | 
						|
  return None;
 | 
						|
}
 |