diff options
author | Yonghong Song <yhs@fb.com> | 2018-12-19 16:40:25 +0000 |
---|---|---|
committer | Yonghong Song <yhs@fb.com> | 2018-12-19 16:40:25 +0000 |
commit | 7b410ac352bea299441a34f3b899e728bae460a7 (patch) | |
tree | bc17e744edff0a02e91472f79f9d88c39f657223 /llvm/lib/Target | |
parent | 8d221b40a7963caf19eaedf29f0512f6a09cd994 (diff) | |
download | bcm5719-llvm-7b410ac352bea299441a34f3b899e728bae460a7.tar.gz bcm5719-llvm-7b410ac352bea299441a34f3b899e728bae460a7.zip |
[BPF] Generate BTF DebugInfo under BPF target
This patch implements BTF (BPF Type Format).
The BTF is the debug info format for BPF, introduced
in the below linux patch:
https://github.com/torvalds/linux/commit/69b693f0aefa0ed521e8bd02260523b5ae446ad7#diff-06fb1c8825f653d7e539058b72c83332
and further extended several times, e.g.,
https://www.spinics.net/lists/netdev/msg534640.html
https://www.spinics.net/lists/netdev/msg538464.html
https://www.spinics.net/lists/netdev/msg540246.html
The main advantage of implementing in LLVM is:
. better integration/deployment as no extra tools are needed.
. bpf JIT based compilation (like bcc, bpftrace, etc.) can get
BTF without much extra effort.
. BTF line_info needs selective source codes, which can be
easily retrieved when inside the compiler.
This patch implemented BTF generation by registering a BPF
specific DebugHandler in BPFAsmPrinter.
Signed-off-by: Yonghong Song <yhs@fb.com>
Differential Revision: https://reviews.llvm.org/D55752
llvm-svn: 349640
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Target/BPF/BTF.def | 33 | ||||
-rw-r--r-- | llvm/lib/Target/BPF/BTF.h | 209 | ||||
-rw-r--r-- | llvm/lib/Target/BPF/BTFDebug.cpp | 759 | ||||
-rw-r--r-- | llvm/lib/Target/BPF/BTFDebug.h | 285 | ||||
-rw-r--r-- | llvm/lib/Target/BPF/CMakeLists.txt | 1 |
6 files changed, 1301 insertions, 0 deletions
diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp index 705211b486b..ada5eb923f4 100644 --- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp @@ -16,6 +16,7 @@ #include "BPFInstrInfo.h" #include "BPFMCInstLower.h" #include "BPFTargetMachine.h" +#include "BTFDebug.h" #include "InstPrinter/BPFInstPrinter.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" @@ -40,6 +41,7 @@ public: : AsmPrinter(TM, std::move(Streamer)) {} StringRef getPassName() const override { return "BPF Assembly Printer"; } + bool doInitialization(Module &M) override; void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, @@ -52,6 +54,18 @@ public: }; } // namespace +bool BPFAsmPrinter::doInitialization(Module &M) { + AsmPrinter::doInitialization(M); + + if (MAI->doesSupportDebugInformation()) { + Handlers.push_back(HandlerInfo(new BTFDebug(this), "emit", + "Debug Info Emission", "BTF", + "BTF Emission")); + } + + return false; +} + void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand(OpNum); diff --git a/llvm/lib/Target/BPF/BTF.def b/llvm/lib/Target/BPF/BTF.def new file mode 100644 index 00000000000..54c5bc3cf09 --- /dev/null +++ b/llvm/lib/Target/BPF/BTF.def @@ -0,0 +1,33 @@ +//===- BTF.def - BTF definitions --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Macros for BTF. +// +//===----------------------------------------------------------------------===// + +#if !defined(HANDLE_BTF_KIND) +#error "Missing macro definition of HANDLE_BTF_*" +#endif + +HANDLE_BTF_KIND(0, UNKN) +HANDLE_BTF_KIND(1, INT) +HANDLE_BTF_KIND(2, PTR) +HANDLE_BTF_KIND(3, ARRAY) +HANDLE_BTF_KIND(4, STRUCT) +HANDLE_BTF_KIND(5, UNION) +HANDLE_BTF_KIND(6, ENUM) +HANDLE_BTF_KIND(7, FWD) +HANDLE_BTF_KIND(8, TYPEDEF) +HANDLE_BTF_KIND(9, VOLATILE) +HANDLE_BTF_KIND(10, CONST) +HANDLE_BTF_KIND(11, RESTRICT) +HANDLE_BTF_KIND(12, FUNC) +HANDLE_BTF_KIND(13, FUNC_PROTO) + +#undef HANDLE_BTF_KIND diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h new file mode 100644 index 00000000000..1e1680faf1b --- /dev/null +++ b/llvm/lib/Target/BPF/BTF.h @@ -0,0 +1,209 @@ +//===-- BTF.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the layout of .BTF and .BTF.ext ELF sections. +/// +/// The binary layout for .BTF section: +/// struct Header +/// Type and Str subsections +/// The Type subsection is a collection of types with type id starting with 1. +/// The Str subsection is simply a collection of strings. +/// +/// The binary layout for .BTF.ext section: +/// struct ExtHeader +/// FuncInfo and LineInfo subsections +/// The FuncInfo subsection is defined as below: +/// BTFFuncInfo Size +/// struct SecFuncInfo for ELF section #1 +/// A number of struct BPFFuncInfo for ELF section #1 +/// struct SecFuncInfo for ELF section #2 +/// A number of struct BPFFuncInfo for ELF section #2 +/// ... +/// The LineInfo subsection is defined as below: +/// BPFLineInfo Size +/// struct SecLineInfo for ELF section #1 +/// A number of struct BPFLineInfo for ELF section #1 +/// struct SecLineInfo for ELF section #2 +/// A number of struct BPFLineInfo for ELF section #2 +/// ... +/// +/// The section formats are also defined at +/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/btf.h +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_BPF_BTF_H +#define LLVM_LIB_TARGET_BPF_BTF_H + +namespace llvm { +namespace BTF { + +enum : uint32_t { MAGIC = 0xeB9F, VERSION = 1 }; + +/// Sizes in bytes of various things in the BTF format. +enum { + HeaderSize = 24, + ExtHeaderSize = 24, + CommonTypeSize = 12, + BTFArraySize = 12, + BTFEnumSize = 8, + BTFMemberSize = 12, + BTFParamSize = 8, + SecFuncInfoSize = 8, + SecLineInfoSize = 8, + BPFFuncInfoSize = 8, + BPFLineInfoSize = 16 +}; + +/// The .BTF section header definition. +struct Header { + uint16_t Magic; ///< Magic value + uint8_t Version; ///< Version number + uint8_t Flags; ///< Extra flags + uint32_t HdrLen; ///< Length of this header + + /// All offsets are in bytes relative to the end of this header. + uint32_t TypeOff; ///< Offset of type section + uint32_t TypeLen; ///< Length of type section + uint32_t StrOff; ///< Offset of string section + uint32_t StrLen; ///< Length of string section +}; + +enum : uint32_t { + MAX_VLEN = 0xffff ///< Max # of struct/union/enum members or func args +}; + +enum TypeKinds : uint8_t { +#define HANDLE_BTF_KIND(ID, NAME) BTF_KIND_##NAME = ID, +#include "BTF.def" +}; + +/// The BTF common type definition. Different kinds may have +/// additional information after this structure data. +struct CommonType { + /// Type name offset in the string table. + uint32_t NameOff; + + /// "Info" bits arrangement: + /// Bits 0-15: vlen (e.g. # of struct's members) + /// Bits 16-23: unused + /// Bits 24-27: kind (e.g. int, ptr, array...etc) + /// Bits 28-30: unused + /// Bit 31: kind_flag, currently used by + /// struct, union and fwd + uint32_t Info; + + /// "Size" is used by INT, ENUM, STRUCT and UNION. + /// "Size" tells the size of the type it is describing. + /// + /// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + /// FUNC and FUNC_PROTO. + /// "Type" is a type_id referring to another type. + union { + uint32_t Size; + uint32_t Type; + }; +}; + +// For some specific BTF_KIND, "struct CommonType" is immediately +// followed by extra data. + +// BTF_KIND_INT is followed by a u32 and the following +// is the 32 bits arrangement: +// BTF_INT_ENCODING(VAL) : (((VAL) & 0x0f000000) >> 24) +// BTF_INT_OFFSET(VAL) : (((VAL & 0x00ff0000)) >> 16) +// BTF_INT_BITS(VAL) : ((VAL) & 0x000000ff) + +/// Attributes stored in the INT_ENCODING. +enum : uint8_t { INT_SIGNED = (1 << 0), INT_CHAR = (1 << 1), INT_BOOL = (1 << 2) }; + +/// BTF_KIND_ENUM is followed by multiple "struct BTFEnum". +/// The exact number of btf_enum is stored in the vlen (of the +/// info in "struct CommonType"). +struct BTFEnum { + uint32_t NameOff; ///< Enum name offset in the string table + int32_t Val; ///< Enum member value +}; + +/// BTF_KIND_ARRAY is followed by one "struct BTFArray". +struct BTFArray { + uint32_t ElemType; ///< Element type + uint32_t IndexType; ///< Index type + uint32_t Nelems; ///< Number of elements for this array +}; + +/// BTF_KIND_STRUCT and BTF_KIND_UNION are followed +/// by multiple "struct BTFMember". The exact number +/// of BTFMember is stored in the vlen (of the info in +/// "struct CommonType"). +/// +/// If the struct/union contains any bitfield member, +/// the Offset below represents BitOffset (bits 0 - 23) +/// and BitFieldSize(bits 24 - 31) with BitFieldSize = 0 +/// for non bitfield members. Otherwise, the Offset +/// represents the BitOffset. +struct BTFMember { + uint32_t NameOff; ///< Member name offset in the string table + uint32_t Type; ///< Member type + uint32_t Offset; ///< BitOffset or BitFieldSize+BitOffset +}; + +/// BTF_KIND_FUNC_PROTO are followed by multiple "struct BTFParam". +/// The exist number of BTFParam is stored in the vlen (of the info +/// in "struct CommonType"). +struct BTFParam { + uint32_t NameOff; + uint32_t Type; +}; + +/// The .BTF.ext section header definition. +struct ExtHeader { + uint16_t Magic; + uint8_t Version; + uint8_t Flags; + uint32_t HdrLen; + + uint32_t FuncInfoOff; ///< Offset of func info section + uint32_t FuncInfoLen; ///< Length of func info section + uint32_t LineInfoOff; ///< Offset of line info section + uint32_t LineInfoLen; ///< Length of line info section +}; + +/// Specifying one function info. +struct BPFFuncInfo { + uint32_t InsnOffset; ///< Byte offset in the section + uint32_t TypeId; ///< Type id referring to .BTF type section +}; + +/// Specifying function info's in one section. +struct SecFuncInfo { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumFuncInfo; ///< Number of func info's in this section +}; + +/// Specifying one line info. +struct BPFLineInfo { + uint32_t InsnOffset; ///< Byte offset in this section + uint32_t FileNameOff; ///< File name index in the .BTF string table + uint32_t LineOff; ///< Line index in the .BTF string table + uint32_t LineCol; ///< Line num: line_col >> 10, + /// col num: line_col & 0x3ff +}; + +/// Specifying line info's in one section. +struct SecLineInfo { + uint32_t SecNameOff; ///< Section name index in the .BTF string tble + uint32_t NumLineInfo; ///< Number of line info's in this section +}; + +} // End namespace BTF. +} // End namespace llvm. + +#endif diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp new file mode 100644 index 00000000000..96efea4ba8e --- /dev/null +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -0,0 +1,759 @@ +//===- BTFDebug.cpp - BTF Generator ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing BTF debug info. +// +//===----------------------------------------------------------------------===// + +#include "BTFDebug.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include <fstream> +#include <sstream> + +using namespace llvm; + +static const char *BTFKindStr[] = { +#define HANDLE_BTF_KIND(ID, NAME) "BTF_KIND_" #NAME, +#include "BTF.def" +}; + +/// Emit a BTF common type. +void BTFTypeBase::emitType(MCStreamer &OS) { + OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) + + ")"); + OS.EmitIntValue(BTFType.NameOff, 4); + OS.AddComment("0x" + Twine::utohexstr(BTFType.Info)); + OS.EmitIntValue(BTFType.Info, 4); + OS.EmitIntValue(BTFType.Size, 4); +} + +BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag) + : DTy(DTy) { + switch (Tag) { + case dwarf::DW_TAG_pointer_type: + Kind = BTF::BTF_KIND_PTR; + break; + case dwarf::DW_TAG_const_type: + Kind = BTF::BTF_KIND_CONST; + break; + case dwarf::DW_TAG_volatile_type: + Kind = BTF::BTF_KIND_VOLATILE; + break; + case dwarf::DW_TAG_typedef: + Kind = BTF::BTF_KIND_TYPEDEF; + break; + case dwarf::DW_TAG_restrict_type: + Kind = BTF::BTF_KIND_RESTRICT; + break; + default: + llvm_unreachable("Unknown DIDerivedType Tag"); + } + BTFType.Info = Kind << 24; +} + +void BTFTypeDerived::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(DTy->getName()); + + // The base type for PTR/CONST/VOLATILE could be void. + const DIType *ResolvedType = DTy->getBaseType().resolve(); + if (!ResolvedType) { + assert((Kind == BTF::BTF_KIND_PTR || Kind == BTF::BTF_KIND_CONST || + Kind == BTF::BTF_KIND_VOLATILE) && + "Invalid null basetype"); + BTFType.Type = 0; + } else { + BTFType.Type = BDebug.getTypeId(ResolvedType); + } +} + +void BTFTypeDerived::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +/// Represent a struct/union forward declaration. +BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) { + Kind = BTF::BTF_KIND_FWD; + BTFType.Info = IsUnion << 31 | Kind << 24; + BTFType.Type = 0; +} + +void BTFTypeFwd::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeFwd::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +BTFTypeInt::BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, + uint32_t OffsetInBits, StringRef TypeName) + : Name(TypeName) { + // Translate IR int encoding to BTF int encoding. + uint8_t BTFEncoding; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + BTFEncoding = BTF::INT_BOOL; + break; + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + BTFEncoding = BTF::INT_SIGNED; + break; + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + BTFEncoding = 0; + break; + default: + llvm_unreachable("Unknown BTFTypeInt Encoding"); + } + + Kind = BTF::BTF_KIND_INT; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); + IntVal = (BTFEncoding << 24) | OffsetInBits << 16 | SizeInBits; +} + +void BTFTypeInt::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeInt::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.AddComment("0x" + Twine::utohexstr(IntVal)); + OS.EmitIntValue(IntVal, 4); +} + +BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen) : ETy(ETy) { + Kind = BTF::BTF_KIND_ENUM; + BTFType.Info = Kind << 24 | VLen; + BTFType.Size = roundupToBytes(ETy->getSizeInBits()); +} + +void BTFTypeEnum::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(ETy->getName()); + + DINodeArray Elements = ETy->getElements(); + for (const auto Element : Elements) { + const auto *Enum = cast<DIEnumerator>(Element); + + struct BTF::BTFEnum BTFEnum; + BTFEnum.NameOff = BDebug.addString(Enum->getName()); + // BTF enum value is 32bit, enforce it. + BTFEnum.Val = static_cast<uint32_t>(Enum->getValue()); + EnumValues.push_back(BTFEnum); + } +} + +void BTFTypeEnum::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Enum : EnumValues) { + OS.EmitIntValue(Enum.NameOff, 4); + OS.EmitIntValue(Enum.Val, 4); + } +} + +BTFTypeArray::BTFTypeArray(const DICompositeType *ATy) : ATy(ATy) { + Kind = BTF::BTF_KIND_ARRAY; + BTFType.Info = Kind << 24; +} + +/// Represent a BTF array. BTF does not record array dimensions, +/// so conceptually a BTF array is a one-dimensional array. +void BTFTypeArray::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(ATy->getName()); + BTFType.Size = 0; + + auto *BaseType = ATy->getBaseType().resolve(); + ArrayInfo.ElemType = BDebug.getTypeId(BaseType); + + // The IR does not really have a type for the index. + // A special type for array index should have been + // created during initial type traversal. Just + // retrieve that type id. + ArrayInfo.IndexType = BDebug.getArrayIndexTypeId(); + + // Get the number of array elements. + // If the array size is 0, set the number of elements as 0. + // Otherwise, recursively traverse the base types to + // find the element size. The number of elements is + // the totoal array size in bits divided by + // element size in bits. + uint64_t ArraySizeInBits = ATy->getSizeInBits(); + if (!ArraySizeInBits) { + ArrayInfo.Nelems = 0; + } else { + uint32_t BaseTypeSize = BaseType->getSizeInBits(); + while (!BaseTypeSize) { + const auto *DDTy = cast<DIDerivedType>(BaseType); + BaseType = DDTy->getBaseType().resolve(); + assert(BaseType); + BaseTypeSize = BaseType->getSizeInBits(); + } + ArrayInfo.Nelems = ATy->getSizeInBits() / BaseTypeSize; + } +} + +void BTFTypeArray::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.EmitIntValue(ArrayInfo.ElemType, 4); + OS.EmitIntValue(ArrayInfo.IndexType, 4); + OS.EmitIntValue(ArrayInfo.Nelems, 4); +} + +/// Represent either a struct or a union. +BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct, + bool HasBitField, uint32_t Vlen) + : STy(STy), HasBitField(HasBitField) { + Kind = IsStruct ? BTF::BTF_KIND_STRUCT : BTF::BTF_KIND_UNION; + BTFType.Size = roundupToBytes(STy->getSizeInBits()); + BTFType.Info = (HasBitField << 31) | (Kind << 24) | Vlen; +} + +void BTFTypeStruct::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(STy->getName()); + + // Add struct/union members. + const DINodeArray Elements = STy->getElements(); + for (const auto *Element : Elements) { + struct BTF::BTFMember BTFMember; + const auto *DDTy = cast<DIDerivedType>(Element); + + BTFMember.NameOff = BDebug.addString(DDTy->getName()); + if (HasBitField) { + uint8_t BitFieldSize = DDTy->isBitField() ? DDTy->getSizeInBits() : 0; + BTFMember.Offset = BitFieldSize << 24 | DDTy->getOffsetInBits(); + } else { + BTFMember.Offset = DDTy->getOffsetInBits(); + } + BTFMember.Type = BDebug.getTypeId(DDTy->getBaseType().resolve()); + Members.push_back(BTFMember); + } +} + +void BTFTypeStruct::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Member : Members) { + OS.EmitIntValue(Member.NameOff, 4); + OS.EmitIntValue(Member.Type, 4); + OS.AddComment("0x" + Twine::utohexstr(Member.Offset)); + OS.EmitIntValue(Member.Offset, 4); + } +} + +/// The Func kind represents both subprogram and pointee of function +/// pointers. If the FuncName is empty, it represents a pointee of function +/// pointer. Otherwise, it represents a subprogram. The func arg names +/// are empty for pointee of function pointer case, and are valid names +/// for subprogram. +BTFTypeFuncProto::BTFTypeFuncProto( + const DISubroutineType *STy, uint32_t VLen, + const std::unordered_map<uint32_t, StringRef> &FuncArgNames) + : STy(STy), FuncArgNames(FuncArgNames) { + Kind = BTF::BTF_KIND_FUNC_PROTO; + BTFType.Info = (Kind << 24) | VLen; +} + +void BTFTypeFuncProto::completeType(BTFDebug &BDebug) { + DITypeRefArray Elements = STy->getTypeArray(); + auto RetType = Elements[0].resolve(); + BTFType.Type = RetType ? BDebug.getTypeId(RetType) : 0; + BTFType.NameOff = 0; + + // For null parameter which is typically the last one + // to represent the vararg, encode the NameOff/Type to be 0. + for (unsigned I = 1, N = Elements.size(); I < N; ++I) { + struct BTF::BTFParam Param; + auto Element = Elements[I].resolve(); + if (Element) { + Param.NameOff = BDebug.addString(FuncArgNames[I]); + Param.Type = BDebug.getTypeId(Element); + } else { + Param.NameOff = 0; + Param.Type = 0; + } + Parameters.push_back(Param); + } +} + +void BTFTypeFuncProto::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Param : Parameters) { + OS.EmitIntValue(Param.NameOff, 4); + OS.EmitIntValue(Param.Type, 4); + } +} + +BTFTypeFunc::BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId) + : Name(FuncName) { + Kind = BTF::BTF_KIND_FUNC; + BTFType.Info = Kind << 24; + BTFType.Type = ProtoTypeId; +} + +void BTFTypeFunc::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeFunc::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +uint32_t BTFStringTable::addString(StringRef S) { + // Check whether the string already exists. + for (auto &OffsetM : OffsetToIdMap) { + if (Table[OffsetM.second] == S) + return OffsetM.first; + } + // Not find, add to the string table. + uint32_t Offset = Size; + OffsetToIdMap[Offset] = Table.size(); + Table.push_back(S); + Size += S.size() + 1; + return Offset; +} + +BTFDebug::BTFDebug(AsmPrinter *AP) + : DebugHandlerBase(AP), OS(*Asm->OutStreamer), SkipInstruction(false), + LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0) { + addString("\0"); +} + +void BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry, + const DIType *Ty) { + TypeEntry->setId(TypeEntries.size() + 1); + DIToIdMap[Ty] = TypeEntry->getId(); + TypeEntries.push_back(std::move(TypeEntry)); +} + +uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry) { + TypeEntry->setId(TypeEntries.size() + 1); + uint32_t Id = TypeEntry->getId(); + TypeEntries.push_back(std::move(TypeEntry)); + return Id; +} + +void BTFDebug::visitBasicType(const DIBasicType *BTy) { + // Only int types are supported in BTF. + uint32_t Encoding = BTy->getEncoding(); + if (Encoding != dwarf::DW_ATE_boolean && Encoding != dwarf::DW_ATE_signed && + Encoding != dwarf::DW_ATE_signed_char && + Encoding != dwarf::DW_ATE_unsigned && + Encoding != dwarf::DW_ATE_unsigned_char) + return; + + // Create a BTF type instance for this DIBasicType and put it into + // DIToIdMap for cross-type reference check. + auto TypeEntry = llvm::make_unique<BTFTypeInt>( + Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); + addType(std::move(TypeEntry), BTy); +} + +/// Handle subprogram or subroutine types. +void BTFDebug::visitSubroutineType( + const DISubroutineType *STy, bool ForSubprog, + const std::unordered_map<uint32_t, StringRef> &FuncArgNames, + uint32_t &TypeId) { + DITypeRefArray Elements = STy->getTypeArray(); + uint32_t VLen = Elements.size() - 1; + if (VLen > BTF::MAX_VLEN) + return; + + // Subprogram has a valid non-zero-length name, and the pointee of + // a function pointer has an empty name. The subprogram type will + // not be added to DIToIdMap as it should not be referenced by + // any other types. + auto TypeEntry = llvm::make_unique<BTFTypeFuncProto>(STy, VLen, FuncArgNames); + if (ForSubprog) + TypeId = addType(std::move(TypeEntry)); // For subprogram + else + addType(std::move(TypeEntry), STy); // For func ptr + + // Visit return type and func arg types. + for (const auto Element : Elements) { + visitTypeEntry(Element.resolve()); + } +} + +/// Handle structure/union types. +void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct) { + const DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + if (VLen > BTF::MAX_VLEN) + return; + + // Check whether we have any bitfield members or not + bool HasBitField = false; + for (const auto *Element : Elements) { + auto E = cast<DIDerivedType>(Element); + if (E->isBitField()) { + HasBitField = true; + break; + } + } + + auto TypeEntry = + llvm::make_unique<BTFTypeStruct>(CTy, IsStruct, HasBitField, VLen); + addType(std::move(TypeEntry), CTy); + + // Visit all struct members. + for (const auto *Element : Elements) + visitTypeEntry(cast<DIDerivedType>(Element)); +} + +void BTFDebug::visitArrayType(const DICompositeType *CTy) { + auto TypeEntry = llvm::make_unique<BTFTypeArray>(CTy); + addType(std::move(TypeEntry), CTy); + + // The IR does not have a type for array index while BTF wants one. + // So create an array index type if there is none. + if (!ArrayIndexTypeId) { + auto TypeEntry = llvm::make_unique<BTFTypeInt>(dwarf::DW_ATE_unsigned, 32, + 0, "__ARRAY_SIZE_TYPE__"); + ArrayIndexTypeId = addType(std::move(TypeEntry)); + } + + // Visit array element type. + visitTypeEntry(CTy->getBaseType().resolve()); +} + +void BTFDebug::visitEnumType(const DICompositeType *CTy) { + DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + if (VLen > BTF::MAX_VLEN) + return; + + auto TypeEntry = llvm::make_unique<BTFTypeEnum>(CTy, VLen); + addType(std::move(TypeEntry), CTy); + // No need to visit base type as BTF does not encode it. +} + +/// Handle structure/union forward declarations. +void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion) { + auto TypeEntry = llvm::make_unique<BTFTypeFwd>(CTy->getName(), IsUnion); + addType(std::move(TypeEntry), CTy); +} + +/// Handle structure, union, array and enumeration types. +void BTFDebug::visitCompositeType(const DICompositeType *CTy) { + auto Tag = CTy->getTag(); + if (Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { + // Handle forward declaration differently as it does not have members. + if (CTy->isForwardDecl()) + visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type); + else + visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type); + } else if (Tag == dwarf::DW_TAG_array_type) + visitArrayType(CTy); + else if (Tag == dwarf::DW_TAG_enumeration_type) + visitEnumType(CTy); +} + +/// Handle pointer, typedef, const, volatile, restrict and member types. +void BTFDebug::visitDerivedType(const DIDerivedType *DTy) { + unsigned Tag = DTy->getTag(); + + if (Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_typedef || + Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || + Tag == dwarf::DW_TAG_restrict_type) { + auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag); + addType(std::move(TypeEntry), DTy); + } else if (Tag != dwarf::DW_TAG_member) { + return; + } + + // Visit base type of pointer, typedef, const, volatile, restrict or + // struct/union member. + visitTypeEntry(DTy->getBaseType().resolve()); +} + +void BTFDebug::visitTypeEntry(const DIType *Ty) { + if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) + return; + + uint32_t TypeId; + if (const auto *BTy = dyn_cast<DIBasicType>(Ty)) + visitBasicType(BTy); + else if (const auto *STy = dyn_cast<DISubroutineType>(Ty)) + visitSubroutineType(STy, false, std::unordered_map<uint32_t, StringRef>(), + TypeId); + else if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) + visitCompositeType(CTy); + else if (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) + visitDerivedType(DTy); + else + llvm_unreachable("Unknown DIType"); +} + +/// Read file contents from the actual file or from the source +std::string BTFDebug::populateFileContent(const DISubprogram *SP) { + auto File = SP->getFile(); + std::string FileName; + + if (File->getDirectory().size()) + FileName = File->getDirectory().str() + "/" + File->getFilename().str(); + else + FileName = File->getFilename(); + + // No need to populate the contends if it has been populated! + if (FileContent.find(FileName) != FileContent.end()) + return FileName; + + std::vector<std::string> Content; + std::string Line; + Content.push_back(Line); // Line 0 for empty string + + auto Source = File->getSource(); + if (Source) { + std::istringstream InputString(Source.getValue()); + while (std::getline(InputString, Line)) + Content.push_back(Line); + } else { + std::ifstream InputFile(FileName); + while (std::getline(InputFile, Line)) + Content.push_back(Line); + } + + FileContent[FileName] = Content; + return FileName; +} + +void BTFDebug::constructLineInfo(const DISubprogram *SP, MCSymbol *Label, + uint32_t Line, uint32_t Column) { + std::string FileName = populateFileContent(SP); + BTFLineInfo LineInfo; + + LineInfo.Label = Label; + LineInfo.FileNameOff = addString(FileName); + // If file content is not available, let LineOff = 0. + if (Line < FileContent[FileName].size()) + LineInfo.LineOff = addString(FileContent[FileName][Line]); + else + LineInfo.LineOff = 0; + LineInfo.LineNum = Line; + LineInfo.ColumnNum = Column; + LineInfoTable[SecNameOff].push_back(LineInfo); +} + +void BTFDebug::emitCommonHeader() { + OS.AddComment("0x" + Twine::utohexstr(BTF::MAGIC)); + OS.EmitIntValue(BTF::MAGIC, 2); + OS.EmitIntValue(BTF::VERSION, 1); + OS.EmitIntValue(0, 1); +} + +void BTFDebug::emitBTFSection() { + MCContext &Ctx = OS.getContext(); + OS.SwitchSection(Ctx.getELFSection(".BTF", ELF::SHT_PROGBITS, 0)); + + // Emit header. + emitCommonHeader(); + OS.EmitIntValue(BTF::HeaderSize, 4); + + uint32_t TypeLen = 0, StrLen; + for (const auto &TypeEntry : TypeEntries) + TypeLen += TypeEntry->getSize(); + StrLen = StringTable.getSize(); + + OS.EmitIntValue(0, 4); + OS.EmitIntValue(TypeLen, 4); + OS.EmitIntValue(TypeLen, 4); + OS.EmitIntValue(StrLen, 4); + + // Emit type table. + for (const auto &TypeEntry : TypeEntries) + TypeEntry->emitType(OS); + + // Emit string table. + uint32_t StringOffset = 0; + for (const auto &S : StringTable.getTable()) { + OS.AddComment("string offset=" + std::to_string(StringOffset)); + OS.EmitBytes(S); + OS.EmitBytes(StringRef("\0", 1)); + StringOffset += S.size() + 1; + } +} + +void BTFDebug::emitBTFExtSection() { + MCContext &Ctx = OS.getContext(); + OS.SwitchSection(Ctx.getELFSection(".BTF.ext", ELF::SHT_PROGBITS, 0)); + + // Emit header. + emitCommonHeader(); + OS.EmitIntValue(BTF::ExtHeaderSize, 4); + + // Account for FuncInfo/LineInfo record size as well. + uint32_t FuncLen = 4, LineLen = 4; + for (const auto &FuncSec : FuncInfoTable) { + FuncLen += BTF::SecFuncInfoSize; + FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize; + } + for (const auto &LineSec : LineInfoTable) { + LineLen += BTF::SecLineInfoSize; + LineLen += LineSec.second.size() * BTF::BPFLineInfoSize; + } + + OS.EmitIntValue(0, 4); + OS.EmitIntValue(FuncLen, 4); + OS.EmitIntValue(FuncLen, 4); + OS.EmitIntValue(LineLen, 4); + + // Emit func_info table. + OS.AddComment("FuncInfo"); + OS.EmitIntValue(BTF::BPFFuncInfoSize, 4); + for (const auto &FuncSec : FuncInfoTable) { + OS.AddComment("FuncInfo section string offset=" + + std::to_string(FuncSec.first)); + OS.EmitIntValue(FuncSec.first, 4); + OS.EmitIntValue(FuncSec.second.size(), 4); + for (const auto &FuncInfo : FuncSec.second) { + Asm->EmitLabelReference(FuncInfo.Label, 4); + OS.EmitIntValue(FuncInfo.TypeId, 4); + } + } + + // Emit line_info table. + OS.AddComment("LineInfo"); + OS.EmitIntValue(BTF::BPFLineInfoSize, 4); + for (const auto &LineSec : LineInfoTable) { + OS.AddComment("LineInfo section string offset=" + + std::to_string(LineSec.first)); + OS.EmitIntValue(LineSec.first, 4); + OS.EmitIntValue(LineSec.second.size(), 4); + for (const auto &LineInfo : LineSec.second) { + Asm->EmitLabelReference(LineInfo.Label, 4); + OS.EmitIntValue(LineInfo.FileNameOff, 4); + OS.EmitIntValue(LineInfo.LineOff, 4); + OS.AddComment("Line " + std::to_string(LineInfo.LineNum) + " Col " + + std::to_string(LineInfo.ColumnNum)); + OS.EmitIntValue(LineInfo.LineNum << 10 | LineInfo.ColumnNum, 4); + } + } +} + +void BTFDebug::beginFunctionImpl(const MachineFunction *MF) { + auto *SP = MF->getFunction().getSubprogram(); + auto *Unit = SP->getUnit(); + + if (Unit->getEmissionKind() == DICompileUnit::NoDebug) { + SkipInstruction = true; + return; + } + SkipInstruction = false; + + // Collect all types locally referenced in this function. + // Use RetainedNodes so we can collect all argument names + // even if the argument is not used. + std::unordered_map<uint32_t, StringRef> FuncArgNames; + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast<DILocalVariable>(DN)) { + visitTypeEntry(DV->getType().resolve()); + + // Collect function arguments for subprogram func type. + uint32_t Arg = DV->getArg(); + if (Arg) + FuncArgNames[Arg] = DV->getName(); + } + } + + // Construct subprogram func proto type. + uint32_t ProtoTypeId; + visitSubroutineType(SP->getType(), true, FuncArgNames, ProtoTypeId); + + // Construct subprogram func type + auto FuncTypeEntry = + llvm::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId); + uint32_t FuncTypeId = addType(std::move(FuncTypeEntry)); + + // Construct funcinfo and the first lineinfo for the function. + MCSymbol *FuncLabel = Asm->getFunctionBegin(); + BTFFuncInfo FuncInfo; + FuncInfo.Label = FuncLabel; + FuncInfo.TypeId = FuncTypeId; + if (FuncLabel->isInSection()) { + MCSection &Section = FuncLabel->getSection(); + const MCSectionELF *SectionELF = dyn_cast<MCSectionELF>(&Section); + assert(SectionELF && "Null section for Function Label"); + SecNameOff = addString(SectionELF->getSectionName()); + } else { + SecNameOff = addString(".text"); + } + FuncInfoTable[SecNameOff].push_back(FuncInfo); +} + +void BTFDebug::endFunctionImpl(const MachineFunction *MF) { + SkipInstruction = false; + LineInfoGenerated = false; + SecNameOff = 0; +} + +void BTFDebug::beginInstruction(const MachineInstr *MI) { + DebugHandlerBase::beginInstruction(MI); + + if (SkipInstruction || MI->isMetaInstruction() || + MI->getFlag(MachineInstr::FrameSetup)) + return; + + if (MI->isInlineAsm()) { + // Count the number of register definitions to find the asm string. + unsigned NumDefs = 0; + for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); + ++NumDefs) + ; + + // Skip this inline asm instruction if the asmstr is empty. + const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); + if (AsmStr[0] == 0) + return; + } + + // Skip this instruction if no DebugLoc or the DebugLoc + // is the same as the previous instruction. + const DebugLoc &DL = MI->getDebugLoc(); + if (!DL || PrevInstLoc == DL) { + // This instruction will be skipped, no LineInfo has + // been generated, construct one based on function signature. + if (LineInfoGenerated == false) { + auto *S = MI->getMF()->getFunction().getSubprogram(); + MCSymbol *FuncLabel = Asm->getFunctionBegin(); + constructLineInfo(S, FuncLabel, S->getLine(), 0); + LineInfoGenerated = true; + } + + return; + } + + // Create a temporary label to remember the insn for lineinfo. + MCSymbol *LineSym = OS.getContext().createTempSymbol(); + OS.EmitLabel(LineSym); + + // Construct the lineinfo. + auto SP = DL.get()->getScope()->getSubprogram(); + constructLineInfo(SP, LineSym, DL.getLine(), DL.getCol()); + + LineInfoGenerated = true; + PrevInstLoc = DL; +} + +void BTFDebug::endModule() { + // Collect all types referenced by globals. + const Module *M = MMI->getModule(); + for (const DICompileUnit *CUNode : M->debug_compile_units()) { + for (const auto *GVE : CUNode->getGlobalVariables()) { + DIGlobalVariable *GV = GVE->getVariable(); + visitTypeEntry(GV->getType().resolve()); + } + } + + // Complete BTF type cross refereences. + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + + // Emit BTF sections. + emitBTFSection(); + emitBTFExtSection(); +} diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h new file mode 100644 index 00000000000..afd4ed87f63 --- /dev/null +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -0,0 +1,285 @@ +//===- BTFDebug.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains support for writing BTF debug info. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_BPF_BTFDEBUG_H +#define LLVM_LIB_TARGET_BPF_BTFDEBUG_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/DebugHandlerBase.h" +#include <unordered_map> +#include "BTF.h" + +namespace llvm { + +class AsmPrinter; +class BTFDebug; +class DIType; +class MCStreamer; +class MCSymbol; +class MachineFunction; + +/// The base class for BTF type generation. +class BTFTypeBase { +protected: + uint8_t Kind; + uint32_t Id; + struct BTF::CommonType BTFType; + +public: + virtual ~BTFTypeBase() = default; + void setId(uint32_t Id) { this->Id = Id; } + uint32_t getId() { return Id; } + uint32_t roundupToBytes(uint32_t NumBits) { return (NumBits + 7) >> 3; } + /// Get the size of this BTF type entry. + virtual uint32_t getSize() { return BTF::CommonTypeSize; } + /// Complete BTF type generation after all related DebugInfo types + /// have been visited so their BTF type id's are available + /// for cross referece. + virtual void completeType(BTFDebug &BDebug) {} + /// Emit types for this BTF type entry. + virtual void emitType(MCStreamer &OS); +}; + +/// Handle several derived types include pointer, const, +/// volatile, typedef and restrict. +class BTFTypeDerived : public BTFTypeBase { + const DIDerivedType *DTy; + +public: + BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag); + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle struct or union forward declaration. +class BTFTypeFwd : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFwd(StringRef Name, bool IsUnion); + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle int type. +class BTFTypeInt : public BTFTypeBase { + StringRef Name; + uint32_t IntVal; ///< Encoding, offset, bits + +public: + BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, uint32_t OffsetInBits, + StringRef TypeName); + uint32_t getSize() { return BTFTypeBase::getSize() + sizeof(uint32_t); } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle enumerate type. +class BTFTypeEnum : public BTFTypeBase { + const DICompositeType *ETy; + std::vector<struct BTF::BTFEnum> EnumValues; + +public: + BTFTypeEnum(const DICompositeType *ETy, uint32_t NumValues); + uint32_t getSize() { + return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnumSize; + } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle array type. +class BTFTypeArray : public BTFTypeBase { + const DICompositeType *ATy; + struct BTF::BTFArray ArrayInfo; + +public: + BTFTypeArray(const DICompositeType *ATy); + uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle struct/union type. +class BTFTypeStruct : public BTFTypeBase { + const DICompositeType *STy; + bool HasBitField; + std::vector<struct BTF::BTFMember> Members; + +public: + BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, + uint32_t NumMembers); + uint32_t getSize() { + return BTFTypeBase::getSize() + Members.size() * BTF::BTFMemberSize; + } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle function pointer. +class BTFTypeFuncProto : public BTFTypeBase { + const DISubroutineType *STy; + std::unordered_map<uint32_t, StringRef> FuncArgNames; + std::vector<struct BTF::BTFParam> Parameters; + +public: + BTFTypeFuncProto(const DISubroutineType *STy, uint32_t NumParams, + const std::unordered_map<uint32_t, StringRef> &FuncArgNames); + uint32_t getSize() { + return BTFTypeBase::getSize() + Parameters.size() * BTF::BTFParamSize; + } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// Handle subprogram +class BTFTypeFunc : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId); + uint32_t getSize() { return BTFTypeBase::getSize(); } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// String table. +class BTFStringTable { + /// String table size in bytes. + uint32_t Size; + /// A mapping from string table offset to the index + /// of the Table. It is used to avoid putting + /// duplicated strings in the table. + std::unordered_map<uint32_t, uint32_t> OffsetToIdMap; + /// A vector of strings to represent the string table. + std::vector<std::string> Table; + +public: + BTFStringTable() : Size(0) {} + uint32_t getSize() { return Size; } + std::vector<std::string> &getTable() { return Table; } + /// Add a string to the string table and returns its offset + /// in the table. + uint32_t addString(StringRef S); +}; + +/// Represent one func and its type id. +struct BTFFuncInfo { + const MCSymbol *Label; ///< Func MCSymbol + uint32_t TypeId; ///< Type id referring to .BTF type section +}; + +/// Represent one line info. +struct BTFLineInfo { + MCSymbol *Label; ///< MCSymbol identifying insn for the lineinfo + uint32_t FileNameOff; ///< file name offset in the .BTF string table + uint32_t LineOff; ///< line offset in the .BTF string table + uint32_t LineNum; ///< the line number + uint32_t ColumnNum; ///< the column number +}; + +/// Collect and emit BTF information. +class BTFDebug : public DebugHandlerBase { + MCStreamer &OS; + bool SkipInstruction; + bool LineInfoGenerated; + uint32_t SecNameOff; + uint32_t ArrayIndexTypeId; + BTFStringTable StringTable; + std::vector<std::unique_ptr<BTFTypeBase>> TypeEntries; + std::unordered_map<const DIType *, uint32_t> DIToIdMap; + std::unordered_map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable; + std::unordered_map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable; + StringMap<std::vector<std::string>> FileContent; + + /// Add types to TypeEntries. + /// @{ + /// Add types to TypeEntries and DIToIdMap. + void addType(std::unique_ptr<BTFTypeBase> TypeEntry, const DIType *Ty); + /// Add types to TypeEntries only and return type id. + uint32_t addType(std::unique_ptr<BTFTypeBase> TypeEntry); + /// @} + + /// IR type visiting functions. + /// @{ + void visitTypeEntry(const DIType *Ty); + void visitBasicType(const DIBasicType *BTy); + void visitSubroutineType( + const DISubroutineType *STy, bool ForSubprog, + const std::unordered_map<uint32_t, StringRef> &FuncArgNames, + uint32_t &TypeId); + void visitFwdDeclType(const DICompositeType *CTy, bool IsUnion); + void visitCompositeType(const DICompositeType *CTy); + void visitStructType(const DICompositeType *STy, bool IsStruct); + void visitArrayType(const DICompositeType *ATy); + void visitEnumType(const DICompositeType *ETy); + void visitDerivedType(const DIDerivedType *DTy); + /// @} + + /// Get the file content for the subprogram. Certain lines of the file + /// later may be put into string table and referenced by line info. + std::string populateFileContent(const DISubprogram *SP); + + /// Construct a line info. + void constructLineInfo(const DISubprogram *SP, MCSymbol *Label, uint32_t Line, + uint32_t Column); + + /// Emit common header of .BTF and .BTF.ext sections. + void emitCommonHeader(); + + /// Emit the .BTF section. + void emitBTFSection(); + + /// Emit the .BTF.ext section. + void emitBTFExtSection(); + +protected: + /// Gather pre-function debug information. + void beginFunctionImpl(const MachineFunction *MF) override; + + /// Post process after all instructions in this function are processed. + void endFunctionImpl(const MachineFunction *MF) override; + +public: + BTFDebug(AsmPrinter *AP); + + /// Get the special array index type id. + uint32_t getArrayIndexTypeId() { + assert(ArrayIndexTypeId); + return ArrayIndexTypeId; + } + + /// Add string to the string table. + size_t addString(StringRef S) { return StringTable.addString(S); } + + /// Get the type id for a particular DIType. + uint32_t getTypeId(const DIType *Ty) { + assert(Ty && "Invalid null Type"); + assert(DIToIdMap.find(Ty) != DIToIdMap.end() && + "DIType not added in the BDIToIdMap"); + return DIToIdMap[Ty]; + } + + void setSymbolSize(const MCSymbol *Symbol, uint64_t Size) override {} + + /// Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI) override; + + /// Complete all the types and emit the BTF sections. + void endModule() override; +}; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index 5e2ae533ea6..c18adf859d3 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -25,6 +25,7 @@ add_llvm_target(BPFCodeGen BPFTargetMachine.cpp BPFMIPeephole.cpp BPFMIChecking.cpp + BTFDebug.cpp ) add_subdirectory(AsmParser) |