summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp')
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp589
1 files changed, 589 insertions, 0 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp
new file mode 100644
index 0000000..02b15d6
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,589 @@
+//===-- 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 "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)) {
+ 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.
+ 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 {
+ 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 {
+ OS << format("0x%8.8x: ", *offset_ptr);
+ 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(";
+ formValue.dump(OS, cu);
+ OS << ")\n";
+}
+
+bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu,
+ const uint8_t *fixed_form_sizes,
+ uint32_t *offset_ptr) {
+ Offset = *offset_ptr;
+
+ DataExtractor debug_info_data = cu->getDebugInfoExtractor();
+ uint64_t abbrCode = debug_info_data.getULEB128(offset_ptr);
+
+ assert(fixed_form_sizes); // For best performance this should be specified!
+
+ if (abbrCode) {
+ uint32_t offset = *offset_ptr;
+
+ AbbrevDecl = cu->getAbbreviations()->getAbbreviationDeclaration(abbrCode);
+
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = AbbrevDecl->getNumAttributes();
+ uint32_t i;
+ uint16_t form;
+ for (i=0; i<numAttributes; ++i) {
+
+ 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.
+ const uint8_t fixed_skip_size = (form < DW_FORM_ref_sig8) ?
+ fixed_form_sizes[form] : 0;
+ if (fixed_skip_size)
+ offset += fixed_skip_size;
+ else {
+ bool form_is_indirect = false;
+ do {
+ form_is_indirect = false;
+ uint32_t form_size = 0;
+ switch (form) {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info.
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ form_size = debug_info_data.getULEB128(&offset);
+ break;
+ case DW_FORM_block1:
+ form_size = debug_info_data.getU8(&offset);
+ break;
+ case DW_FORM_block2:
+ form_size = debug_info_data.getU16(&offset);
+ break;
+ case DW_FORM_block4:
+ form_size = debug_info_data.getU32(&offset);
+ break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.getCStr(&offset);
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ form_size = cu->getAddressByteSize();
+ break;
+
+ // 0 sized form.
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp:
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ debug_info_data.getULEB128(&offset);
+ break;
+
+ case DW_FORM_indirect:
+ form_is_indirect = true;
+ form = debug_info_data.getULEB128(&offset);
+ break;
+
+ // FIXME: 64-bit for DWARF64
+ case DW_FORM_sec_offset:
+ debug_info_data.getU32(offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = Offset;
+ return false;
+ }
+ offset += form_size;
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ } else {
+ AbbrevDecl = NULL;
+ return true; // NULL debug tag entry
+ }
+}
+
+bool
+DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *cu,
+ uint32_t *offset_ptr) {
+ DataExtractor debug_info_data = cu->getDebugInfoExtractor();
+ const uint32_t cu_end_offset = cu->getNextCompileUnitOffset();
+ const uint8_t cu_addr_size = cu->getAddressByteSize();
+ uint32_t offset = *offset_ptr;
+ if ((offset < cu_end_offset) && debug_info_data.isValidOffset(offset)) {
+ Offset = offset;
+
+ uint64_t abbrCode = debug_info_data.getULEB128(&offset);
+
+ if (abbrCode) {
+ AbbrevDecl = cu->getAbbreviations()->getAbbreviationDeclaration(abbrCode);
+
+ if (AbbrevDecl) {
+ uint16_t tag = AbbrevDecl->getTag();
+
+ bool isCompileUnitTag = tag == DW_TAG_compile_unit;
+ if(cu && isCompileUnitTag)
+ const_cast<DWARFCompileUnit*>(cu)->setBaseAddress(0);
+
+ // Skip all data in the .debug_info for the attributes
+ 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);
+
+ if (isCompileUnitTag &&
+ ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) {
+ DWARFFormValue form_value(form);
+ if (form_value.extractValue(debug_info_data, &offset, cu)) {
+ if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
+ const_cast<DWARFCompileUnit*>(cu)
+ ->setBaseAddress(form_value.getUnsigned());
+ }
+ } else {
+ bool form_is_indirect = false;
+ do {
+ form_is_indirect = false;
+ register uint32_t form_size = 0;
+ switch (form) {
+ // Blocks if inlined data that have a length field and the data
+ // bytes // inlined in the .debug_info
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ form_size = debug_info_data.getULEB128(&offset);
+ break;
+ case DW_FORM_block1:
+ form_size = debug_info_data.getU8(&offset);
+ break;
+ case DW_FORM_block2:
+ form_size = debug_info_data.getU16(&offset);
+ break;
+ case DW_FORM_block4:
+ form_size = debug_info_data.getU32(&offset);
+ break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.getCStr(&offset);
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ form_size = cu_addr_size;
+ break;
+
+ // 0 byte value
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp:
+ form_size = 4;
+ break;
+
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ debug_info_data.getULEB128(&offset);
+ break;
+
+ case DW_FORM_indirect:
+ form = debug_info_data.getULEB128(&offset);
+ form_is_indirect = true;
+ break;
+
+ // FIXME: 64-bit for DWARF64.
+ case DW_FORM_sec_offset:
+ debug_info_data.getU32(offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ } else {
+ AbbrevDecl = NULL;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+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* fail_value)
+ const {
+ DWARFFormValue form_value;
+ if (getAttributeValue(cu, attr, form_value)) {
+ DataExtractor stringExtractor(cu->getStringSection(), false, 0);
+ return form_value.getAsCString(&stringExtractor);
+ }
+ return fail_value;
+}
+
+uint64_t
+DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned(
+ const DWARFCompileUnit* cu,
+ const uint16_t attr,
+ uint64_t fail_value) const {
+ DWARFFormValue form_value;
+ if (getAttributeValue(cu, attr, form_value))
+ return form_value.getUnsigned();
+ return fail_value;
+}
+
+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
+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;
+}
+
+bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFCompileUnit *CU,
+ uint64_t &LowPC,
+ uint64_t &HighPC) const {
+ HighPC = -1ULL;
+ LowPC = getAttributeValueAsUnsigned(CU, DW_AT_low_pc, -1ULL);
+ if (LowPC != -1ULL)
+ HighPC = getAttributeValueAsUnsigned(CU, DW_AT_high_pc, -1ULL);
+ return (HighPC != -1ULL);
+}
+
+void
+DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU,
+ DWARFDebugAranges *DebugAranges)
+ const {
+ if (AbbrevDecl) {
+ if (isSubprogramDIE()) {
+ uint64_t LowPC, HighPC;
+ if (getLowAndHighPC(CU, LowPC, HighPC)) {
+ DebugAranges->appendRange(CU->getOffset(), LowPC, HighPC);
+ }
+ // FIXME: try to append ranges from .debug_ranges section.
+ }
+
+ const DWARFDebugInfoEntryMinimal *child = getFirstChild();
+ while (child) {
+ child->buildAddressRangeTable(CU, DebugAranges);
+ child = child->getSibling();
+ }
+ }
+}
+
+bool
+DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
+ const DWARFCompileUnit *CU,
+ const uint64_t Address)
+ const {
+ 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);
+ }
+ return false;
+}
+
+const char*
+DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFCompileUnit *CU)
+ const {
+ if (!isSubroutineDIE())
+ return 0;
+ // Try to get mangled name if possible.
+ if (const char *name =
+ getAttributeValueAsString(CU, DW_AT_MIPS_linkage_name, 0))
+ return name;
+ if (const char *name = getAttributeValueAsString(CU, DW_AT_linkage_name, 0))
+ return name;
+ if (const char *name = getAttributeValueAsString(CU, DW_AT_name, 0))
+ return name;
+ // Try to get name from specification DIE.
+ uint32_t spec_ref =
+ getAttributeValueAsReference(CU, DW_AT_specification, -1U);
+ if (spec_ref != -1U) {
+ DWARFDebugInfoEntryMinimal spec_die;
+ if (spec_die.extract(CU, &spec_ref)) {
+ if (const char *name = spec_die.getSubroutineName(CU))
+ return name;
+ }
+ }
+ // Try to get name from abstract origin DIE.
+ uint32_t abs_origin_ref =
+ getAttributeValueAsReference(CU, DW_AT_abstract_origin, -1U);
+ if (abs_origin_ref != -1U) {
+ DWARFDebugInfoEntryMinimal abs_origin_die;
+ if (abs_origin_die.extract(CU, &abs_origin_ref)) {
+ if (const char *name = abs_origin_die.getSubroutineName(CU))
+ return name;
+ }
+ }
+ return 0;
+}
+
+void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFCompileUnit *CU,
+ uint32_t &CallFile,
+ uint32_t &CallLine,
+ uint32_t &CallColumn) const {
+ CallFile = getAttributeValueAsUnsigned(CU, DW_AT_call_file, 0);
+ CallLine = getAttributeValueAsUnsigned(CU, DW_AT_call_line, 0);
+ CallColumn = getAttributeValueAsUnsigned(CU, DW_AT_call_column, 0);
+}
+
+DWARFDebugInfoEntryMinimal::InlinedChain
+DWARFDebugInfoEntryMinimal::getInlinedChainForAddress(
+ const DWARFCompileUnit *CU,
+ const uint64_t Address)
+ const {
+ DWARFDebugInfoEntryMinimal::InlinedChain InlinedChain;
+ 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.push_back(*DIE);
+ }
+ // 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.
+ std::reverse(InlinedChain.begin(), InlinedChain.end());
+ return InlinedChain;
+}
OpenPOWER on IntegriCloud