bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); uint64_t AbbrOffset = debug_info.getU32(offset_ptr); if (IndexEntry) { if (AbbrOffset) return false; auto *UnitContrib = IndexEntry->getOffset(); if (!UnitContrib || UnitContrib->Length != (Length + 4)) return false; auto *AbbrEntry = IndexEntry->getOffset(DW_SECT_ABBREV); if (!AbbrEntry) return false; AbbrOffset = AbbrEntry->Offset; } AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(Version); bool AddrSizeOK = AddrSize == 4 || AddrSize == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); return Abbrevs != nullptr; }
bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { clear(); Offset = *offset_ptr; if (debug_info.isValidOffset(*offset_ptr)) { uint64_t abbrOffset; Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); abbrOffset = debug_info.getU32(offset_ptr); AddrSize = debug_info.getU8(offset_ptr); bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1); bool versionOK = DWARFContext::isSupportedVersion(Version); bool abbrOffsetOK = AbbrevSection.size() > abbrOffset; bool addrSizeOK = AddrSize == 4 || AddrSize == 8; if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && Abbrev != NULL) { Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); return true; } // reset the offset to where we tried to parse from if anything went wrong *offset_ptr = Offset; } return false; }
bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) { uint32_t Offset = 0; if (!Header.parse(IndexData, &Offset)) return false; if (!IndexData.isValidOffsetForDataOfSize( Offset, Header.NumBuckets * (8 + 4) + (2 * Header.NumUnits + 1) * 4 * Header.NumColumns)) return false; Rows = llvm::make_unique<Entry[]>(Header.NumBuckets); auto Contribs = llvm::make_unique<Entry::SectionContribution *[]>(Header.NumUnits); ColumnKinds = llvm::make_unique<DWARFSectionKind[]>(Header.NumColumns); // Read Hash Table of Signatures for (unsigned i = 0; i != Header.NumBuckets; ++i) Rows[i].Signature = IndexData.getU64(&Offset); // Read Parallel Table of Indexes for (unsigned i = 0; i != Header.NumBuckets; ++i) { auto Index = IndexData.getU32(&Offset); if (!Index) continue; Rows[i].Index = this; Rows[i].Contributions = llvm::make_unique<Entry::SectionContribution[]>(Header.NumColumns); Contribs[Index - 1] = Rows[i].Contributions.get(); } // Read the Column Headers for (unsigned i = 0; i != Header.NumColumns; ++i) { ColumnKinds[i] = static_cast<DWARFSectionKind>(IndexData.getU32(&Offset)); if (ColumnKinds[i] == InfoColumnKind) { if (InfoColumn != -1) return false; InfoColumn = i; } } if (InfoColumn == -1) return false; // Read Table of Section Offsets for (unsigned i = 0; i != Header.NumUnits; ++i) { auto *Contrib = Contribs[i]; for (unsigned i = 0; i != Header.NumColumns; ++i) Contrib[i].Offset = IndexData.getU32(&Offset); } // Read Table of Section Sizes for (unsigned i = 0; i != Header.NumUnits; ++i) { auto *Contrib = Contribs[i]; for (unsigned i = 0; i != Header.NumColumns; ++i) Contrib[i].Length = IndexData.getU32(&Offset); } return true; }
bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data, uint32_t *offset_ptr) { const uint32_t prologue_offset = *offset_ptr; clear(); TotalLength = debug_line_data.getU32(offset_ptr); Version = debug_line_data.getU16(offset_ptr); if (Version < 2) return false; PrologueLength = debug_line_data.getU32(offset_ptr); const uint32_t end_prologue_offset = PrologueLength + *offset_ptr; MinInstLength = debug_line_data.getU8(offset_ptr); if (Version >= 4) MaxOpsPerInst = debug_line_data.getU8(offset_ptr); DefaultIsStmt = debug_line_data.getU8(offset_ptr); LineBase = debug_line_data.getU8(offset_ptr); LineRange = debug_line_data.getU8(offset_ptr); OpcodeBase = debug_line_data.getU8(offset_ptr); StandardOpcodeLengths.reserve(OpcodeBase - 1); for (uint32_t i = 1; i < OpcodeBase; ++i) { uint8_t op_len = debug_line_data.getU8(offset_ptr); StandardOpcodeLengths.push_back(op_len); } while (*offset_ptr < end_prologue_offset) { const char *s = debug_line_data.getCStr(offset_ptr); if (s && s[0]) IncludeDirectories.push_back(s); else break; } while (*offset_ptr < end_prologue_offset) { const char *name = debug_line_data.getCStr(offset_ptr); if (name && name[0]) { FileNameEntry fileEntry; fileEntry.Name = name; fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); fileEntry.Length = debug_line_data.getULEB128(offset_ptr); FileNames.push_back(fileEntry); } else { break; } } if (*offset_ptr != end_prologue_offset) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8x should" " have ended at 0x%8.8x but it ended at 0x%8.8x\n", prologue_offset, end_prologue_offset, *offset_ptr); return false; } return true; }
bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, uint32_t *OffsetPtr) { if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16)) return false; Version = IndexData.getU32(OffsetPtr); NumColumns = IndexData.getU32(OffsetPtr); NumUnits = IndexData.getU32(OffsetPtr); NumBuckets = IndexData.getU32(OffsetPtr); return Version <= 2; }
Optional<DWARFDebugLocDWO::LocationList> DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { LocationList LL; LL.Offset = *Offset; // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. while (auto Kind = static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) { if (Kind != dwarf::DW_LLE_startx_length) { llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind << " not implemented\n"; return None; } Entry E; E.Start = Data.getULEB128(Offset); E.Length = Data.getU32(Offset); unsigned Bytes = Data.getU16(Offset); // A single location description describing the location of the object... StringRef str = Data.getData().substr(*Offset, Bytes); *Offset += Bytes; E.Loc.resize(str.size()); std::copy(str.begin(), str.end(), E.Loc.begin()); LL.Entries.push_back(std::move(E)); } return LL; }
void DWARFDebugLocDWO::parse(DataExtractor data) { uint32_t Offset = 0; while (data.isValidOffset(Offset)) { Locations.resize(Locations.size() + 1); LocationList &Loc = Locations.back(); Loc.Offset = Offset; dwarf::LocationListEntry Kind; while ((Kind = static_cast<dwarf::LocationListEntry>( data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { if (Kind != dwarf::DW_LLE_startx_length) { llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind << " not implemented\n"; return; } Entry E; E.Start = data.getULEB128(&Offset); E.Length = data.getU32(&Offset); unsigned Bytes = data.getU16(&Offset); // A single location description describing the location of the object... StringRef str = data.getData().substr(Offset, Bytes); Offset += Bytes; E.Loc.resize(str.size()); std::copy(str.begin(), str.end(), E.Loc.begin()); Loc.Entries.push_back(std::move(E)); } } }
bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); uint64_t abbrOffset = debug_info.getU32(offset_ptr); AddrSize = debug_info.getU8(offset_ptr); bool lengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool versionOK = DWARFContext::isSupportedVersion(Version); bool abbrOffsetOK = AbbrevSection.size() > abbrOffset; bool addrSizeOK = AddrSize == 4 || AddrSize == 8; if (!lengthOK || !versionOK || !addrSizeOK || !abbrOffsetOK) return false; Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); return true; }
bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { if (!DWARFUnit::extractImpl(debug_info, offset_ptr)) return false; TypeHash = debug_info.getU64(offset_ptr); TypeOffset = debug_info.getU32(offset_ptr); return TypeOffset < getLength(); }
bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); uint64_t AbbrOffset = debug_info.getU32(offset_ptr); AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(Version); bool AddrSizeOK = AddrSize == 4 || AddrSize == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); if (Abbrevs == nullptr) return false; return true; }
bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { if (!DWARFUnit::extractImpl(debug_info, offset_ptr)) return false; TypeHash = debug_info.getU64(offset_ptr); TypeOffset = debug_info.getU32(offset_ptr); // TypeOffset is relative to the beginning of the header, // so we have to account for the leading length field. // FIXME: The size of the length field is 12 in DWARF64. unsigned SizeOfLength = 4; return TypeOffset < getLength() + SizeOfLength; }
static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset, unsigned Encoding) { switch (getSizeForEncoding(Data, Encoding)) { case 2: return Data.getU16(&Offset); case 4: return Data.getU32(&Offset); case 8: return Data.getU64(&Offset); default: llvm_unreachable("Illegal data size"); } }
uint32_t DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data, const DWARFAbbreviationDeclarationSet *abbrevs) { clear(); Offset = offset; if (debug_info_data.isValidOffset(offset)) { Length = debug_info_data.getU32(&offset); Version = debug_info_data.getU16(&offset); bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset(); Abbrevs = abbrevs; AddrSize = debug_info_data.getU8(&offset); bool versionOK = DWARFContext::isSupportedVersion(Version); bool addrSizeOK = AddrSize == 4 || AddrSize == 8; if (versionOK && addrSizeOK && abbrevsOK && debug_info_data.isValidOffset(offset)) return offset; } return 0; }
bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); // FIXME: Support DWARF64. FormParams.Format = DWARF32; FormParams.Version = debug_info.getU16(offset_ptr); if (FormParams.Version >= 5) { UnitType = debug_info.getU8(offset_ptr); FormParams.AddrSize = debug_info.getU8(offset_ptr); AbbrOffset = debug_info.getU32(offset_ptr); } else { AbbrOffset = debug_info.getU32(offset_ptr); FormParams.AddrSize = debug_info.getU8(offset_ptr); } if (IndexEntry) { if (AbbrOffset) return false; auto *UnitContrib = IndexEntry->getOffset(); if (!UnitContrib || UnitContrib->Length != (Length + 4)) return false; auto *AbbrEntry = IndexEntry->getOffset(DW_SECT_ABBREV); if (!AbbrEntry) return false; AbbrOffset = AbbrEntry->Offset; } bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; // Keep track of the highest DWARF version we encounter across all units. Context.setMaxVersionIfGreater(getVersion()); return true; }
/// State transition when a CustomEventMarker is encountered. Error processCustomEventMarker(FDRState &State, uint8_t RecordFirstByte, DataExtractor &RecordExtractor, size_t &RecordSize) { // We can encounter a CustomEventMarker anywhere in the log, so we can handle // it regardless of the expectation. However, we do se the expectation to read // a set number of fixed bytes, as described in the metadata. uint32_t OffsetPtr = 1; // Read after the first byte. uint32_t DataSize = RecordExtractor.getU32(&OffsetPtr); uint64_t TSC = RecordExtractor.getU64(&OffsetPtr); // FIXME: Actually represent the record through the API. For now we only skip // through the data. (void)TSC; RecordSize = 16 + DataSize; return Error::success(); }
void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset) { while (*Offset < EndOffset) { uint8_t Opcode = Data.getU8(Offset); // Some instructions have a primary opcode encoded in the top bits. uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; if (Primary) { // If it's a primary opcode, the first operand is encoded in the bottom // bits of the opcode itself. uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; switch (Primary) { default: llvm_unreachable("Impossible primary CFI opcode"); case DW_CFA_advance_loc: case DW_CFA_restore: addInstruction(Primary, Op1); break; case DW_CFA_offset: addInstruction(Primary, Op1, Data.getULEB128(Offset)); break; } } else { // Extended opcode - its value is Opcode itself. switch (Opcode) { default: llvm_unreachable("Invalid extended CFI opcode"); case DW_CFA_nop: case DW_CFA_remember_state: case DW_CFA_restore_state: case DW_CFA_GNU_window_save: // No operands addInstruction(Opcode); break; case DW_CFA_set_loc: // Operands: Address addInstruction(Opcode, Data.getAddress(Offset)); break; case DW_CFA_advance_loc1: // Operands: 1-byte delta addInstruction(Opcode, Data.getU8(Offset)); break; case DW_CFA_advance_loc2: // Operands: 2-byte delta addInstruction(Opcode, Data.getU16(Offset)); break; case DW_CFA_advance_loc4: // Operands: 4-byte delta addInstruction(Opcode, Data.getU32(Offset)); break; case DW_CFA_restore_extended: case DW_CFA_undefined: case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: // Operands: ULEB128 addInstruction(Opcode, Data.getULEB128(Offset)); break; case DW_CFA_def_cfa_offset_sf: // Operands: SLEB128 addInstruction(Opcode, Data.getSLEB128(Offset)); break; case DW_CFA_offset_extended: case DW_CFA_register: case DW_CFA_def_cfa: case DW_CFA_val_offset: // Operands: ULEB128, ULEB128 addInstruction(Opcode, Data.getULEB128(Offset), Data.getULEB128(Offset)); break; case DW_CFA_offset_extended_sf: case DW_CFA_def_cfa_sf: case DW_CFA_val_offset_sf: // Operands: ULEB128, SLEB128 addInstruction(Opcode, Data.getULEB128(Offset), Data.getSLEB128(Offset)); break; case DW_CFA_def_cfa_expression: case DW_CFA_expression: case DW_CFA_val_expression: // TODO: implement this report_fatal_error("Values with expressions not implemented yet!"); } } } }
void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; DenseMap<uint32_t, CIE *> CIEs; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; if (Length == UINT32_MAX) { // DWARF-64 is distinguished by the first 32 bits of the initial length // field being 0xffffffff. Then, the next 64 bits are the actual entry // length. IsDWARF64 = true; Length = Data.getU64(&Offset); } // At this point, Offset points to the next field after Length. // Length is the structure size excluding itself. Compute an offset one // past the end of the structure (needed to know how many instructions to // read). // TODO: For honest DWARF64 support, DataExtractor will have to treat // offset_ptr as uint64_t* uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); // The Id field's size depends on the DWARF format Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); if (IsCIE) { uint8_t Version = Data.getU8(&Offset); const char *Augmentation = Data.getCStr(&Offset); uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset); Data.setAddressSize(AddressSize); uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); auto Cie = make_unique<CIE>(StartOffset, Length, Version, StringRef(Augmentation), AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor, ReturnAddressRegister); CIEs[StartOffset] = Cie.get(); Entries.emplace_back(std::move(Cie)); } else { // FDE uint64_t CIEPointer = Id; uint64_t InitialLocation = Data.getAddress(&Offset); uint64_t AddressRange = Data.getAddress(&Offset); Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer, InitialLocation, AddressRange, CIEs[CIEPointer])); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) { std::string Str; raw_string_ostream OS(Str); OS << format("Parsing entry instructions at %lx failed", StartOffset); report_fatal_error(Str); } } }
bool DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *cu) { bool indirect = false; do { 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: { uint64_t size = debug_info_data.getULEB128(offset_ptr); *offset_ptr += size; return true; } case DW_FORM_block1: { uint8_t size = debug_info_data.getU8(offset_ptr); *offset_ptr += size; return true; } case DW_FORM_block2: { uint16_t size = debug_info_data.getU16(offset_ptr); *offset_ptr += size; return true; } case DW_FORM_block4: { uint32_t size = debug_info_data.getU32(offset_ptr); *offset_ptr += size; return true; } // Inlined NULL terminated C-strings case DW_FORM_string: debug_info_data.getCStr(offset_ptr); return true; // Compile unit address sized values case DW_FORM_addr: *offset_ptr += cu->getAddressByteSize(); return true; case DW_FORM_ref_addr: *offset_ptr += getRefAddrSize(cu->getAddressByteSize(), cu->getVersion()); return true; // 0 byte values - implied from the form. case DW_FORM_flag_present: return true; // 1 byte values case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: *offset_ptr += 1; return true; // 2 byte values case DW_FORM_data2: case DW_FORM_ref2: *offset_ptr += 2; return true; // 4 byte values case DW_FORM_strp: case DW_FORM_data4: case DW_FORM_ref4: *offset_ptr += 4; return true; // 8 byte values case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sig8: *offset_ptr += 8; return true; // signed or unsigned LEB 128 values // case DW_FORM_APPLE_db_str: 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_ptr); return true; case DW_FORM_indirect: indirect = true; form = debug_info_data.getULEB128(offset_ptr); break; // FIXME: 4 for DWARF32, 8 for DWARF64. case DW_FORM_sec_offset: *offset_ptr += 4; return true; default: return false; } } while (indirect); return true; }
bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFUnit *cu) { bool indirect = false; bool is_block = false; Value.data = nullptr; // Read the value for the form into value and follow and DW_FORM_indirect // instances we run into do { indirect = false; switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { uint16_t AddrSize = (Form == DW_FORM_addr) ? cu->getAddressByteSize() : getRefAddrSize(cu->getAddressByteSize(), cu->getVersion()); RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second; } else Value.uval = data.getUnsigned(offset_ptr, AddrSize); break; } case DW_FORM_exprloc: case DW_FORM_block: Value.uval = data.getULEB128(offset_ptr); is_block = true; break; case DW_FORM_block1: Value.uval = data.getU8(offset_ptr); is_block = true; break; case DW_FORM_block2: Value.uval = data.getU16(offset_ptr); is_block = true; break; case DW_FORM_block4: Value.uval = data.getU32(offset_ptr); is_block = true; break; case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: Value.uval = data.getU8(offset_ptr); break; case DW_FORM_data2: case DW_FORM_ref2: Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: case DW_FORM_ref4: { RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); Value.uval = data.getU32(offset_ptr); if (AI != cu->getRelocMap()->end()) Value.uval += AI->second.second; break; } case DW_FORM_data8: case DW_FORM_ref8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_sdata: Value.sval = data.getSLEB128(offset_ptr); break; case DW_FORM_strp: { RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getU32(offset_ptr) + R.second; } else Value.uval = data.getU32(offset_ptr); break; } case DW_FORM_udata: case DW_FORM_ref_udata: Value.uval = data.getULEB128(offset_ptr); break; case DW_FORM_string: Value.cstr = data.getCStr(offset_ptr); break; case DW_FORM_indirect: Form = data.getULEB128(offset_ptr); indirect = true; break; case DW_FORM_sec_offset: { // FIXME: This is 64-bit for DWARF64. RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getU32(offset_ptr) + R.second; } else Value.uval = data.getU32(offset_ptr); break; } case DW_FORM_flag_present: Value.uval = 1; break; case DW_FORM_ref_sig8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: Value.uval = data.getULEB128(offset_ptr); break; default: return false; } } while (indirect); if (is_block) { StringRef str = data.getData().substr(*offset_ptr, Value.uval); Value.data = nullptr; if (!str.empty()) { Value.data = reinterpret_cast<const uint8_t *>(str.data()); *offset_ptr += Value.uval; } } return true; }
void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; DenseMap<uint32_t, CIE *> CIEs; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; auto ReportError = [StartOffset](const char *ErrorMsg) { std::string Str; raw_string_ostream OS(Str); OS << format(ErrorMsg, StartOffset); OS.flush(); report_fatal_error(Str); }; bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; if (Length == UINT32_MAX) { // DWARF-64 is distinguished by the first 32 bits of the initial length // field being 0xffffffff. Then, the next 64 bits are the actual entry // length. IsDWARF64 = true; Length = Data.getU64(&Offset); } // At this point, Offset points to the next field after Length. // Length is the structure size excluding itself. Compute an offset one // past the end of the structure (needed to know how many instructions to // read). // TODO: For honest DWARF64 support, DataExtractor will have to treat // offset_ptr as uint64_t* uint32_t StartStructureOffset = Offset; uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); // The Id field's size depends on the DWARF format Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4); bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id)); if (IsCIE) { uint8_t Version = Data.getU8(&Offset); const char *Augmentation = Data.getCStr(&Offset); StringRef AugmentationString(Augmentation ? Augmentation : ""); uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset); Data.setAddressSize(AddressSize); uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); // Parse the augmentation data for EH CIEs StringRef AugmentationData(""); uint32_t FDEPointerEncoding = DW_EH_PE_omit; uint32_t LSDAPointerEncoding = DW_EH_PE_omit; if (IsEH) { Optional<uint32_t> PersonalityEncoding; Optional<uint64_t> Personality; Optional<uint64_t> AugmentationLength; uint32_t StartAugmentationOffset; uint32_t EndAugmentationOffset; // Walk the augmentation string to get all the augmentation data. for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { switch (AugmentationString[i]) { default: ReportError("Unknown augmentation character in entry at %lx"); case 'L': LSDAPointerEncoding = Data.getU8(&Offset); break; case 'P': { if (Personality) ReportError("Duplicate personality in entry at %lx"); PersonalityEncoding = Data.getU8(&Offset); Personality = readPointer(Data, Offset, *PersonalityEncoding); break; } case 'R': FDEPointerEncoding = Data.getU8(&Offset); break; case 'z': if (i) ReportError("'z' must be the first character at %lx"); // Parse the augmentation length first. We only parse it if // the string contains a 'z'. AugmentationLength = Data.getULEB128(&Offset); StartAugmentationOffset = Offset; EndAugmentationOffset = Offset + static_cast<uint32_t>(*AugmentationLength); } } if (AugmentationLength.hasValue()) { if (Offset != EndAugmentationOffset) ReportError("Parsing augmentation data at %lx failed"); AugmentationData = Data.getData().slice(StartAugmentationOffset, EndAugmentationOffset); } } auto Cie = make_unique<CIE>(StartOffset, Length, Version, AugmentationString, AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor, ReturnAddressRegister, AugmentationData, FDEPointerEncoding, LSDAPointerEncoding); CIEs[StartOffset] = Cie.get(); Entries.emplace_back(std::move(Cie)); } else { // FDE uint64_t CIEPointer = Id; uint64_t InitialLocation = 0; uint64_t AddressRange = 0; CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; if (IsEH) { // The address size is encoded in the CIE we reference. if (!Cie) ReportError("Parsing FDE data at %lx failed due to missing CIE"); InitialLocation = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); AddressRange = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); StringRef AugmentationString = Cie->getAugmentationString(); if (!AugmentationString.empty()) { // Parse the augmentation length and data for this FDE. uint64_t AugmentationLength = Data.getULEB128(&Offset); uint32_t EndAugmentationOffset = Offset + static_cast<uint32_t>(AugmentationLength); // Decode the LSDA if the CIE augmentation string said we should. if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) readPointer(Data, Offset, Cie->getLSDAPointerEncoding()); if (Offset != EndAugmentationOffset) ReportError("Parsing augmentation data at %lx failed"); } } else { InitialLocation = Data.getAddress(&Offset); AddressRange = Data.getAddress(&Offset); } Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer, InitialLocation, AddressRange, Cie)); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) ReportError("Parsing entry instructions at %lx failed"); } }
void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset) { while (*Offset < EndOffset) { uint8_t Opcode = Data.getU8(Offset); // Some instructions have a primary opcode encoded in the top bits. uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; if (Primary) { // If it's a primary opcode, the first operand is encoded in the bottom // bits of the opcode itself. uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; switch (Primary) { default: llvm_unreachable("Impossible primary CFI opcode"); case DW_CFA_advance_loc: case DW_CFA_restore: addInstruction(Primary, Op1); break; case DW_CFA_offset: addInstruction(Primary, Op1, Data.getULEB128(Offset)); break; } } else { // Extended opcode - its value is Opcode itself. switch (Opcode) { default: llvm_unreachable("Invalid extended CFI opcode"); case DW_CFA_nop: case DW_CFA_remember_state: case DW_CFA_restore_state: case DW_CFA_GNU_window_save: // No operands addInstruction(Opcode); break; case DW_CFA_set_loc: // Operands: Address addInstruction(Opcode, Data.getAddress(Offset)); break; case DW_CFA_advance_loc1: // Operands: 1-byte delta addInstruction(Opcode, Data.getU8(Offset)); break; case DW_CFA_advance_loc2: // Operands: 2-byte delta addInstruction(Opcode, Data.getU16(Offset)); break; case DW_CFA_advance_loc4: // Operands: 4-byte delta addInstruction(Opcode, Data.getU32(Offset)); break; case DW_CFA_restore_extended: case DW_CFA_undefined: case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: case DW_CFA_GNU_args_size: // Operands: ULEB128 addInstruction(Opcode, Data.getULEB128(Offset)); break; case DW_CFA_def_cfa_offset_sf: // Operands: SLEB128 addInstruction(Opcode, Data.getSLEB128(Offset)); break; case DW_CFA_offset_extended: case DW_CFA_register: case DW_CFA_def_cfa: case DW_CFA_val_offset: { // Operands: ULEB128, ULEB128 // Note: We can not embed getULEB128 directly into function // argument list. getULEB128 changes Offset and order of evaluation // for arguments is unspecified. auto op1 = Data.getULEB128(Offset); auto op2 = Data.getULEB128(Offset); addInstruction(Opcode, op1, op2); break; } case DW_CFA_offset_extended_sf: case DW_CFA_def_cfa_sf: case DW_CFA_val_offset_sf: { // Operands: ULEB128, SLEB128 // Note: see comment for the previous case auto op1 = Data.getULEB128(Offset); auto op2 = (uint64_t)Data.getSLEB128(Offset); addInstruction(Opcode, op1, op2); break; } case DW_CFA_def_cfa_expression: // FIXME: Parse the actual instruction. *Offset += Data.getULEB128(Offset); break; case DW_CFA_expression: case DW_CFA_val_expression: { // FIXME: Parse the actual instruction. Data.getULEB128(Offset); *Offset += Data.getULEB128(Offset); break; } } } } }
bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFCompileUnit *cu) { bool indirect = false; bool is_block = false; Value.data = NULL; // Read the value for the form into value and follow and DW_FORM_indirect // instances we run into do { indirect = false; switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize()); break; case DW_FORM_block: Value.uval = data.getULEB128(offset_ptr); is_block = true; break; case DW_FORM_block1: Value.uval = data.getU8(offset_ptr); is_block = true; break; case DW_FORM_block2: Value.uval = data.getU16(offset_ptr); is_block = true; break; case DW_FORM_block4: Value.uval = data.getU32(offset_ptr); is_block = true; break; case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: Value.uval = data.getU8(offset_ptr); break; case DW_FORM_data2: case DW_FORM_ref2: Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: case DW_FORM_ref4: Value.uval = data.getU32(offset_ptr); break; case DW_FORM_data8: case DW_FORM_ref8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_sdata: Value.sval = data.getSLEB128(offset_ptr); break; case DW_FORM_strp: Value.uval = data.getU32(offset_ptr); break; case DW_FORM_udata: case DW_FORM_ref_udata: Value.uval = data.getULEB128(offset_ptr); break; case DW_FORM_string: Value.cstr = data.getCStr(offset_ptr); // Set the string value to also be the data for inlined cstr form // values only so we can tell the differnence between DW_FORM_string // and DW_FORM_strp form values Value.data = (uint8_t*)Value.cstr; break; case DW_FORM_indirect: Form = data.getULEB128(offset_ptr); indirect = true; break; default: return false; } } while (indirect); if (is_block) { StringRef str = data.getData().substr(*offset_ptr, Value.uval); Value.data = NULL; if (!str.empty()) { Value.data = reinterpret_cast<const uint8_t *>(str.data()); *offset_ptr += Value.uval; } } return true; }
void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; if (Length == UINT32_MAX) { // DWARF-64 is distinguished by the first 32 bits of the initial length // field being 0xffffffff. Then, the next 64 bits are the actual entry // length. IsDWARF64 = true; Length = Data.getU64(&Offset); } // At this point, Offset points to the next field after Length. // Length is the structure size excluding itself. Compute an offset one // past the end of the structure (needed to know how many instructions to // read). // TODO: For honest DWARF64 support, DataExtractor will have to treat // offset_ptr as uint64_t* uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); // The Id field's size depends on the DWARF format Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); if (IsCIE) { // Note: this is specifically DWARFv3 CIE header structure. It was // changed in DWARFv4. We currently don't support reading DWARFv4 // here because LLVM itself does not emit it (and LLDB doesn't // support it either). uint8_t Version = Data.getU8(&Offset); const char *Augmentation = Data.getCStr(&Offset); uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); Entries.emplace_back(new CIE(StartOffset, Length, Version, StringRef(Augmentation), CodeAlignmentFactor, DataAlignmentFactor, ReturnAddressRegister)); } else { // FDE uint64_t CIEPointer = Id; uint64_t InitialLocation = Data.getAddress(&Offset); uint64_t AddressRange = Data.getAddress(&Offset); Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer, InitialLocation, AddressRange)); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) { string_ostream Str; Str << format("Parsing entry instructions at %lx failed", StartOffset); report_fatal_error(Str.str()); } } }
bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFCompileUnit *cu) { bool indirect = false; bool is_block = false; Value.data = NULL; // Read the value for the form into value and follow and DW_FORM_indirect // instances we run into do { indirect = false; switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize()) + R.second; } else Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize()); break; } case DW_FORM_exprloc: case DW_FORM_block: Value.uval = data.getULEB128(offset_ptr); is_block = true; break; case DW_FORM_block1: Value.uval = data.getU8(offset_ptr); is_block = true; break; case DW_FORM_block2: Value.uval = data.getU16(offset_ptr); is_block = true; break; case DW_FORM_block4: Value.uval = data.getU32(offset_ptr); is_block = true; break; case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: Value.uval = data.getU8(offset_ptr); break; case DW_FORM_data2: case DW_FORM_ref2: Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: case DW_FORM_ref4: Value.uval = data.getU32(offset_ptr); break; case DW_FORM_data8: case DW_FORM_ref8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_sdata: Value.sval = data.getSLEB128(offset_ptr); break; case DW_FORM_strp: { RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getU32(offset_ptr) + R.second; } else Value.uval = data.getU32(offset_ptr); break; } case DW_FORM_udata: case DW_FORM_ref_udata: Value.uval = data.getULEB128(offset_ptr); break; case DW_FORM_string: Value.cstr = data.getCStr(offset_ptr); // Set the string value to also be the data for inlined cstr form // values only so we can tell the differnence between DW_FORM_string // and DW_FORM_strp form values Value.data = (const uint8_t*)Value.cstr; break; case DW_FORM_indirect: Form = data.getULEB128(offset_ptr); indirect = true; break; case DW_FORM_sec_offset: // FIXME: This is 64-bit for DWARF64. Value.uval = data.getU32(offset_ptr); break; case DW_FORM_flag_present: Value.uval = 1; break; case DW_FORM_ref_sig8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_GNU_addr_index: Value.uval = data.getULEB128(offset_ptr); break; case DW_FORM_GNU_str_index: Value.uval = data.getULEB128(offset_ptr); break; default: return false; } } while (indirect); if (is_block) { StringRef str = data.getData().substr(*offset_ptr, Value.uval); Value.data = NULL; if (!str.empty()) { Value.data = reinterpret_cast<const uint8_t *>(str.data()); *offset_ptr += Value.uval; } } return true; }
bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, uint32_t *OffsetPtr, const DWARFFormParams Params) { bool Indirect = false; do { switch (Form) { // Blocks of inlined data that have a length field and the data bytes // inlined in the .debug_info. case DW_FORM_exprloc: case DW_FORM_block: { uint64_t size = DebugInfoData.getULEB128(OffsetPtr); *OffsetPtr += size; return true; } case DW_FORM_block1: { uint8_t size = DebugInfoData.getU8(OffsetPtr); *OffsetPtr += size; return true; } case DW_FORM_block2: { uint16_t size = DebugInfoData.getU16(OffsetPtr); *OffsetPtr += size; return true; } case DW_FORM_block4: { uint32_t size = DebugInfoData.getU32(OffsetPtr); *OffsetPtr += size; return true; } // Inlined NULL terminated C-strings. case DW_FORM_string: DebugInfoData.getCStr(OffsetPtr); return true; case DW_FORM_addr: case DW_FORM_ref_addr: case DW_FORM_flag_present: case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_data16: case DW_FORM_flag: case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_sig8: case DW_FORM_ref_sup4: case DW_FORM_ref_sup8: case DW_FORM_strx1: case DW_FORM_strx2: case DW_FORM_strx4: case DW_FORM_addrx1: case DW_FORM_addrx2: case DW_FORM_addrx4: case DW_FORM_sec_offset: case DW_FORM_strp: case DW_FORM_strp_sup: case DW_FORM_line_strp: case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: if (Optional<uint8_t> FixedSize = DWARFFormValue::getFixedByteSize(Form, Params)) { *OffsetPtr += *FixedSize; return true; } return false; // signed or unsigned LEB 128 values. case DW_FORM_sdata: DebugInfoData.getSLEB128(OffsetPtr); return true; case DW_FORM_udata: case DW_FORM_ref_udata: case DW_FORM_strx: case DW_FORM_addrx: case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: DebugInfoData.getULEB128(OffsetPtr); return true; case DW_FORM_indirect: Indirect = true; Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr)); break; default: return false; } } while (Indirect); return true; }