DWARFCompileUnit.cpp revision 239462
1//===-- DWARFCompileUnit.cpp ----------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "DWARFCompileUnit.h" 11#include "DWARFContext.h" 12#include "DWARFFormValue.h" 13#include "llvm/Support/Dwarf.h" 14#include "llvm/Support/Format.h" 15#include "llvm/Support/raw_ostream.h" 16using namespace llvm; 17using namespace dwarf; 18 19DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const { 20 return DataExtractor(Context.getInfoSection(), 21 Context.isLittleEndian(), getAddressByteSize()); 22} 23 24bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { 25 clear(); 26 27 Offset = *offset_ptr; 28 29 if (debug_info.isValidOffset(*offset_ptr)) { 30 uint64_t abbrOffset; 31 const DWARFDebugAbbrev *abbr = Context.getDebugAbbrev(); 32 Length = debug_info.getU32(offset_ptr); 33 Version = debug_info.getU16(offset_ptr); 34 abbrOffset = debug_info.getU32(offset_ptr); 35 AddrSize = debug_info.getU8(offset_ptr); 36 37 bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1); 38 bool versionOK = DWARFContext::isSupportedVersion(Version); 39 bool abbrOffsetOK = Context.getAbbrevSection().size() > abbrOffset; 40 bool addrSizeOK = AddrSize == 4 || AddrSize == 8; 41 42 if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && abbr != NULL) { 43 Abbrevs = abbr->getAbbreviationDeclarationSet(abbrOffset); 44 return true; 45 } 46 47 // reset the offset to where we tried to parse from if anything went wrong 48 *offset_ptr = Offset; 49 } 50 51 return false; 52} 53 54uint32_t 55DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data, 56 const DWARFAbbreviationDeclarationSet *abbrevs) { 57 clear(); 58 59 Offset = offset; 60 61 if (debug_info_data.isValidOffset(offset)) { 62 Length = debug_info_data.getU32(&offset); 63 Version = debug_info_data.getU16(&offset); 64 bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset(); 65 Abbrevs = abbrevs; 66 AddrSize = debug_info_data.getU8 (&offset); 67 68 bool versionOK = DWARFContext::isSupportedVersion(Version); 69 bool addrSizeOK = AddrSize == 4 || AddrSize == 8; 70 71 if (versionOK && addrSizeOK && abbrevsOK && 72 debug_info_data.isValidOffset(offset)) 73 return offset; 74 } 75 return 0; 76} 77 78void DWARFCompileUnit::clear() { 79 Offset = 0; 80 Length = 0; 81 Version = 0; 82 Abbrevs = 0; 83 AddrSize = 0; 84 BaseAddr = 0; 85 clearDIEs(false); 86} 87 88void DWARFCompileUnit::dump(raw_ostream &OS) { 89 OS << format("0x%08x", Offset) << ": Compile Unit:" 90 << " length = " << format("0x%08x", Length) 91 << " version = " << format("0x%04x", Version) 92 << " abbr_offset = " << format("0x%04x", Abbrevs->getOffset()) 93 << " addr_size = " << format("0x%02x", AddrSize) 94 << " (next CU at " << format("0x%08x", getNextCompileUnitOffset()) 95 << ")\n"; 96 97 getCompileUnitDIE(false)->dump(OS, this, -1U); 98} 99 100const char *DWARFCompileUnit::getCompilationDir() { 101 extractDIEsIfNeeded(true); 102 if (DieArray.empty()) 103 return 0; 104 return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); 105} 106 107void DWARFCompileUnit::setDIERelations() { 108 if (DieArray.empty()) 109 return; 110 DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); 111 DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); 112 DWARFDebugInfoEntryMinimal *curr_die; 113 // We purposely are skipping the last element in the array in the loop below 114 // so that we can always have a valid next item 115 for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { 116 // Since our loop doesn't include the last element, we can always 117 // safely access the next die in the array. 118 DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; 119 120 const DWARFAbbreviationDeclaration *curr_die_abbrev = 121 curr_die->getAbbreviationDeclarationPtr(); 122 123 if (curr_die_abbrev) { 124 // Normal DIE 125 if (curr_die_abbrev->hasChildren()) 126 next_die->setParent(curr_die); 127 else 128 curr_die->setSibling(next_die); 129 } else { 130 // NULL DIE that terminates a sibling chain 131 DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); 132 if (parent) 133 parent->setSibling(next_die); 134 } 135 } 136 137 // Since we skipped the last element, we need to fix it up! 138 if (die_array_begin < die_array_end) 139 curr_die->setParent(die_array_begin); 140} 141 142size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) { 143 const size_t initial_die_array_size = DieArray.size(); 144 if ((cu_die_only && initial_die_array_size > 0) || 145 initial_die_array_size > 1) 146 return 0; // Already parsed 147 148 // Set the offset to that of the first DIE and calculate the start of the 149 // next compilation unit header. 150 uint32_t offset = getFirstDIEOffset(); 151 uint32_t next_cu_offset = getNextCompileUnitOffset(); 152 153 DWARFDebugInfoEntryMinimal die; 154 // Keep a flat array of the DIE for binary lookup by DIE offset 155 uint32_t depth = 0; 156 // We are in our compile unit, parse starting at the offset 157 // we were told to parse 158 159 const uint8_t *fixed_form_sizes = 160 DWARFFormValue::getFixedFormSizesForAddressSize(getAddressByteSize()); 161 162 while (offset < next_cu_offset && 163 die.extractFast(this, fixed_form_sizes, &offset)) { 164 165 if (depth == 0) { 166 uint64_t base_addr = 167 die.getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); 168 if (base_addr == -1U) 169 base_addr = die.getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); 170 setBaseAddress(base_addr); 171 } 172 173 if (cu_die_only) { 174 addDIE(die); 175 return 1; 176 } 177 else if (depth == 0 && initial_die_array_size == 1) { 178 // Don't append the CU die as we already did that 179 } else { 180 addDIE (die); 181 } 182 183 const DWARFAbbreviationDeclaration *abbrDecl = 184 die.getAbbreviationDeclarationPtr(); 185 if (abbrDecl) { 186 // Normal DIE 187 if (abbrDecl->hasChildren()) 188 ++depth; 189 } else { 190 // NULL DIE. 191 if (depth > 0) 192 --depth; 193 if (depth == 0) 194 break; // We are done with this compile unit! 195 } 196 197 } 198 199 // Give a little bit of info if we encounter corrupt DWARF (our offset 200 // should always terminate at or before the start of the next compilation 201 // unit header). 202 if (offset > next_cu_offset) { 203 fprintf (stderr, "warning: DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), offset); 204 } 205 206 setDIERelations(); 207 return DieArray.size(); 208} 209 210void DWARFCompileUnit::clearDIEs(bool keep_compile_unit_die) { 211 if (DieArray.size() > (unsigned)keep_compile_unit_die) { 212 // std::vectors never get any smaller when resized to a smaller size, 213 // or when clear() or erase() are called, the size will report that it 214 // is smaller, but the memory allocated remains intact (call capacity() 215 // to see this). So we need to create a temporary vector and swap the 216 // contents which will cause just the internal pointers to be swapped 217 // so that when "tmp_array" goes out of scope, it will destroy the 218 // contents. 219 220 // Save at least the compile unit DIE 221 std::vector<DWARFDebugInfoEntryMinimal> tmpArray; 222 DieArray.swap(tmpArray); 223 if (keep_compile_unit_die) 224 DieArray.push_back(tmpArray.front()); 225 } 226} 227 228void 229DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, 230 bool clear_dies_if_already_not_parsed){ 231 // This function is usually called if there in no .debug_aranges section 232 // in order to produce a compile unit level set of address ranges that 233 // is accurate. If the DIEs weren't parsed, then we don't want all dies for 234 // all compile units to stay loaded when they weren't needed. So we can end 235 // up parsing the DWARF and then throwing them all away to keep memory usage 236 // down. 237 const bool clear_dies = extractDIEsIfNeeded(false) > 1 && 238 clear_dies_if_already_not_parsed; 239 DieArray[0].buildAddressRangeTable(this, debug_aranges); 240 241 // Keep memory down by clearing DIEs if this generate function 242 // caused them to be parsed. 243 if (clear_dies) 244 clearDIEs(true); 245} 246 247const DWARFDebugInfoEntryMinimal* 248DWARFCompileUnit::getFunctionDIEForAddress(int64_t address) { 249 extractDIEsIfNeeded(false); 250 for (size_t i = 0, n = DieArray.size(); i != n; i++) { 251 if (DieArray[i].addressRangeContainsAddress(this, address)) 252 return &DieArray[i]; 253 } 254 return 0; 255} 256