void TargetLoweringObjectFileCOFF:: emitModuleFlags(MCStreamer &Streamer, ArrayRef<Module::ModuleFlagEntry> ModuleFlags, Mangler &Mang, const TargetMachine &TM) const { MDNode *LinkerOptions = nullptr; // Look for the "Linker Options" flag, since it's the only one we support. for (ArrayRef<Module::ModuleFlagEntry>::iterator i = ModuleFlags.begin(), e = ModuleFlags.end(); i != e; ++i) { const Module::ModuleFlagEntry &MFE = *i; StringRef Key = MFE.Key->getString(); Metadata *Val = MFE.Val; if (Key == "Linker Options") { LinkerOptions = cast<MDNode>(Val); break; } } if (!LinkerOptions) return; // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for linker. const MCSection *Sec = getDrectveSection(); Streamer.SwitchSection(Sec); for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { MDNode *MDOptions = cast<MDNode>(LinkerOptions->getOperand(i)); for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { MDString *MDOption = cast<MDString>(MDOptions->getOperand(ii)); // Lead with a space for consistency with our dllexport implementation. std::string Directive(" "); Directive.append(MDOption->getString()); Streamer.EmitBytes(Directive); } } }
static void addAllTypesFromDWP( MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) { Out.SwitchSection(OutputTypes); for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { auto *I = E.getOffsets(); if (!I) continue; auto P = TypeIndexEntries.insert(std::make_pair(E.getSignature(), TUEntry)); if (!P.second) continue; auto &Entry = P.first->second; // Zero out the debug_info contribution Entry.Contributions[0] = {}; for (auto Kind : TUIndex.getColumnKinds()) { auto &C = Entry.Contributions[Kind - DW_SECT_INFO]; C.Offset += I->Offset; C.Length = I->Length; ++I; } auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; Out.EmitBytes(Types.substr( C.Offset - TUEntry.Contributions[DW_SECT_TYPES - DW_SECT_INFO].Offset, C.Length)); C.Offset = TypesOffset; TypesOffset += C.Length; } }
static void addAllTypes(MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, MCSection *OutputTypes, const std::vector<StringRef> &TypesSections, const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { for (StringRef Types : TypesSections) { Out.SwitchSection(OutputTypes); uint32_t Offset = 0; DataExtractor Data(Types, true, 0); while (Data.isValidOffset(Offset)) { UnitIndexEntry Entry = CUEntry; // Zero out the debug_info contribution Entry.Contributions[0] = {}; auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; C.Offset = TypesOffset; auto PrevOffset = Offset; // Length of the unit, including the 4 byte length field. C.Length = Data.getU32(&Offset) + 4; Data.getU16(&Offset); // Version Data.getU32(&Offset); // Abbrev offset Data.getU8(&Offset); // Address size auto Signature = Data.getU64(&Offset); Offset = PrevOffset + C.Length; auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); if (!P.second) continue; Out.EmitBytes(Types.substr(PrevOffset, C.Length)); TypesOffset += C.Length; } } }
void TargetLoweringObjectFileCOFF::emitModuleFlags( MCStreamer &Streamer, ArrayRef<Module::ModuleFlagEntry> ModuleFlags, const TargetMachine &TM) const { MDNode *LinkerOptions = nullptr; for (const auto &MFE : ModuleFlags) { StringRef Key = MFE.Key->getString(); if (Key == "Linker Options") LinkerOptions = cast<MDNode>(MFE.Val); } if (LinkerOptions) { // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for // linker. MCSection *Sec = getDrectveSection(); Streamer.SwitchSection(Sec); for (const auto &Option : LinkerOptions->operands()) { for (const auto &Piece : cast<MDNode>(Option)->operands()) { // Lead with a space for consistency with our dllexport implementation. std::string Directive(" "); Directive.append(cast<MDString>(Piece)->getString()); Streamer.EmitBytes(Directive); } } } }
static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) { // Microsoft's linker seems to have trouble with symbol names longer than // 0xffd8 bytes. S = S.substr(0, 0xffd8); SmallString<32> NullTerminatedString(S); NullTerminatedString.push_back('\0'); OS.EmitBytes(NullTerminatedString); }
/// \brief Emit the optimal amount of multi-byte nops on X86. static void EmitNops(MCStreamer &OS, unsigned NumBytes, bool Is64Bit, const MCSubtargetInfo &STI) { // This works only for 64bit. For 32bit we have to do additional checking if // the CPU supports multi-byte nops. assert(Is64Bit && "EmitNops only supports X86-64"); while (NumBytes) { unsigned Opc, BaseReg, ScaleVal, IndexReg, Displacement, SegmentReg; Opc = IndexReg = Displacement = SegmentReg = 0; BaseReg = X86::RAX; ScaleVal = 1; switch (NumBytes) { case 0: llvm_unreachable("Zero nops?"); break; case 1: NumBytes -= 1; Opc = X86::NOOP; break; case 2: NumBytes -= 2; Opc = X86::XCHG16ar; break; case 3: NumBytes -= 3; Opc = X86::NOOPL; break; case 4: NumBytes -= 4; Opc = X86::NOOPL; Displacement = 8; break; case 5: NumBytes -= 5; Opc = X86::NOOPL; Displacement = 8; IndexReg = X86::RAX; break; case 6: NumBytes -= 6; Opc = X86::NOOPW; Displacement = 8; IndexReg = X86::RAX; break; case 7: NumBytes -= 7; Opc = X86::NOOPL; Displacement = 512; break; case 8: NumBytes -= 8; Opc = X86::NOOPL; Displacement = 512; IndexReg = X86::RAX; break; case 9: NumBytes -= 9; Opc = X86::NOOPW; Displacement = 512; IndexReg = X86::RAX; break; default: NumBytes -= 10; Opc = X86::NOOPW; Displacement = 512; IndexReg = X86::RAX; SegmentReg = X86::CS; break; } unsigned NumPrefixes = std::min(NumBytes, 5U); NumBytes -= NumPrefixes; for (unsigned i = 0; i != NumPrefixes; ++i) OS.EmitBytes("\x66"); switch (Opc) { default: llvm_unreachable("Unexpected opcode"); break; case X86::NOOP: OS.EmitInstruction(MCInstBuilder(Opc), STI); break; case X86::XCHG16ar: OS.EmitInstruction(MCInstBuilder(Opc).addReg(X86::AX), STI); break; case X86::NOOPL: case X86::NOOPW: OS.EmitInstruction(MCInstBuilder(Opc).addReg(BaseReg).addImm(ScaleVal) .addReg(IndexReg) .addImm(Displacement) .addReg(SegmentReg), STI); break; } } // while (NumBytes) }
void TargetLoweringObjectFileCOFF:: emitModuleFlags(MCStreamer &Streamer, ArrayRef<Module::ModuleFlagEntry> ModuleFlags, Mangler &Mang, const TargetMachine &TM) const { MDNode *LinkerOptions = nullptr; // Look for the "Linker Options" flag, since it's the only one we support. for (ArrayRef<Module::ModuleFlagEntry>::iterator i = ModuleFlags.begin(), e = ModuleFlags.end(); i != e; ++i) { const Module::ModuleFlagEntry &MFE = *i; StringRef Key = MFE.Key->getString(); Value *Val = MFE.Val; if (Key == "Linker Options") { LinkerOptions = cast<MDNode>(Val); break; } } if (!LinkerOptions) return; // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for linker. const MCSection *Sec = getDrectveSection(); Streamer.SwitchSection(Sec); for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { MDNode *MDOptions = cast<MDNode>(LinkerOptions->getOperand(i)); for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { MDString *MDOption = cast<MDString>(MDOptions->getOperand(ii)); StringRef Op = MDOption->getString(); // Lead with a space for consistency with our dllexport implementation. std::string Escaped(" "); if (Op.find(" ") != StringRef::npos) { // The PE-COFF spec says args with spaces must be quoted. It doesn't say // how to escape quotes, but it probably uses this algorithm: // http://msdn.microsoft.com/en-us/library/17w5ykft(v=vs.85).aspx // FIXME: Reuse escaping code from Support/Windows/Program.inc Escaped.push_back('\"'); Escaped.append(Op); Escaped.push_back('\"'); } else { Escaped.append(Op); } Streamer.EmitBytes(Escaped); } } }
static std::error_code writeStringsAndOffsets(MCStreamer &Out, StringMap<uint32_t> &Strings, uint32_t &StringOffset, MCSection *StrSection, MCSection *StrOffsetSection, StringRef CurStrSection, StringRef CurStrOffsetSection) { // Could possibly produce an error or warning if one of these was non-null but // the other was null. if (CurStrSection.empty() || CurStrOffsetSection.empty()) return std::error_code(); DenseMap<uint32_t, uint32_t> OffsetRemapping; DataExtractor Data(CurStrSection, true, 0); uint32_t LocalOffset = 0; uint32_t PrevOffset = 0; while (const char *s = Data.getCStr(&LocalOffset)) { StringRef Str(s, LocalOffset - PrevOffset - 1); auto Pair = Strings.insert(std::make_pair(Str, StringOffset)); if (Pair.second) { Out.SwitchSection(StrSection); Out.EmitBytes( StringRef(Pair.first->getKeyData(), Pair.first->getKeyLength() + 1)); StringOffset += Str.size() + 1; } OffsetRemapping[PrevOffset] = Pair.first->second; PrevOffset = LocalOffset; } Data = DataExtractor(CurStrOffsetSection, true, 0); Out.SwitchSection(StrOffsetSection); uint32_t Offset = 0; uint64_t Size = CurStrOffsetSection.size(); while (Offset < Size) { auto OldOffset = Data.getU32(&Offset); auto NewOffset = OffsetRemapping[OldOffset]; Out.EmitIntValue(NewOffset, 4); } return std::error_code(); }
static void addAllTypes(MCStreamer &Out, std::vector<UnitIndexEntry> &TypeIndexEntries, MCSection *OutputTypes, StringRef Types, const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { if (Types.empty()) return; Out.SwitchSection(OutputTypes); uint32_t Offset = 0; DataExtractor Data(Types, true, 0); while (Data.isValidOffset(Offset)) { UnitIndexEntry Entry = CUEntry; // Zero out the debug_info contribution Entry.Contributions[0] = {}; auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; C.Offset = TypesOffset; auto PrevOffset = Offset; // Length of the unit, including the 4 byte length field. C.Length = Data.getU32(&Offset) + 4; Data.getU16(&Offset); // Version Data.getU32(&Offset); // Abbrev offset Data.getU8(&Offset); // Address size Entry.Signature = Data.getU64(&Offset); Offset = PrevOffset + C.Length; if (any_of(TypeIndexEntries, [&](const UnitIndexEntry &E) { return E.Signature == Entry.Signature; })) continue; Out.EmitBytes(Types.substr(PrevOffset, C.Length)); TypesOffset += C.Length; TypeIndexEntries.push_back(Entry); } }
void TargetLoweringObjectFileCOFF::emitModuleMetadata( MCStreamer &Streamer, Module &M, const TargetMachine &TM) const { if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for // linker. MCSection *Sec = getDrectveSection(); Streamer.SwitchSection(Sec); for (const auto &Option : LinkerOptions->operands()) { for (const auto &Piece : cast<MDNode>(Option)->operands()) { // Lead with a space for consistency with our dllexport implementation. std::string Directive(" "); Directive.append(cast<MDString>(Piece)->getString()); Streamer.EmitBytes(Directive); } } } unsigned Version = 0; unsigned Flags = 0; StringRef Section; GetObjCImageInfo(M, Version, Flags, Section); if (Section.empty()) return; auto &C = getContext(); auto *S = C.getCOFFSection( Section, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); Streamer.SwitchSection(S); Streamer.EmitLabel(C.getOrCreateSymbol(StringRef("OBJC_IMAGE_INFO"))); Streamer.EmitIntValue(Version, 4); Streamer.EmitIntValue(Flags, 4); Streamer.AddBlankLine(); }
static std::error_code write(MCStreamer &Out, ArrayRef<std::string> Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = { {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}}, {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, {"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}}, {"debug_tu_index", {TUIndexSection, static_cast<DWARFSectionKind>(0)}}}; MapVector<uint64_t, UnitIndexEntry> IndexEntries; MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries; StringMap<uint32_t> Strings; uint32_t StringOffset = 0; uint32_t ContributionOffsets[8] = {}; for (const auto &Input : Inputs) { auto ErrOrObj = object::ObjectFile::createObjectFile(Input); if (!ErrOrObj) return errorToErrorCode(ErrOrObj.takeError()); UnitIndexEntry CurEntry = {}; StringRef CurStrSection; StringRef CurStrOffsetSection; std::vector<StringRef> CurTypesSection; StringRef InfoSection; StringRef AbbrevSection; StringRef CurCUIndexSection; StringRef CurTUIndexSection; SmallVector<SmallString<32>, 4> UncompressedSections; for (const auto &Section : ErrOrObj->getBinary()->sections()) { if (Section.isBSS()) continue; if (Section.isVirtual()) continue; StringRef Name; if (std::error_code Err = Section.getName(Name)) return Err; Name = Name.substr(Name.find_first_not_of("._")); StringRef Contents; if (auto Err = Section.getContents(Contents)) return Err; if (Name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(Contents, OriginalSize)) return make_error_code(std::errc::invalid_argument); UncompressedSections.resize(UncompressedSections.size() + 1); if (zlib::uncompress(Contents, UncompressedSections.back(), OriginalSize) != zlib::StatusOK) { UncompressedSections.pop_back(); continue; } Name = Name.substr(1); Contents = UncompressedSections.back(); } auto SectionPair = KnownSections.find(Name); if (SectionPair == KnownSections.end()) continue; if (DWARFSectionKind Kind = SectionPair->second.second) { auto Index = Kind - DW_SECT_INFO; if (Kind != DW_SECT_TYPES) { CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; ContributionOffsets[Index] += (CurEntry.Contributions[Index].Length = Contents.size()); } switch (Kind) { case DW_SECT_INFO: InfoSection = Contents; break; case DW_SECT_ABBREV: AbbrevSection = Contents; break; default: break; } } MCSection *OutSection = SectionPair->second.first; if (OutSection == StrOffsetSection) CurStrOffsetSection = Contents; else if (OutSection == StrSection) CurStrSection = Contents; else if (OutSection == TypesSection) CurTypesSection.push_back(Contents); else if (OutSection == CUIndexSection) CurCUIndexSection = Contents; else if (OutSection == TUIndexSection) CurTUIndexSection = Contents; else { Out.SwitchSection(OutSection); Out.EmitBytes(Contents); } } if (InfoSection.empty()) continue; if (!CurCUIndexSection.empty()) { DWARFUnitIndex CUIndex(DW_SECT_INFO); DataExtractor CUIndexData(CurCUIndexSection, ErrOrObj->getBinary()->isLittleEndian(), 0); if (!CUIndex.parse(CUIndexData)) return make_error_code(std::errc::invalid_argument); for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { auto *I = E.getOffsets(); if (!I) continue; auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); CompileUnitIdentifiers ID = getCUIdentifiers( getSubsection(AbbrevSection, E, DW_SECT_ABBREV), getSubsection(InfoSection, E, DW_SECT_INFO), getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), CurStrSection); if (!P.second) { printDuplicateError(*P.first, ID, Input); return make_error_code(std::errc::invalid_argument); } auto &NewEntry = P.first->second; NewEntry.Name = ID.Name; NewEntry.DWOName = ID.DWOName; NewEntry.DWPName = Input; for (auto Kind : CUIndex.getColumnKinds()) { auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; C.Offset += I->Offset; C.Length = I->Length; ++I; } } if (!CurTypesSection.empty()) { assert(CurTypesSection.size() == 1); if (CurTUIndexSection.empty()) return make_error_code(std::errc::invalid_argument); DWARFUnitIndex TUIndex(DW_SECT_TYPES); DataExtractor TUIndexData(CurTUIndexSection, ErrOrObj->getBinary()->isLittleEndian(), 0); if (!TUIndex.parse(TUIndexData)) return make_error_code(std::errc::invalid_argument); addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(), CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); } } else { CompileUnitIdentifiers ID = getCUIdentifiers( AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); if (!P.second) { printDuplicateError(*P.first, ID, ""); return make_error_code(std::errc::invalid_argument); } P.first->second.Name = ID.Name; P.first->second.DWOName = ID.DWOName; addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); } if (auto Err = writeStringsAndOffsets(Out, Strings, StringOffset, StrSection, StrOffsetSection, CurStrSection, CurStrOffsetSection)) return Err; } // Lie about there being no info contributions so the TU index only includes // the type unit contribution ContributionOffsets[0] = 0; writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, TypeIndexEntries); // Lie about the type contribution ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0; // Unlie about the info contribution ContributionOffsets[0] = 1; writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, IndexEntries); return std::error_code(); }
static std::error_code write(MCStreamer &Out, ArrayRef<std::string> Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = { {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}}, {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}}; struct UnitIndexEntry { uint64_t Signature; DWARFUnitIndex::Entry::SectionContribution Contributions[8]; }; std::vector<UnitIndexEntry> IndexEntries; StringMap<uint32_t> Strings; uint32_t StringOffset = 0; uint64_t UnitIndex = 0; uint32_t ContributionOffsets[8] = {}; for (const auto &Input : Inputs) { auto ErrOrObj = object::ObjectFile::createObjectFile(Input); if (!ErrOrObj) return ErrOrObj.getError(); IndexEntries.emplace_back(); UnitIndexEntry &CurEntry = IndexEntries.back(); CurEntry.Signature = UnitIndex++; StringRef CurStrSection; StringRef CurStrOffsetSection; for (const auto &Section : ErrOrObj->getBinary()->sections()) { StringRef Name; if (std::error_code Err = Section.getName(Name)) return Err; auto SectionPair = KnownSections.find(Name.substr(Name.find_first_not_of("._"))); if (SectionPair == KnownSections.end()) continue; StringRef Contents; if (auto Err = Section.getContents(Contents)) return Err; if (DWARFSectionKind Kind = SectionPair->second.second) { auto Index = Kind - DW_SECT_INFO; CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; ContributionOffsets[Index] += (CurEntry.Contributions[Index].Length = Contents.size()); } MCSection *OutSection = SectionPair->second.first; if (OutSection == StrOffsetSection) CurStrOffsetSection = Contents; else if (OutSection == StrSection) CurStrSection = Contents; else { Out.SwitchSection(OutSection); Out.EmitBytes(Contents); } } if (auto Err = writeStringsAndOffsets(Out, Strings, StringOffset, StrSection, StrOffsetSection, CurStrSection, CurStrOffsetSection)) return Err; } Out.SwitchSection(MCOFI.getDwarfCUIndexSection()); Out.EmitIntValue(2, 4); // Version Out.EmitIntValue(8, 4); // Columns Out.EmitIntValue(IndexEntries.size(), 4); // Num Units // FIXME: This is not the right number of buckets for a real hash. Out.EmitIntValue(IndexEntries.size(), 4); // Num Buckets // Write the signatures. for (const auto &E : IndexEntries) Out.EmitIntValue(E.Signature, 8); // Write the indexes. for (size_t i = 0; i != IndexEntries.size(); ++i) Out.EmitIntValue(i + 1, 4); // Write the column headers (which sections will appear in the table) for (size_t i = 1; i != 9; ++i) Out.EmitIntValue(i, 4); // Write the offsets. for (const auto &E : IndexEntries) for (const auto &C : E.Contributions) Out.EmitIntValue(C.Offset, 4); // Write the lengths. for (const auto &E : IndexEntries) for (const auto &C : E.Contributions) Out.EmitIntValue(C.Length, 4); return std::error_code(); }
template <typename T> static void emitRecord(MCStreamer &OS, const T &Rec) { OS.EmitBytes(StringRef(reinterpret_cast<const char *>(&Rec), sizeof(Rec))); }
void EmitCFIInstruction(MCStreamer &Streamer, const MCCFIInstruction &Instr, int &CFAOffset, int DataAlignmentFactor) { // Same as MCDwarf::EmitCFIInstruction () // FIXME: Unify int dataAlignmentFactor = DataAlignmentFactor; bool VerboseAsm = Streamer.isVerboseAsm(); switch (Instr.getOperation()) { case MCCFIInstruction::OpWindowSave: { Streamer.EmitIntValue(dwarf::DW_CFA_GNU_window_save, 1); return; } case MCCFIInstruction::OpUndefined: { unsigned Reg = Instr.getRegister(); if (VerboseAsm) { Streamer.AddComment("DW_CFA_undefined"); Streamer.AddComment(Twine("Reg ") + Twine(Reg)); } Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1); Streamer.EmitULEB128IntValue(Reg); return; } case MCCFIInstruction::OpAdjustCfaOffset: case MCCFIInstruction::OpDefCfaOffset: { const bool IsRelative = Instr.getOperation() == MCCFIInstruction::OpAdjustCfaOffset; if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_offset"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); if (IsRelative) CFAOffset += Instr.getOffset(); else // The backends pass in a negative value, // then createDefCfaOffset () negates it CFAOffset = Instr.getOffset(); if (VerboseAsm) Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); Streamer.EmitULEB128IntValue(CFAOffset); return; } case MCCFIInstruction::OpDefCfa: { if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); Streamer.EmitULEB128IntValue(Instr.getRegister()); // Backends pass a negative value to createDefCfa () which // negates it back CFAOffset = Instr.getOffset(); if (VerboseAsm) Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); Streamer.EmitULEB128IntValue(CFAOffset); return; } case MCCFIInstruction::OpDefCfaRegister: { if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_register"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); Streamer.EmitULEB128IntValue(Instr.getRegister()); return; } case MCCFIInstruction::OpOffset: case MCCFIInstruction::OpRelOffset: { const bool IsRelative = Instr.getOperation() == MCCFIInstruction::OpRelOffset; unsigned Reg = Instr.getRegister(); int Offset = Instr.getOffset(); if (IsRelative) Offset -= CFAOffset; Offset = Offset / dataAlignmentFactor; if (Offset < 0) { if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended_sf"); Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitSLEB128IntValue(Offset); } else if (Reg < 64) { if (VerboseAsm) Streamer.AddComment(Twine("DW_CFA_offset + Reg(") + Twine(Reg) + ")"); Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitULEB128IntValue(Offset); } else { if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended"); Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitULEB128IntValue(Offset); } return; } case MCCFIInstruction::OpRememberState: if (VerboseAsm) Streamer.AddComment("DW_CFA_remember_state"); Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); return; case MCCFIInstruction::OpRestoreState: if (VerboseAsm) Streamer.AddComment("DW_CFA_restore_state"); Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); return; case MCCFIInstruction::OpSameValue: { unsigned Reg = Instr.getRegister(); if (VerboseAsm) Streamer.AddComment("DW_CFA_same_value"); Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); return; } case MCCFIInstruction::OpRestore: { unsigned Reg = Instr.getRegister(); if (VerboseAsm) { Streamer.AddComment("DW_CFA_restore"); Streamer.AddComment(Twine("Reg ") + Twine(Reg)); } Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); return; } case MCCFIInstruction::OpEscape: if (VerboseAsm) Streamer.AddComment("Escape bytes"); Streamer.EmitBytes(Instr.getValues()); return; case MCCFIInstruction::OpRegister: llvm_unreachable("Unhandled case in switch"); return; } llvm_unreachable("Unhandled case in switch"); }
static std::error_code write(MCStreamer &Out, ArrayRef<std::string> Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = { {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}}, {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, {"debug_cu_index", {MCOFI.getDwarfCUIndexSection(), static_cast<DWARFSectionKind>(0)}}}; std::vector<UnitIndexEntry> IndexEntries; std::vector<UnitIndexEntry> TypeIndexEntries; StringMap<uint32_t> Strings; uint32_t StringOffset = 0; uint32_t ContributionOffsets[8] = {}; for (const auto &Input : Inputs) { auto ErrOrObj = object::ObjectFile::createObjectFile(Input); if (!ErrOrObj) return ErrOrObj.getError(); UnitIndexEntry CurEntry = {}; StringRef CurStrSection; StringRef CurStrOffsetSection; StringRef CurTypesSection; StringRef InfoSection; StringRef AbbrevSection; StringRef CurCUIndexSection; for (const auto &Section : ErrOrObj->getBinary()->sections()) { StringRef Name; if (std::error_code Err = Section.getName(Name)) return Err; auto SectionPair = KnownSections.find(Name.substr(Name.find_first_not_of("._"))); if (SectionPair == KnownSections.end()) continue; StringRef Contents; if (auto Err = Section.getContents(Contents)) return Err; if (DWARFSectionKind Kind = SectionPair->second.second) { auto Index = Kind - DW_SECT_INFO; if (Kind != DW_SECT_TYPES) { CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; ContributionOffsets[Index] += (CurEntry.Contributions[Index].Length = Contents.size()); } switch (Kind) { case DW_SECT_INFO: InfoSection = Contents; break; case DW_SECT_ABBREV: AbbrevSection = Contents; break; default: break; } } MCSection *OutSection = SectionPair->second.first; if (OutSection == StrOffsetSection) CurStrOffsetSection = Contents; else if (OutSection == StrSection) CurStrSection = Contents; else if (OutSection == TypesSection) CurTypesSection = Contents; else if (OutSection == CUIndexSection) CurCUIndexSection = Contents; else { Out.SwitchSection(OutSection); Out.EmitBytes(Contents); } } assert(!AbbrevSection.empty()); assert(!InfoSection.empty()); if (!CurCUIndexSection.empty()) { DWARFUnitIndex CUIndex(DW_SECT_INFO); DataExtractor CUIndexData(CurCUIndexSection, ErrOrObj->getBinary()->isLittleEndian(), 0); if (!CUIndex.parse(CUIndexData)) return make_error_code(std::errc::invalid_argument); for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { auto NewEntry = CurEntry; auto *I = E.getOffsets(); if (!I) continue; NewEntry.Signature = E.getSignature(); for (auto Kind : CUIndex.getColumnKinds()) { auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; C.Offset += I->Offset; C.Length = I->Length; ++I; } IndexEntries.push_back(NewEntry); } } else { CurEntry.Signature = getCUSignature(AbbrevSection, InfoSection); addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); IndexEntries.push_back(CurEntry); } if (auto Err = writeStringsAndOffsets(Out, Strings, StringOffset, StrSection, StrOffsetSection, CurStrSection, CurStrOffsetSection)) return Err; } if (!TypeIndexEntries.empty()) { // Lie about there being no info contributions so the TU index only includes // the type unit contribution ContributionOffsets[0] = 0; writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, TypeIndexEntries); } // Lie about the type contribution ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0; // Unlie about the info contribution ContributionOffsets[0] = 1; writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, IndexEntries); return std::error_code(); }