| //===-- 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/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)) { | |
| uint64_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 .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); | |
| 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); | |
| const uint8_t fixed_skip_size = fixed_form_sizes[form]; | |
| 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_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; | |
| // 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: | |
| form_size = 8; | |
| break; | |
| // signed or unsigned LEB 128 values | |
| case DW_FORM_sdata: | |
| case DW_FORM_udata: | |
| case DW_FORM_ref_udata: | |
| debug_info_data.getULEB128(&offset); | |
| break; | |
| case DW_FORM_indirect: | |
| form_is_indirect = true; | |
| form = debug_info_data.getULEB128(&offset); | |
| 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 | |
| } | |
| return false; | |
| } | |
| 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_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; | |
| // 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: | |
| form_size = 8; | |
| break; | |
| // signed or unsigned LEB 128 values | |
| case DW_FORM_sdata: | |
| case DW_FORM_udata: | |
| case DW_FORM_ref_udata: | |
| debug_info_data.getULEB128(&offset); | |
| break; | |
| case DW_FORM_indirect: | |
| form = debug_info_data.getULEB128(&offset); | |
| form_is_indirect = true; | |
| 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; | |
| } | |
| 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->getContext().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; | |
| } | |
| void | |
| DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *cu, | |
| DWARFDebugAranges *debug_aranges) | |
| const { | |
| if (AbbrevDecl) { | |
| uint16_t tag = AbbrevDecl->getTag(); | |
| if (tag == DW_TAG_subprogram) { | |
| uint64_t hi_pc = -1ULL; | |
| uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL); | |
| if (lo_pc != -1ULL) | |
| hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL); | |
| if (hi_pc != -1ULL) | |
| debug_aranges->appendRange(cu->getOffset(), lo_pc, hi_pc); | |
| } | |
| const DWARFDebugInfoEntryMinimal *child = getFirstChild(); | |
| while (child) { | |
| child->buildAddressRangeTable(cu, debug_aranges); | |
| child = child->getSibling(); | |
| } | |
| } | |
| } |