blob: 624245650a0924bfd5350340bea88463f6bc408c [file] [log] [blame]
//===- bolt/Rewrite/DWARFRewriter.h -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_REWRITE_DWARF_REWRITER_H
#define BOLT_REWRITE_DWARF_REWRITER_H
#include "bolt/Core/DIEBuilder.h"
#include "bolt/Core/DebugData.h"
#include "bolt/Core/DebugNames.h"
#include "bolt/Core/GDBIndex.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/ToolOutputFile.h"
#include <cstdint>
#include <memory>
#include <mutex>
#include <optional>
#include <unordered_map>
#include <vector>
namespace llvm {
namespace bolt {
class BinaryContext;
class DWARFRewriter {
public:
DWARFRewriter() = delete;
/// Contains information about TU so we can write out correct entries in GDB
/// index.
struct GDBIndexTUEntry {
uint64_t UnitOffset;
uint64_t TypeHash;
uint64_t TypeDIERelativeOffset;
};
private:
BinaryContext &BC;
std::mutex DWARFRewriterMutex;
/// Stores and serializes information that will be put into the
/// .debug_ranges DWARF section.
std::unique_ptr<DebugRangesSectionWriter> LegacyRangesSectionWriter;
/// Stores and serializes information that will be put into the
/// .debug_rnglists DWARF section.
std::unique_ptr<DebugRangeListsSectionWriter> RangeListsSectionWriter;
/// Stores and serializes information that will be put into the
/// .debug_aranges DWARF section.
std::unique_ptr<DebugARangesSectionWriter> ARangesSectionWriter;
/// Stores and serializes information that will be put in to the
/// .debug_addr DWARF section.
/// Does not do de-duplication.
std::unique_ptr<DebugStrWriter> StrWriter;
/// Stores and serializes information that will be put in to the
/// .debug_str_offsets DWARF section.
std::unique_ptr<DebugStrOffsetsWriter> StrOffstsWriter;
using LocWriters = std::map<uint64_t, std::unique_ptr<DebugLocWriter>>;
/// Use a separate location list writer for each compilation unit
LocWriters LocListWritersByCU;
using RangeListsDWOWriers =
std::unordered_map<uint64_t,
std::unique_ptr<DebugRangeListsSectionWriter>>;
/// Store Rangelists writer for each DWO CU.
RangeListsDWOWriers RangeListsWritersByCU;
/// Stores ranges writer for each DWO CU.
std::unordered_map<uint64_t, std::unique_ptr<DebugRangesSectionWriter>>
LegacyRangesWritersByCU;
/// Stores address writer for each CU.
std::unordered_map<uint64_t, std::unique_ptr<DebugAddrWriter>>
AddressWritersByCU;
std::mutex LocListDebugInfoPatchesMutex;
std::unordered_map<DWARFUnit *, uint64_t> LineTablePatchMap;
std::unordered_map<const DWARFUnit *, uint64_t> TypeUnitRelocMap;
/// Entries for GDB Index Types CU List
using GDBIndexTUEntryType = std::vector<GDBIndexTUEntry>;
GDBIndexTUEntryType GDBIndexTUEntryVector;
/// DWARFLegacy is all DWARF versions before DWARF 5.
enum class DWARFVersion { DWARFLegacy, DWARF5 };
/// Used to track last CU offset for GDB Index.
uint32_t CUOffset{0};
/// Update debug info for all DIEs in \p Unit.
void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr,
DebugLocWriter &DebugLocWriter,
DebugRangesSectionWriter &RangesSectionWriter,
DebugAddrWriter &AddressWriter,
std::optional<uint64_t> RangesBase = std::nullopt);
/// Patches the binary for an object's address ranges to be updated.
/// The object can be anything that has associated address ranges via either
/// DW_AT_low/high_pc or DW_AT_ranges (i.e. functions, lexical blocks, etc).
/// \p DebugRangesOffset is the offset in .debug_ranges of the object's
/// new address ranges in the output binary.
/// \p Unit Compile unit the object belongs to.
/// \p DIE is the object's DIE in the input binary.
/// \p RangesBase if present, update \p DIE to use DW_AT_GNU_ranges_base
/// attribute.
void updateDWARFObjectAddressRanges(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
uint64_t DebugRangesOffset,
std::optional<uint64_t> RangesBase = std::nullopt);
std::unique_ptr<DebugBufferVector>
makeFinalLocListsSection(DWARFVersion Version);
/// Finalize type sections in the main binary.
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
GDBIndex &GDBIndexSection);
/// Process and write out CUs that are passsed in.
void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
CUOffsetMap &CUMap,
const std::list<DWARFUnit *> &CUs,
DebugAddrWriter &FinalAddrWriter);
/// Finalize debug sections in the main binary.
void finalizeDebugSections(DIEBuilder &DIEBlder,
DWARF5AcceleratorTable &DebugNamesTable,
DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
CUOffsetMap &CUMap,
DebugAddrWriter &FinalAddrWriter);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
void updateDebugAddressRanges();
/// DWARFDie contains a pointer to a DIE and hence gets invalidated once the
/// embedded DIE is destroyed. This wrapper class stores a DIE internally and
/// could be cast to a DWARFDie that is valid even after the initial DIE is
/// destroyed.
struct DWARFDieWrapper {
DWARFUnit *Unit;
DWARFDebugInfoEntry DIE;
DWARFDieWrapper(DWARFUnit *Unit, DWARFDebugInfoEntry DIE)
: Unit(Unit), DIE(DIE) {}
DWARFDieWrapper(DWARFDie &Die)
: Unit(Die.getDwarfUnit()), DIE(*Die.getDebugInfoEntry()) {}
operator DWARFDie() { return DWARFDie(Unit, &DIE); }
};
/// Update \p DIE that was using DW_AT_(low|high)_pc with DW_AT_ranges offset.
/// Updates to the DIE should be synced with abbreviation updates using the
/// function above.
void convertToRangesPatchDebugInfo(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
DIEValue &HighPCAttrInfo,
std::optional<uint64_t> RangesBase = std::nullopt);
public:
DWARFRewriter(BinaryContext &BC) : BC(BC) {}
/// Main function for updating the DWARF debug info.
void updateDebugInfo();
/// Update stmt_list for CUs based on the new .debug_line \p Layout.
void updateLineTableOffsets(const MCAssembler &Asm);
using OverriddenSectionsMap = std::unordered_map<DWARFSectionKind, StringRef>;
/// Output .dwo files.
void writeDWOFiles(DWARFUnit &, const OverriddenSectionsMap &,
const std::string &, DebugLocWriter &,
DebugStrOffsetsWriter &, DebugStrWriter &,
DebugRangesSectionWriter &);
using KnownSectionsEntry = std::pair<MCSection *, DWARFSectionKind>;
};
} // namespace bolt
} // namespace llvm
#endif