Newer
Older
//===-- 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;
void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS,
const DWARFCompileUnit *cu,
unsigned recurseDepth,
unsigned indent) const {
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
uint32_t offset = Offset;
if (debug_info_data.isValidOffset(offset)) {
Benjamin Kramer
committed
uint32_t abbrCode = debug_info_data.getULEB128(&offset);
Benjamin Kramer
committed
OS << format("\n0x%8.8x: ", Offset);
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() ? '*' : ' ');
const uint32_t numAttributes = AbbrevDecl->getNumAttributes();
for (uint32_t i = 0; i != numAttributes; ++i) {
uint16_t attr = AbbrevDecl->getAttrByIndex(i);
uint16_t form = AbbrevDecl->getFormByIndex(i);
dumpAttribute(OS, cu, &offset, attr, form, indent);
}
const DWARFDebugInfoEntryMinimal *child = getFirstChild();
if (recurseDepth > 0 && child) {
while (child) {
child->dump(OS, cu, recurseDepth-1, indent+2);
child = child->getSibling();
}
}
} else {
OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
<< abbrCode << '\n';
}
} else {
Benjamin Kramer
committed
OS.indent(indent) << "NULL\n";
}
}
}
void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS,
const DWARFCompileUnit *cu,
uint32_t* offset_ptr,
uint16_t attr,
uint16_t form,
unsigned indent) const {
David Blaikie
committed
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(cu->getDebugInfoExtractor(), offset_ptr, cu))
return;
OS << "\t(";
Alexey Samsonov
committed
bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *CU,
const uint8_t *FixedFormSizes,
uint32_t *OffsetPtr) {
Offset = *OffsetPtr;
DataExtractor DebugInfoData = CU->getDebugInfoExtractor();
uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
if (0 == AbbrCode) {
// NULL debug tag entry.
Alexey Samsonov
committed
return true;
}
AbbrevDecl = CU->getAbbreviations()->getAbbreviationDeclaration(AbbrCode);
assert(AbbrevDecl);
assert(FixedFormSizes); // For best performance this should be specified!
// Skip all data in the .debug_info for the attributes
for (uint32_t i = 0, n = AbbrevDecl->getNumAttributes(); i < n; ++i) {
uint16_t Form = AbbrevDecl->getFormByIndex(i);
// FIXME: Currently we're checking if this is less than the last
// entry in the fixed_form_sizes table, but this should be changed
// to use dynamic dispatch.
uint8_t FixedFormSize =
(Form < DW_FORM_ref_sig8) ? FixedFormSizes[Form] : 0;
if (FixedFormSize)
*OffsetPtr += FixedFormSize;
else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr,
CU)) {
// Restore the original offset.
*OffsetPtr = Offset;
return false;
}
Alexey Samsonov
committed
return true;
Alexey Samsonov
committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *CU,
uint32_t *OffsetPtr) {
DataExtractor DebugInfoData = CU->getDebugInfoExtractor();
const uint32_t CUEndOffset = CU->getNextCompileUnitOffset();
Offset = *OffsetPtr;
if ((Offset >= CUEndOffset) || !DebugInfoData.isValidOffset(Offset))
return false;
uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
if (0 == AbbrCode) {
// NULL debug tag entry.
AbbrevDecl = NULL;
return true;
}
AbbrevDecl = CU->getAbbreviations()->getAbbreviationDeclaration(AbbrCode);
if (0 == AbbrevDecl) {
// Restore the original offset.
*OffsetPtr = Offset;
return false;
}
bool IsCompileUnitTag = (AbbrevDecl->getTag() == DW_TAG_compile_unit);
if (IsCompileUnitTag)
const_cast<DWARFCompileUnit*>(CU)->setBaseAddress(0);
// Skip all data in the .debug_info for the attributes
for (uint32_t i = 0, n = AbbrevDecl->getNumAttributes(); i < n; ++i) {
uint16_t Attr = AbbrevDecl->getAttrByIndex(i);
uint16_t Form = AbbrevDecl->getFormByIndex(i);
if (IsCompileUnitTag &&
((Attr == DW_AT_entry_pc) || (Attr == DW_AT_low_pc))) {
DWARFFormValue FormValue(Form);
if (FormValue.extractValue(DebugInfoData, OffsetPtr, CU)) {
if (Attr == DW_AT_low_pc || Attr == DW_AT_entry_pc)
const_cast<DWARFCompileUnit*>(CU)
->setBaseAddress(FormValue.getUnsigned());
Alexey Samsonov
committed
} else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr,
CU)) {
// Restore the original offset.
*OffsetPtr = Offset;
return false;
Alexey Samsonov
committed
return true;
Alexey Samsonov
committed
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;
}
uint32_t
DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu,
const uint16_t attr,
DWARFFormValue &form_value,
uint32_t *end_attr_offset_ptr)
const {
if (AbbrevDecl) {
uint32_t attr_idx = AbbrevDecl->findAttributeIndex(attr);
if (attr_idx != -1U) {
uint32_t offset = getOffset();
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
// Skip the abbreviation code so we are at the data for the attributes
debug_info_data.getULEB128(&offset);
uint32_t idx = 0;
while (idx < attr_idx)
DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(idx++),
debug_info_data, &offset, cu);
const uint32_t attr_offset = offset;
form_value = DWARFFormValue(AbbrevDecl->getFormByIndex(idx));
if (form_value.extractValue(debug_info_data, &offset, cu)) {
if (end_attr_offset_ptr)
*end_attr_offset_ptr = offset;
return attr_offset;
}
}
}
return 0;
}
const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
const DWARFCompileUnit *CU, const uint16_t Attr,
const char *FailValue) const {
DWARFFormValue FormValue;
if (getAttributeValue(CU, Attr, FormValue))
return FormValue.getAsCString(CU);
return FailValue;
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress(
const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const {
DWARFFormValue FormValue;
if (getAttributeValue(CU, Attr, FormValue))
return FormValue.getAsAddress(CU);
return FailValue;
}
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned(
const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const {
DWARFFormValue FormValue;
if (getAttributeValue(CU, Attr, FormValue)) {
return FormValue.getUnsigned();
}
return FailValue;
}
int64_t
DWARFDebugInfoEntryMinimal::getAttributeValueAsSigned(
const DWARFCompileUnit* cu,
const uint16_t attr,
int64_t fail_value) const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value))
return form_value.getSigned();
return fail_value;
}
uint64_t
Benjamin Kramer
committed
DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(
const DWARFCompileUnit* cu,
const uint16_t attr,
uint64_t fail_value)
const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value))
return form_value.getReference(cu);
return fail_value;
}
Benjamin Kramer
committed
Alexey Samsonov
committed
bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFCompileUnit *CU,
uint64_t &LowPC,
uint64_t &HighPC) const {
Alexey Samsonov
committed
HighPC = -1ULL;
LowPC = getAttributeValueAsAddress(CU, DW_AT_low_pc, -1ULL);
Alexey Samsonov
committed
if (LowPC != -1ULL)
HighPC = getAttributeValueAsAddress(CU, DW_AT_high_pc, -1ULL);
Alexey Samsonov
committed
return (HighPC != -1ULL);
}
Benjamin Kramer
committed
void
Alexey Samsonov
committed
DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU,
DWARFDebugAranges *DebugAranges,
uint32_t CUOffsetInAranges)
Benjamin Kramer
committed
const {
if (AbbrevDecl) {
Alexey Samsonov
committed
if (isSubprogramDIE()) {
uint64_t LowPC, HighPC;
if (getLowAndHighPC(CU, LowPC, HighPC))
DebugAranges->appendRange(CUOffsetInAranges, LowPC, HighPC);
Alexey Samsonov
committed
// FIXME: try to append ranges from .debug_ranges section.
Benjamin Kramer
committed
}
const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
while (Child) {
Child->buildAddressRangeTable(CU, DebugAranges, CUOffsetInAranges);
Child = Child->getSibling();
Benjamin Kramer
committed
}
}
}
Alexey Samsonov
committed
bool
DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
const DWARFCompileUnit *CU,
const uint64_t Address)
const {
Alexey Samsonov
committed
if (isNULL())
return false;
uint64_t LowPC, HighPC;
if (getLowAndHighPC(CU, LowPC, HighPC))
return (LowPC <= Address && Address <= HighPC);
// Try to get address ranges from .debug_ranges section.
uint32_t RangesOffset = getAttributeValueAsReference(CU, DW_AT_ranges, -1U);
if (RangesOffset != -1U) {
DWARFDebugRangeList RangeList;
if (CU->extractRangeList(RangesOffset, RangeList))
return RangeList.containsAddress(CU->getBaseAddress(), Address);
Alexey Samsonov
committed
}
return false;
}
const char*
DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFCompileUnit *CU)
const {
Alexey Samsonov
committed
if (!isSubroutineDIE())
Alexey Samsonov
committed
return 0;
Alexey Samsonov
committed
// Try to get mangled name if possible.
if (const char *name =
Alexey Samsonov
committed
getAttributeValueAsString(CU, DW_AT_MIPS_linkage_name, 0))
Alexey Samsonov
committed
return name;
Alexey Samsonov
committed
if (const char *name = getAttributeValueAsString(CU, DW_AT_linkage_name, 0))
Alexey Samsonov
committed
return name;
Alexey Samsonov
committed
if (const char *name = getAttributeValueAsString(CU, DW_AT_name, 0))
Alexey Samsonov
committed
return name;
// Try to get name from specification DIE.
uint32_t spec_ref =
Alexey Samsonov
committed
getAttributeValueAsReference(CU, DW_AT_specification, -1U);
Alexey Samsonov
committed
if (spec_ref != -1U) {
DWARFDebugInfoEntryMinimal spec_die;
Alexey Samsonov
committed
if (spec_die.extract(CU, &spec_ref)) {
if (const char *name = spec_die.getSubroutineName(CU))
Alexey Samsonov
committed
return name;
Alexey Samsonov
committed
}
}
Alexey Samsonov
committed
// Try to get name from abstract origin DIE.
uint32_t abs_origin_ref =
Alexey Samsonov
committed
getAttributeValueAsReference(CU, DW_AT_abstract_origin, -1U);
Alexey Samsonov
committed
if (abs_origin_ref != -1U) {
DWARFDebugInfoEntryMinimal abs_origin_die;
Alexey Samsonov
committed
if (abs_origin_die.extract(CU, &abs_origin_ref)) {
if (const char *name = abs_origin_die.getSubroutineName(CU))
Alexey Samsonov
committed
return name;
}
}
return 0;
Alexey Samsonov
committed
}
Alexey Samsonov
committed
void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFCompileUnit *CU,
uint32_t &CallFile,
uint32_t &CallLine,
uint32_t &CallColumn) const {
Alexey Samsonov
committed
CallFile = getAttributeValueAsUnsigned(CU, DW_AT_call_file, 0);
CallLine = getAttributeValueAsUnsigned(CU, DW_AT_call_line, 0);
CallColumn = getAttributeValueAsUnsigned(CU, DW_AT_call_column, 0);
}
Alexey Samsonov
committed
DWARFDebugInfoEntryInlinedChain
Alexey Samsonov
committed
DWARFDebugInfoEntryMinimal::getInlinedChainForAddress(
Alexey Samsonov
committed
const DWARFCompileUnit *CU, const uint64_t Address) const {
DWARFDebugInfoEntryInlinedChain InlinedChain;
InlinedChain.CU = CU;
Alexey Samsonov
committed
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()) {
Alexey Samsonov
committed
InlinedChain.DIEs.push_back(*DIE);
Alexey Samsonov
committed
}
// Try to get child which also contains provided address.
const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild();
while (Child) {
if (Child->addressRangeContainsAddress(CU, 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.
Alexey Samsonov
committed
std::reverse(InlinedChain.DIEs.begin(), InlinedChain.DIEs.end());
Alexey Samsonov
committed
return InlinedChain;
}