summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-12-19 16:40:25 +0000
committerYonghong Song <yhs@fb.com>2018-12-19 16:40:25 +0000
commit7b410ac352bea299441a34f3b899e728bae460a7 (patch)
treebc17e744edff0a02e91472f79f9d88c39f657223 /llvm/lib/Target
parent8d221b40a7963caf19eaedf29f0512f6a09cd994 (diff)
downloadbcm5719-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.cpp14
-rw-r--r--llvm/lib/Target/BPF/BTF.def33
-rw-r--r--llvm/lib/Target/BPF/BTF.h209
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.cpp759
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.h285
-rw-r--r--llvm/lib/Target/BPF/CMakeLists.txt1
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)
OpenPOWER on IntegriCloud