Skip to content

[BOLT][DWARF] Add support for .debug_names #81062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bolt/include/bolt/Core/BinaryContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,10 @@ class BinaryContext {
return getUniqueSectionByName(".gdb_index");
}

ErrorOr<BinarySection &> getDebugNamesSection() const {
return getUniqueSectionByName(".debug_names");
}

/// @}

/// Register \p TargetFunction as a fragment of \p Function if checks pass:
Expand Down
7 changes: 5 additions & 2 deletions bolt/include/bolt/Core/DIEBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define BOLT_CORE_DIE_BUILDER_H

#include "bolt/Core/BinaryContext.h"
#include "bolt/Core/DebugNames.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
Expand Down Expand Up @@ -127,6 +128,7 @@ class DIEBuilder {
DWARFUnit *SkeletonCU{nullptr};
uint64_t UnitSize{0};
llvm::DenseSet<uint64_t> AllProcessed;
DWARF5AcceleratorTable &DebugNamesTable;

/// Returns current state of the DIEBuilder
State &getState() { return *BuilderState.get(); }
Expand Down Expand Up @@ -206,8 +208,8 @@ class DIEBuilder {
/// Update references once the layout is finalized.
void updateReferences();

/// Update the Offset and Size of DIE.
uint32_t computeDIEOffset(const DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
/// Update the Offset and Size of DIE, populate DebugNames table.
uint32_t finalizeDIEs(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);

void registerUnit(DWARFUnit &DU, bool NeedSort);

Expand Down Expand Up @@ -269,6 +271,7 @@ class DIEBuilder {

public:
DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
DWARF5AcceleratorTable &DebugNamesTable,
DWARFUnit *SkeletonCU = nullptr);

/// Returns enum to what we are currently processing.
Expand Down
9 changes: 6 additions & 3 deletions bolt/include/bolt/Core/DebugData.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ class DebugStrOffsetsWriter {
/// Update Str offset in .debug_str in .debug_str_offsets.
void updateAddressMap(uint32_t Index, uint32_t Address);

/// Get offset for given index in original .debug_str_offsets section.
uint64_t getOffset(uint32_t Index) const { return StrOffsets[Index]; }
/// Writes out current sections entry into .debug_str_offsets.
void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr);

Expand All @@ -463,7 +465,7 @@ class DebugStrOffsetsWriter {
std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
std::map<uint32_t, uint32_t> IndexToAddressMap;
std::vector<uint32_t> StrOffsets;
SmallVector<uint32_t, 5> StrOffsets;
std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
bool StrOffsetSectionWasModified = false;
};
Expand All @@ -484,11 +486,12 @@ class DebugStrWriter {
/// Returns False if no strings were added to .debug_str.
bool isInitialized() const { return !StrBuffer->empty(); }

/// Initializes Buffer and Stream.
void initialize();

private:
/// Mutex used for parallel processing of debug info.
std::mutex WriterMutex;
/// Initializes Buffer and Stream.
void initialize();
/// Creates internal data structures.
void create();
std::unique_ptr<DebugStrBufferVector> StrBuffer;
Expand Down
172 changes: 172 additions & 0 deletions bolt/include/bolt/Core/DebugNames.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//===- bolt/Core/DebugNames.h - Debug names support ---*- 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
//
//===----------------------------------------------------------------------===//
//
// This file contains declaration of classes required for generation of
// .debug_names section.
//
//===----------------------------------------------------------------------===//

#ifndef BOLT_CORE_DEBUG_NAMES_H
#define BOLT_CORE_DEBUG_NAMES_H

#include "DebugData.h"
#include "llvm/CodeGen/AccelTable.h"

namespace llvm {
namespace bolt {
class BOLTDWARF5AccelTableData : public DWARF5AccelTableData {
public:
BOLTDWARF5AccelTableData(const uint64_t DieOffset,
const std::optional<uint64_t> DefiningParentOffset,
const unsigned DieTag, const unsigned UnitID,
const bool IsTU,
const std::optional<unsigned> SecondUnitID)
: DWARF5AccelTableData(DieOffset, DefiningParentOffset, DieTag, UnitID,
IsTU),
SecondUnitID(SecondUnitID) {}

uint64_t getDieOffset() const { return DWARF5AccelTableData::getDieOffset(); }
unsigned getDieTag() const { return DWARF5AccelTableData::getDieTag(); }
unsigned getUnitID() const { return DWARF5AccelTableData::getUnitID(); }
bool isTU() const { return DWARF5AccelTableData::isTU(); }
std::optional<unsigned> getSecondUnitID() const { return SecondUnitID; }

private:
std::optional<unsigned> SecondUnitID;
};

class DWARF5AcceleratorTable {
public:
DWARF5AcceleratorTable(const bool CreateDebugNames, BinaryContext &BC,
DebugStrWriter &MainBinaryStrWriter);
~DWARF5AcceleratorTable() {
for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
Abbrev->~DebugNamesAbbrev();
}
/// Add DWARF5 Accelerator table entry.
/// Input is DWARFUnit being processed, DIE that belongs to it, and potential
/// SkeletonCU if the Unit comes from a DWO section.
void addAccelTableEntry(DWARFUnit &Unit, const DIE &Die,
const std::optional<uint64_t> &DWOID);
/// Set current unit being processed.
void setCurrentUnit(DWARFUnit &Unit, const uint64_t UnitStartOffset);
/// Emit Accelerator table.
void emitAccelTable();
/// Returns true if the table was crated.
bool isCreated() const { return NeedToCreate; }
/// Returns buffer containing the accelerator table.
std::unique_ptr<DebugBufferVector> releaseBuffer() {
return std::move(FullTableBuffer);
}

private:
BinaryContext &BC;
bool NeedToCreate = false;
BumpPtrAllocator Allocator;
DebugStrWriter &MainBinaryStrWriter;
StringRef StrSection;
uint64_t CurrentUnitOffset = 0;
const DWARFUnit *CurrentUnit = nullptr;
std::unordered_map<uint32_t, uint32_t> AbbrevTagToIndexMap;

/// Represents a group of entries with identical name (and hence, hash value).
struct HashData {
uint64_t StrOffset;
uint32_t HashValue;
uint32_t EntryOffset;
std::vector<BOLTDWARF5AccelTableData *> Values;
};
using HashList = std::vector<HashData *>;
using BucketList = std::vector<HashList>;
/// Contains all the offsets of CUs.
SmallVector<uint32_t, 1> CUList;
/// Contains all the offsets of local TUs.
SmallVector<uint32_t, 1> LocalTUList;
/// Contains all the type hashes for split dwarf TUs.
SmallVector<uint64_t, 1> ForeignTUList;
using StringEntries =
MapVector<std::string, HashData, llvm::StringMap<unsigned>>;
StringEntries Entries;
/// FoldingSet that uniques the abbreviations.
FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
/// Vector containing DebugNames abbreviations for iteration in order.
SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
/// The bump allocator to use when creating DIEAbbrev objects in the uniqued
/// storage container.
BumpPtrAllocator Alloc;
uint32_t BucketCount = 0;
uint32_t UniqueHashCount = 0;
uint32_t AbbrevTableSize = 0;
uint32_t CUIndexEncodingSize = 4;
uint32_t TUIndexEncodingSize = 4;
uint32_t AugmentationStringSize = 0;
dwarf::Form CUIndexForm = dwarf::DW_FORM_data4;
dwarf::Form TUIndexForm = dwarf::DW_FORM_data4;

BucketList Buckets;

std::unique_ptr<DebugBufferVector> FullTableBuffer;
std::unique_ptr<raw_svector_ostream> FullTableStream;
std::unique_ptr<DebugBufferVector> StrBuffer;
std::unique_ptr<raw_svector_ostream> StrStream;
std::unique_ptr<DebugBufferVector> EntriesBuffer;
std::unique_ptr<raw_svector_ostream> Entriestream;
std::unique_ptr<DebugBufferVector> AugStringBuffer;
std::unique_ptr<raw_svector_ostream> AugStringtream;
llvm::DenseMap<llvm::hash_code, uint64_t> StrCacheToOffsetMap;
// Contains DWO ID to CUList Index.
llvm::DenseMap<uint64_t, uint32_t> CUOffsetsToPatch;
/// Adds Unit to either CUList, LocalTUList or ForeignTUList.
/// Input Unit being processed, and DWO ID if Unit is being processed comes
/// from a DWO section.
void addUnit(DWARFUnit &Unit, const std::optional<uint64_t> &DWOID);
/// Returns number of buckets in .debug_name table.
ArrayRef<HashList> getBuckets() const { return Buckets; }
/// Get encoding for a given attribute.
std::optional<DWARF5AccelTable::UnitIndexAndEncoding>
getIndexForEntry(const BOLTDWARF5AccelTableData &Value) const;
/// Get encoding for a given attribute for second index.
/// Returns nullopt if there is no second index.
std::optional<DWARF5AccelTable::UnitIndexAndEncoding>
getSecondIndexForEntry(const BOLTDWARF5AccelTableData &Value) const;
/// Uniquify Entries.
void finalize();
/// Computes bucket count.
void computeBucketCount();
/// Populate Abbreviations Map.
void populateAbbrevsMap();
/// Write Entries.
void writeEntries();
/// Write an Entry.
void writeEntry(const BOLTDWARF5AccelTableData &Entry);
/// Write augmentation_string for BOLT.
void writeAugmentationString();
/// Emit out Header for DWARF5 Accelerator table.
void emitHeader() const;
/// Emit out CU list.
void emitCUList() const;
/// Emit out TU List. Combination of LocalTUList and ForeignTUList.
void emitTUList() const;
/// Emit buckets.
void emitBuckets() const;
/// Emit hashes for hash table.
void emitHashes() const;
/// Emit string offsets for hash table.
void emitStringOffsets() const;
/// Emit Entry Offsets for hash table.
void emitOffsets() const;
/// Emit abbreviation table.
void emitAbbrevs();
/// Emit entries.
void emitData();
/// Emit augmentation string.
void emitAugmentationString() const;
};
} // namespace bolt
} // namespace llvm
#endif
7 changes: 5 additions & 2 deletions bolt/include/bolt/Rewrite/DWARFRewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "bolt/Core/DIEBuilder.h"
#include "bolt/Core/DebugData.h"
#include "bolt/Core/DebugNames.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DWP/DWP.h"
Expand Down Expand Up @@ -140,8 +141,10 @@ class DWARFRewriter {
const std::list<DWARFUnit *> &CUs);

/// Finalize debug sections in the main binary.
void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
raw_svector_ostream &ObjOS, CUOffsetMap &CUMap);
void finalizeDebugSections(DIEBuilder &DIEBlder,
DWARF5AcceleratorTable &DebugNamesTable,
DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
CUOffsetMap &CUMap);

/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
Expand Down
1 change: 1 addition & 0 deletions bolt/lib/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_llvm_library(LLVMBOLTCore
BinaryFunctionProfile.cpp
BinarySection.cpp
DebugData.cpp
DebugNames.cpp
DIEBuilder.cpp
DynoStats.cpp
Exceptions.cpp
Expand Down
31 changes: 16 additions & 15 deletions bolt/lib/Core/DIEBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,17 @@
#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/YAMLTraits.h"

#include <algorithm>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -179,8 +176,10 @@ void DIEBuilder::constructFromUnit(DWARFUnit &DU) {
}

DIEBuilder::DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
DWARF5AcceleratorTable &DebugNamesTable,
DWARFUnit *SkeletonCU)
: BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU) {}
: BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU),
DebugNamesTable(DebugNamesTable) {}

static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) {
unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits()
Expand Down Expand Up @@ -378,18 +377,20 @@ getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,
return nullptr;
}

uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die,
uint32_t &CurOffset) {
uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
uint32_t &CurOffset) {
getState().DWARFDieAddressesParsed.erase(Die.getOffset());
uint32_t CurSize = 0;
Die.setOffset(CurOffset);
DebugNamesTable.addAccelTableEntry(
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt);
for (DIEValue &Val : Die.values())
CurSize += Val.sizeOf(CU.getFormParams());
CurSize += getULEB128Size(Die.getAbbrevNumber());
CurOffset += CurSize;

for (DIE &Child : Die.children()) {
uint32_t ChildSize = computeDIEOffset(CU, Child, CurOffset);
uint32_t ChildSize = finalizeDIEs(CU, Child, CurOffset);
CurSize += ChildSize;
}
// for children end mark.
Expand All @@ -404,12 +405,12 @@ uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die,
}

void DIEBuilder::finish() {
auto computeOffset = [&](const DWARFUnit &CU,
uint64_t &UnitStartOffset) -> void {
auto finalizeCU = [&](DWARFUnit &CU, uint64_t &UnitStartOffset) -> void {
DIE *UnitDIE = getUnitDIEbyUnit(CU);
uint32_t HeaderSize = CU.getHeaderSize();
uint32_t CurOffset = HeaderSize;
computeDIEOffset(CU, *UnitDIE, CurOffset);
DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);
finalizeDIEs(CU, *UnitDIE, CurOffset);

DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);
CurUnitInfo.UnitOffset = UnitStartOffset;
Expand All @@ -420,18 +421,18 @@ void DIEBuilder::finish() {
// It's processed first when CU is registered so will be at the begginnig of
// the vector.
uint64_t TypeUnitStartOffset = 0;
for (const DWARFUnit *CU : getState().DUList) {
for (DWARFUnit *CU : getState().DUList) {
// We process DWARF$ types first.
if (!(CU->getVersion() < 5 && CU->isTypeUnit()))
break;
computeOffset(*CU, TypeUnitStartOffset);
finalizeCU(*CU, TypeUnitStartOffset);
}

for (const DWARFUnit *CU : getState().DUList) {
for (DWARFUnit *CU : getState().DUList) {
// Skipping DWARF4 types.
if (CU->getVersion() < 5 && CU->isTypeUnit())
continue;
computeOffset(*CU, UnitSize);
finalizeCU(*CU, UnitSize);
}
if (opts::Verbosity >= 1) {
if (!getState().DWARFDieAddressesParsed.empty())
Expand Down
Loading