+ Attr->set(Streamer->getRangesSectionSize());
+ Streamer->emitUnitRangesEntries(Unit, static_cast<bool>(Attr));
+}
+
+/// \brief Insert the new line info sequence \p Seq into the current
+/// set of already linked line info \p Rows.
+static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
+ std::vector<DWARFDebugLine::Row> &Rows) {
+ if (Seq.empty())
+ return;
+
+ if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
+ Rows.insert(Rows.end(), Seq.begin(), Seq.end());
+ Seq.clear();
+ return;
+ }
+
+ auto InsertPoint = std::lower_bound(
+ Rows.begin(), Rows.end(), Seq.front(),
+ [](const DWARFDebugLine::Row &LHS, const DWARFDebugLine::Row &RHS) {
+ return LHS.Address < RHS.Address;
+ });
+
+ // FIXME: this only removes the unneeded end_sequence if the
+ // sequences have been inserted in order. using a global sort like
+ // described in patchLineTableForUnit() and delaying the end_sequene
+ // elimination to emitLineTableForUnit() we can get rid of all of them.
+ if (InsertPoint != Rows.end() &&
+ InsertPoint->Address == Seq.front().Address && InsertPoint->EndSequence) {
+ *InsertPoint = Seq.front();
+ Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
+ } else {
+ Rows.insert(InsertPoint, Seq.begin(), Seq.end());
+ }
+
+ Seq.clear();
+}
+
+static void patchStmtList(DIE &Die, DIEInteger Offset) {
+ for (auto &V : Die.values())
+ if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
+ V = DIEValue(V.getAttribute(), V.getForm(), Offset);
+ return;
+ }
+
+ llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");
+}
+
+/// \brief Extract the line table for \p Unit from \p OrigDwarf, and
+/// recreate a relocated version of these for the address ranges that
+/// are present in the binary.
+void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
+ DWARFContext &OrigDwarf) {
+ const DWARFDebugInfoEntryMinimal *CUDie = Unit.getOrigUnit().getUnitDIE();
+ uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset(
+ &Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL);
+ if (StmtList == -1ULL)
+ return;
+
+ // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
+ if (auto *OutputDIE = Unit.getOutputUnitDIE())
+ patchStmtList(*OutputDIE, DIEInteger(Streamer->getLineSectionSize()));
+
+ // Parse the original line info for the unit.
+ DWARFDebugLine::LineTable LineTable;
+ uint32_t StmtOffset = StmtList;
+ StringRef LineData = OrigDwarf.getLineSection().Data;
+ DataExtractor LineExtractor(LineData, OrigDwarf.isLittleEndian(),
+ Unit.getOrigUnit().getAddressByteSize());
+ LineTable.parse(LineExtractor, &OrigDwarf.getLineSection().Relocs,
+ &StmtOffset);
+
+ // This vector is the output line table.
+ std::vector<DWARFDebugLine::Row> NewRows;
+ NewRows.reserve(LineTable.Rows.size());
+
+ // Current sequence of rows being extracted, before being inserted
+ // in NewRows.
+ std::vector<DWARFDebugLine::Row> Seq;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
+
+ // FIXME: This logic is meant to generate exactly the same output as
+ // Darwin's classic dsynutil. There is a nicer way to implement this
+ // by simply putting all the relocated line info in NewRows and simply
+ // sorting NewRows before passing it to emitLineTableForUnit. This
+ // should be correct as sequences for a function should stay
+ // together in the sorted output. There are a few corner cases that
+ // look suspicious though, and that required to implement the logic
+ // this way. Revisit that once initial validation is finished.
+
+ // Iterate over the object file line info and extract the sequences
+ // that correspond to linked functions.
+ for (auto &Row : LineTable.Rows) {
+ // Check wether we stepped out of the range. The range is
+ // half-open, but consider accept the end address of the range if
+ // it is marked as end_sequence in the input (because in that
+ // case, the relocation offset is accurate and that entry won't
+ // serve as the start of another function).
+ if (CurrRange == InvalidRange || Row.Address < CurrRange.start() ||
+ Row.Address > CurrRange.stop() ||
+ (Row.Address == CurrRange.stop() && !Row.EndSequence)) {
+ // We just stepped out of a known range. Insert a end_sequence
+ // corresponding to the end of the range.
+ uint64_t StopAddress = CurrRange != InvalidRange
+ ? CurrRange.stop() + CurrRange.value()
+ : -1ULL;
+ CurrRange = FunctionRanges.find(Row.Address);
+ bool CurrRangeValid =
+ CurrRange != InvalidRange && CurrRange.start() <= Row.Address;
+ if (!CurrRangeValid) {
+ CurrRange = InvalidRange;
+ if (StopAddress != -1ULL) {
+ // Try harder by looking in the DebugMapObject function
+ // ranges map. There are corner cases where this finds a
+ // valid entry. It's unclear if this is right or wrong, but
+ // for now do as dsymutil.
+ // FIXME: Understand exactly what cases this addresses and
+ // potentially remove it along with the Ranges map.
+ auto Range = Ranges.lower_bound(Row.Address);
+ if (Range != Ranges.begin() && Range != Ranges.end())
+ --Range;
+
+ if (Range != Ranges.end() && Range->first <= Row.Address &&
+ Range->second.first >= Row.Address) {
+ StopAddress = Row.Address + Range->second.second;
+ }
+ }
+ }
+ if (StopAddress != -1ULL && !Seq.empty()) {
+ // Insert end sequence row with the computed end address, but
+ // the same line as the previous one.
+ Seq.emplace_back(Seq.back());
+ Seq.back().Address = StopAddress;
+ Seq.back().EndSequence = 1;
+ Seq.back().PrologueEnd = 0;
+ Seq.back().BasicBlock = 0;
+ Seq.back().EpilogueBegin = 0;
+ insertLineSequence(Seq, NewRows);
+ }
+
+ if (!CurrRangeValid)
+ continue;
+ }
+
+ // Ignore empty sequences.
+ if (Row.EndSequence && Seq.empty())
+ continue;
+
+ // Relocate row address and add it to the current sequence.
+ Row.Address += CurrRange.value();
+ Seq.emplace_back(Row);
+
+ if (Row.EndSequence)
+ insertLineSequence(Seq, NewRows);
+ }
+
+ // Finished extracting, now emit the line tables.
+ uint32_t PrologueEnd = StmtList + 10 + LineTable.Prologue.PrologueLength;
+ // FIXME: LLVM hardcodes it's prologue values. We just copy the
+ // prologue over and that works because we act as both producer and
+ // consumer. It would be nicer to have a real configurable line
+ // table emitter.
+ if (LineTable.Prologue.Version != 2 ||
+ LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
+ LineTable.Prologue.OpcodeBase > 13)
+ reportWarning("line table paramters mismatch. Cannot emit.");
+ else {
+ MCDwarfLineTableParams Params;
+ Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
+ Params.DWARF2LineBase = LineTable.Prologue.LineBase;
+ Params.DWARF2LineRange = LineTable.Prologue.LineRange;
+ Streamer->emitLineTableForUnit(Params,
+ LineData.slice(StmtList + 4, PrologueEnd),
+ LineTable.Prologue.MinInstLength, NewRows,
+ Unit.getOrigUnit().getAddressByteSize());
+ }
+}
+
+void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
+ Streamer->emitPubNamesForUnit(Unit);
+ Streamer->emitPubTypesForUnit(Unit);
+}
+
+/// \brief Read the frame info stored in the object, and emit the
+/// patched frame descriptions for the linked binary.
+///
+/// This is actually pretty easy as the data of the CIEs and FDEs can
+/// be considered as black boxes and moved as is. The only thing to do
+/// is to patch the addresses in the headers.
+void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO,
+ DWARFContext &OrigDwarf,
+ unsigned AddrSize) {
+ StringRef FrameData = OrigDwarf.getDebugFrameSection();
+ if (FrameData.empty())
+ return;
+
+ DataExtractor Data(FrameData, OrigDwarf.isLittleEndian(), 0);
+ uint32_t InputOffset = 0;
+
+ // Store the data of the CIEs defined in this object, keyed by their
+ // offsets.
+ DenseMap<uint32_t, StringRef> LocalCIES;
+
+ while (Data.isValidOffset(InputOffset)) {
+ uint32_t EntryOffset = InputOffset;
+ uint32_t InitialLength = Data.getU32(&InputOffset);
+ if (InitialLength == 0xFFFFFFFF)
+ return reportWarning("Dwarf64 bits no supported");
+
+ uint32_t CIEId = Data.getU32(&InputOffset);
+ if (CIEId == 0xFFFFFFFF) {
+ // This is a CIE, store it.
+ StringRef CIEData = FrameData.substr(EntryOffset, InitialLength + 4);
+ LocalCIES[EntryOffset] = CIEData;
+ // The -4 is to account for the CIEId we just read.
+ InputOffset += InitialLength - 4;
+ continue;
+ }
+
+ uint32_t Loc = Data.getUnsigned(&InputOffset, AddrSize);
+
+ // Some compilers seem to emit frame info that doesn't start at
+ // the function entry point, thus we can't just lookup the address
+ // in the debug map. Use the linker's range map to see if the FDE
+ // describes something that we can relocate.
+ auto Range = Ranges.upper_bound(Loc);
+ if (Range != Ranges.begin())
+ --Range;
+ if (Range == Ranges.end() || Range->first > Loc ||
+ Range->second.first <= Loc) {
+ // The +4 is to account for the size of the InitialLength field itself.
+ InputOffset = EntryOffset + InitialLength + 4;
+ continue;
+ }
+
+ // This is an FDE, and we have a mapping.
+ // Have we already emitted a corresponding CIE?
+ StringRef CIEData = LocalCIES[CIEId];
+ if (CIEData.empty())
+ return reportWarning("Inconsistent debug_frame content. Dropping.");
+
+ // Look if we already emitted a CIE that corresponds to the
+ // referenced one (the CIE data is the key of that lookup).
+ auto IteratorInserted = EmittedCIEs.insert(
+ std::make_pair(CIEData, Streamer->getFrameSectionSize()));
+ // If there is no CIE yet for this ID, emit it.
+ if (IteratorInserted.second ||
+ // FIXME: dsymutil-classic only caches the last used CIE for
+ // reuse. Mimic that behavior for now. Just removing that
+ // second half of the condition and the LastCIEOffset variable
+ // makes the code DTRT.
+ LastCIEOffset != IteratorInserted.first->getValue()) {
+ LastCIEOffset = Streamer->getFrameSectionSize();
+ IteratorInserted.first->getValue() = LastCIEOffset;
+ Streamer->emitCIE(CIEData);
+ }
+
+ // Emit the FDE with updated address and CIE pointer.
+ // (4 + AddrSize) is the size of the CIEId + initial_location
+ // fields that will get reconstructed by emitFDE().
+ unsigned FDERemainingBytes = InitialLength - (4 + AddrSize);
+ Streamer->emitFDE(IteratorInserted.first->getValue(), AddrSize,
+ Loc + Range->second.second,
+ FrameData.substr(InputOffset, FDERemainingBytes));
+ InputOffset += FDERemainingBytes;
+ }
+}
+
+ErrorOr<const object::ObjectFile &>
+DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
+ const DebugMap &Map) {
+ auto ErrOrObjs =
+ BinaryHolder.GetObjectFiles(Obj.getObjectFilename(), Obj.getTimestamp());
+ if (std::error_code EC = ErrOrObjs.getError())
+ reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
+ auto ErrOrObj = BinaryHolder.Get(Map.getTriple());
+ if (std::error_code EC = ErrOrObj.getError())
+ reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
+ return ErrOrObj;