mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-05 02:16:46 +00:00
b043c3d94a
It is more appropriate than the current situation, when one flag (AbsoluteFilePath) is relevant only if another flag is set. This refactoring would also simplify fetching the short function name (stored in DW_AT_name) instead of a linkage name returned currently. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208921 91177308-0d34-0410-b5e6-96231b3b80d8
349 lines
12 KiB
C++
349 lines
12 KiB
C++
//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DWARFDebugInfoEntry.h"
|
|
#include "DWARFCompileUnit.h"
|
|
#include "DWARFContext.h"
|
|
#include "DWARFDebugAbbrev.h"
|
|
#include "llvm/DebugInfo/DWARFFormValue.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/Dwarf.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
using namespace dwarf;
|
|
typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind;
|
|
|
|
void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, const DWARFUnit *u,
|
|
unsigned recurseDepth,
|
|
unsigned indent) const {
|
|
DataExtractor debug_info_data = u->getDebugInfoExtractor();
|
|
uint32_t offset = Offset;
|
|
|
|
if (debug_info_data.isValidOffset(offset)) {
|
|
uint32_t abbrCode = debug_info_data.getULEB128(&offset);
|
|
|
|
OS << format("\n0x%8.8x: ", Offset);
|
|
if (abbrCode) {
|
|
if (AbbrevDecl) {
|
|
const char *tagString = TagString(getTag());
|
|
if (tagString)
|
|
OS.indent(indent) << tagString;
|
|
else
|
|
OS.indent(indent) << format("DW_TAG_Unknown_%x", getTag());
|
|
OS << format(" [%u] %c\n", abbrCode,
|
|
AbbrevDecl->hasChildren() ? '*' : ' ');
|
|
|
|
// Dump all data in the DIE for the attributes.
|
|
for (const auto &AttrSpec : AbbrevDecl->attributes()) {
|
|
dumpAttribute(OS, u, &offset, AttrSpec.Attr, AttrSpec.Form, indent);
|
|
}
|
|
|
|
const DWARFDebugInfoEntryMinimal *child = getFirstChild();
|
|
if (recurseDepth > 0 && child) {
|
|
while (child) {
|
|
child->dump(OS, u, recurseDepth-1, indent+2);
|
|
child = child->getSibling();
|
|
}
|
|
}
|
|
} else {
|
|
OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
|
|
<< abbrCode << '\n';
|
|
}
|
|
} else {
|
|
OS.indent(indent) << "NULL\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS,
|
|
const DWARFUnit *u,
|
|
uint32_t *offset_ptr,
|
|
uint16_t attr, uint16_t form,
|
|
unsigned indent) const {
|
|
OS << " ";
|
|
OS.indent(indent+2);
|
|
const char *attrString = AttributeString(attr);
|
|
if (attrString)
|
|
OS << attrString;
|
|
else
|
|
OS << format("DW_AT_Unknown_%x", attr);
|
|
const char *formString = FormEncodingString(form);
|
|
if (formString)
|
|
OS << " [" << formString << ']';
|
|
else
|
|
OS << format(" [DW_FORM_Unknown_%x]", form);
|
|
|
|
DWARFFormValue formValue(form);
|
|
|
|
if (!formValue.extractValue(u->getDebugInfoExtractor(), offset_ptr, u))
|
|
return;
|
|
|
|
OS << "\t(";
|
|
formValue.dump(OS, u);
|
|
OS << ")\n";
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U,
|
|
uint32_t *OffsetPtr) {
|
|
Offset = *OffsetPtr;
|
|
DataExtractor DebugInfoData = U->getDebugInfoExtractor();
|
|
uint32_t UEndOffset = U->getNextUnitOffset();
|
|
if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
|
|
return false;
|
|
uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
|
|
if (0 == AbbrCode) {
|
|
// NULL debug tag entry.
|
|
AbbrevDecl = nullptr;
|
|
return true;
|
|
}
|
|
AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode);
|
|
if (nullptr == AbbrevDecl) {
|
|
// Restore the original offset.
|
|
*OffsetPtr = Offset;
|
|
return false;
|
|
}
|
|
ArrayRef<uint8_t> FixedFormSizes = DWARFFormValue::getFixedFormSizes(
|
|
U->getAddressByteSize(), U->getVersion());
|
|
assert(FixedFormSizes.size() > 0);
|
|
|
|
// Skip all data in the .debug_info for the attributes
|
|
for (const auto &AttrSpec : AbbrevDecl->attributes()) {
|
|
uint16_t Form = AttrSpec.Form;
|
|
|
|
uint8_t FixedFormSize =
|
|
(Form < FixedFormSizes.size()) ? FixedFormSizes[Form] : 0;
|
|
if (FixedFormSize)
|
|
*OffsetPtr += FixedFormSize;
|
|
else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) {
|
|
// Restore the original offset.
|
|
*OffsetPtr = Offset;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::isSubprogramDIE() const {
|
|
return getTag() == DW_TAG_subprogram;
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::isSubroutineDIE() const {
|
|
uint32_t Tag = getTag();
|
|
return Tag == DW_TAG_subprogram ||
|
|
Tag == DW_TAG_inlined_subroutine;
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::getAttributeValue(
|
|
const DWARFUnit *U, const uint16_t Attr, DWARFFormValue &FormValue) const {
|
|
if (!AbbrevDecl)
|
|
return false;
|
|
|
|
uint32_t AttrIdx = AbbrevDecl->findAttributeIndex(Attr);
|
|
if (AttrIdx == -1U)
|
|
return false;
|
|
|
|
DataExtractor DebugInfoData = U->getDebugInfoExtractor();
|
|
uint32_t DebugInfoOffset = getOffset();
|
|
|
|
// Skip the abbreviation code so we are at the data for the attributes
|
|
DebugInfoData.getULEB128(&DebugInfoOffset);
|
|
|
|
// Skip preceding attribute values.
|
|
for (uint32_t i = 0; i < AttrIdx; ++i) {
|
|
DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(i),
|
|
DebugInfoData, &DebugInfoOffset, U);
|
|
}
|
|
|
|
FormValue = DWARFFormValue(AbbrevDecl->getFormByIndex(AttrIdx));
|
|
return FormValue.extractValue(DebugInfoData, &DebugInfoOffset, U);
|
|
}
|
|
|
|
const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
|
|
const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const {
|
|
DWARFFormValue FormValue;
|
|
if (!getAttributeValue(U, Attr, FormValue))
|
|
return FailValue;
|
|
Optional<const char *> Result = FormValue.getAsCString(U);
|
|
return Result.hasValue() ? Result.getValue() : FailValue;
|
|
}
|
|
|
|
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress(
|
|
const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
|
|
DWARFFormValue FormValue;
|
|
if (!getAttributeValue(U, Attr, FormValue))
|
|
return FailValue;
|
|
Optional<uint64_t> Result = FormValue.getAsAddress(U);
|
|
return Result.hasValue() ? Result.getValue() : FailValue;
|
|
}
|
|
|
|
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant(
|
|
const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
|
|
DWARFFormValue FormValue;
|
|
if (!getAttributeValue(U, Attr, FormValue))
|
|
return FailValue;
|
|
Optional<uint64_t> Result = FormValue.getAsUnsignedConstant();
|
|
return Result.hasValue() ? Result.getValue() : FailValue;
|
|
}
|
|
|
|
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(
|
|
const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
|
|
DWARFFormValue FormValue;
|
|
if (!getAttributeValue(U, Attr, FormValue))
|
|
return FailValue;
|
|
Optional<uint64_t> Result = FormValue.getAsReference(U);
|
|
return Result.hasValue() ? Result.getValue() : FailValue;
|
|
}
|
|
|
|
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSectionOffset(
|
|
const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
|
|
DWARFFormValue FormValue;
|
|
if (!getAttributeValue(U, Attr, FormValue))
|
|
return FailValue;
|
|
Optional<uint64_t> Result = FormValue.getAsSectionOffset();
|
|
return Result.hasValue() ? Result.getValue() : FailValue;
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U,
|
|
uint64_t &LowPC,
|
|
uint64_t &HighPC) const {
|
|
LowPC = getAttributeValueAsAddress(U, DW_AT_low_pc, -1ULL);
|
|
if (LowPC == -1ULL)
|
|
return false;
|
|
HighPC = getAttributeValueAsAddress(U, DW_AT_high_pc, -1ULL);
|
|
if (HighPC == -1ULL) {
|
|
// Since DWARF4, DW_AT_high_pc may also be of class constant, in which case
|
|
// it represents function size.
|
|
HighPC = getAttributeValueAsUnsignedConstant(U, DW_AT_high_pc, -1ULL);
|
|
if (HighPC != -1ULL)
|
|
HighPC += LowPC;
|
|
}
|
|
return (HighPC != -1ULL);
|
|
}
|
|
|
|
DWARFAddressRangesVector
|
|
DWARFDebugInfoEntryMinimal::getAddressRanges(const DWARFUnit *U) const {
|
|
if (isNULL())
|
|
return DWARFAddressRangesVector();
|
|
// Single range specified by low/high PC.
|
|
uint64_t LowPC, HighPC;
|
|
if (getLowAndHighPC(U, LowPC, HighPC)) {
|
|
return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC));
|
|
}
|
|
// Multiple ranges from .debug_ranges section.
|
|
uint32_t RangesOffset =
|
|
getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U);
|
|
if (RangesOffset != -1U) {
|
|
DWARFDebugRangeList RangeList;
|
|
if (U->extractRangeList(RangesOffset, RangeList))
|
|
return RangeList.getAbsoluteRanges(U->getBaseAddress());
|
|
}
|
|
return DWARFAddressRangesVector();
|
|
}
|
|
|
|
void DWARFDebugInfoEntryMinimal::collectChildrenAddressRanges(
|
|
const DWARFUnit *U, DWARFAddressRangesVector& Ranges) const {
|
|
if (isNULL())
|
|
return;
|
|
if (isSubprogramDIE()) {
|
|
const auto &DIERanges = getAddressRanges(U);
|
|
Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
|
|
}
|
|
|
|
const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
|
|
while (Child) {
|
|
Child->collectChildrenAddressRanges(U, Ranges);
|
|
Child = Child->getSibling();
|
|
}
|
|
}
|
|
|
|
bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
|
|
const DWARFUnit *U, const uint64_t Address) const {
|
|
for (const auto& R : getAddressRanges(U)) {
|
|
if (R.first <= Address && Address < R.second)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const char *
|
|
DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFUnit *U,
|
|
FunctionNameKind Kind) const {
|
|
if (!isSubroutineDIE() || Kind == FunctionNameKind::None)
|
|
return nullptr;
|
|
// Try to get mangled name if possible.
|
|
if (const char *name =
|
|
getAttributeValueAsString(U, DW_AT_MIPS_linkage_name, nullptr))
|
|
return name;
|
|
if (const char *name = getAttributeValueAsString(U, DW_AT_linkage_name,
|
|
nullptr))
|
|
return name;
|
|
if (const char *name = getAttributeValueAsString(U, DW_AT_name, nullptr))
|
|
return name;
|
|
// Try to get name from specification DIE.
|
|
uint32_t spec_ref =
|
|
getAttributeValueAsReference(U, DW_AT_specification, -1U);
|
|
if (spec_ref != -1U) {
|
|
DWARFDebugInfoEntryMinimal spec_die;
|
|
if (spec_die.extractFast(U, &spec_ref)) {
|
|
if (const char *name = spec_die.getSubroutineName(U, Kind))
|
|
return name;
|
|
}
|
|
}
|
|
// Try to get name from abstract origin DIE.
|
|
uint32_t abs_origin_ref =
|
|
getAttributeValueAsReference(U, DW_AT_abstract_origin, -1U);
|
|
if (abs_origin_ref != -1U) {
|
|
DWARFDebugInfoEntryMinimal abs_origin_die;
|
|
if (abs_origin_die.extractFast(U, &abs_origin_ref)) {
|
|
if (const char *name = abs_origin_die.getSubroutineName(U, Kind))
|
|
return name;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFUnit *U,
|
|
uint32_t &CallFile,
|
|
uint32_t &CallLine,
|
|
uint32_t &CallColumn) const {
|
|
CallFile = getAttributeValueAsUnsignedConstant(U, DW_AT_call_file, 0);
|
|
CallLine = getAttributeValueAsUnsignedConstant(U, DW_AT_call_line, 0);
|
|
CallColumn = getAttributeValueAsUnsignedConstant(U, DW_AT_call_column, 0);
|
|
}
|
|
|
|
DWARFDebugInfoEntryInlinedChain
|
|
DWARFDebugInfoEntryMinimal::getInlinedChainForAddress(
|
|
const DWARFUnit *U, const uint64_t Address) const {
|
|
DWARFDebugInfoEntryInlinedChain InlinedChain;
|
|
InlinedChain.U = U;
|
|
if (isNULL())
|
|
return InlinedChain;
|
|
for (const DWARFDebugInfoEntryMinimal *DIE = this; DIE; ) {
|
|
// Append current DIE to inlined chain only if it has correct tag
|
|
// (e.g. it is not a lexical block).
|
|
if (DIE->isSubroutineDIE()) {
|
|
InlinedChain.DIEs.push_back(*DIE);
|
|
}
|
|
// Try to get child which also contains provided address.
|
|
const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild();
|
|
while (Child) {
|
|
if (Child->addressRangeContainsAddress(U, Address)) {
|
|
// Assume there is only one such child.
|
|
break;
|
|
}
|
|
Child = Child->getSibling();
|
|
}
|
|
DIE = Child;
|
|
}
|
|
// Reverse the obtained chain to make the root of inlined chain last.
|
|
std::reverse(InlinedChain.DIEs.begin(), InlinedChain.DIEs.end());
|
|
return InlinedChain;
|
|
}
|