diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1516,6 +1516,10 @@ FieldType = createFieldType(name, type, field->getLocation(), field->getAccess(), OffsetInBits, Align, tunit, RecordTy, RD); + if (field->hasAttr()) { + for (const auto *I : field->specific_attrs()) + FieldType->addAnnotation(I->getAnnotation()); + } } elements.push_back(FieldType); @@ -3487,6 +3491,11 @@ break; } + if (D->hasAttr()) { + for (const auto *I : D->specific_attrs()) + RealDecl->addAnnotation(I->getAnnotation()); + } + RegionMap[Ty->getDecl()].reset(RealDecl); TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl); @@ -3880,7 +3889,12 @@ getDwarfCC(CC)); } - return cast(getOrCreateType(FnType, F)); + auto DISubroutineTy = cast(getOrCreateType(FnType, F)); + if (D->hasAttr()) { + for (const auto *I : D->specific_attrs()) + DISubroutineTy->addAnnotation(I->getAnnotation()); + } + return DISubroutineTy; } void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, @@ -4375,6 +4389,10 @@ if (ArgNo) { D = DBuilder.createParameterVariable(Scope, Name, *ArgNo, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags); + if (VD->hasAttr()) { + for (const auto *I : VD->specific_attrs()) + D->addAnnotation(I->getAnnotation()); + } } else { // For normal local variable, we will try to find out whether 'VD' is the // copy parameter of coroutine. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -128,6 +128,8 @@ friend class LLVMContextImpl; friend class MDNode; + SmallVector Annotations; + protected: DINode(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, ArrayRef Ops1, ArrayRef Ops2 = None) @@ -183,6 +185,10 @@ static DIFlags splitFlags(DIFlags Flags, SmallVectorImpl &SplitFlags); + void addAnnotation(StringRef Annotation) { Annotations.emplace_back(Annotation); } + SmallVectorImpl &getAnnotations() { return Annotations; } + const SmallVectorImpl &getAnnotations() const { return Annotations; } + static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -707,7 +713,6 @@ DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(2); } - Metadata *getRawScope() const { return getOperand(1); } MDString *getRawName() const { return getOperandAs(2); } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/AsmPrinter.h" +#include "BTF2Debug.h" #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" @@ -154,6 +155,8 @@ const char PPTimerDescription[] = "Pseudo Probe Emission"; const char PPGroupName[] = "pseudo probe"; const char PPGroupDescription[] = "Pseudo Probe Emission"; +const char BTFGroupName[] = "btf2"; +const char BTFGroupDescription[] = "BTF2 Emission"; STATISTIC(EmittedInsts, "Number of machine instrs printed"); @@ -342,6 +345,14 @@ DWARFGroupDescription); } } + + std::string TripleName = Target.getTriple(); + if (TripleName != "bpf" && TripleName != "bpfel" && TripleName != "bpfeb" && + !M.debug_compile_units().empty()) { + Handlers.emplace_back(std::make_unique(this), + DbgTimerName, DbgTimerDescription, + BTFGroupName, BTFGroupDescription); + } } if (M.getNamedMetadata(PseudoProbeDescMetadataName)) { diff --git a/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.h b/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.h new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.h @@ -0,0 +1,295 @@ +//===- BTF2Debug.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains support for writing BTF debug info. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_BTFDEBUG_H +#define LLVM_LIB_cODEGEN_ASMPRINTER_BTFDEBUG_H + +#include "llvm/CodeGen/DebugHandlerBase.h" +#include +#include + +namespace llvm { + +class AsmPrinter; +class BTF2Debug; +class MachineInstr; +class MCStreamer; + +namespace BTF2 { +enum : uint32_t { MAGIC = 0xeB9F, VERSION = 1 }; +enum { + HeaderSize = 24, + CommonTypeSize = 12, + BTFArraySize = 12, + BTFEnumSize = 8, + BTFMemberSize = 12, + BTFParamSize = 8, + BTFDataSecVarSize = 12, +}; +enum TypeKinds : uint8_t { + BTF_KIND_UNKN = 0, + BTF_KIND_INT = 1, + BTF_KIND_PTR = 2, + BTF_KIND_ARRAY = 3, + BTF_KIND_STRUCT= 4, + BTF_KIND_UNION = 5, + BTF_KIND_ENUM = 6, + BTF_KIND_FWD = 7, + BTF_KIND_TYPEDEF = 8, + BTF_KIND_VOLATILE = 9, + BTF_KIND_CONST = 10, + BTF_KIND_RESTRICT = 11, + BTF_KIND_FUNC = 12, + BTF_KIND_FUNC_PROTO = 13, + BTF_KIND_VAR = 14, + BTF_KIND_DATASEC = 15, + BTF_KIND_FLOAT = 16, +}; + +struct CommonType { + uint32_t NameOff; + uint32_t Info; + union { + uint32_t Size; + uint32_t Type; + }; +}; + +enum : uint8_t { + INT_SIGNED = (1 << 0), + INT_CHAR = (1 << 1), + INT_BOOL = (1 << 2) +}; + +struct BTFEnum { + uint32_t NameOff; + int32_t Val; +}; + +struct BTFArray { + uint32_t ElemType; + uint32_t IndexType; + uint32_t Nelems; +}; + +struct BTFMember { + uint32_t NameOff; ///< Member name offset in the string table + uint32_t Type; ///< Member type + uint32_t Offset; ///< BitOffset or BitFieldSize+BitOffset +}; + +struct BTFParam { + uint32_t NameOff; + uint32_t Type; +}; + +enum : uint8_t { + FUNC_STATIC = 0, + FUNC_GLOBAL = 1, + FUNC_EXTERN = 2, +}; + +enum : uint8_t { + VAR_STATIC = 0, ///< Linkage: InternalLinkage + VAR_GLOBAL_ALLOCATED = 1, ///< Linkage: ExternalLinkage + VAR_GLOBAL_EXTERNAL = 2, ///< Linkage: ExternalLinkage +}; + +struct BTFDataSec { + uint32_t Type; ///< A BTF_KIND_VAR type + uint32_t Offset; ///< In-section offset + uint32_t Size; ///< Occupied memory size +}; + +} + +class BTF2TypeBase { +protected: + uint8_t Kind; + uint32_t Id; + struct BTF2::CommonType BTFType; + +public: + BTF2TypeBase() {} + virtual ~BTF2TypeBase() = default; + void setId(uint32_t Id) { this->Id = Id; } + void setType(uint32_t Type) { BTFType.Type = Type; } + uint32_t roundupToBytes(uint32_t NumBits) { return (NumBits + 7) >> 3; } + virtual uint32_t getSize() { return BTF2::CommonTypeSize; } + virtual void emitType(MCStreamer &OS); +}; + +class BTF2TypeInt : public BTF2TypeBase { + uint32_t IntVal; ///< Encoding, offset, bits + +public: + BTF2TypeInt(uint32_t Encoding, uint32_t SizeInBits, uint32_t OffsetInBits, + uint32_t NameOff); + uint32_t getSize() override { return BTF2TypeBase::getSize() + sizeof(uint32_t); } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeDerived : public BTF2TypeBase { +public: + BTF2TypeDerived(const DIDerivedType *Ty, uint32_t NameOff); +}; + +class BTF2TypeFwd : public BTF2TypeBase { +public: + BTF2TypeFwd(uint32_t NameOff, bool IsUnion); +}; + +class BTF2TypeEnum : public BTF2TypeBase { +public: + std::vector EnumValues; + + BTF2TypeEnum(const DICompositeType *ETy, uint32_t NameOff, uint32_t NumValues); + uint32_t getSize() override { + return BTF2TypeBase::getSize() + EnumValues.size() * BTF2::BTFEnumSize; + } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeArray : public BTF2TypeBase { +public: + struct BTF2::BTFArray ArrayInfo; + + BTF2TypeArray(uint32_t ElemTypeId, uint32_t IndexTypeId, uint32_t NumElems); + uint32_t getSize() override { return BTF2TypeBase::getSize() + BTF2::BTFArraySize; } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeStruct : public BTF2TypeBase { +public: + std::vector Members; + + BTF2TypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, + uint32_t NameOff, uint32_t NumMembers); + uint32_t getSize() override { + return BTF2TypeBase::getSize() + Members.size() * BTF2::BTFMemberSize; + } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeFuncProto : public BTF2TypeBase { +public: + std::vector Parameters; + + BTF2TypeFuncProto(uint32_t NumParams); + uint32_t getSize() override { + return BTF2TypeBase::getSize() + Parameters.size() * BTF2::BTFParamSize; + } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeFunc : public BTF2TypeBase { +public: + BTF2TypeFunc(uint32_t NameOff, uint32_t ProtoTypeId, uint32_t Scope); +}; + +class BTF2KindVar : public BTF2TypeBase { + uint32_t Info; + +public: + BTF2KindVar(uint32_t NameOff, uint32_t TypeId, uint32_t VarInfo); + uint32_t getSize() override { return BTF2TypeBase::getSize() + 4; } + void emitType(MCStreamer &OS) override; +}; + +class BTF2KindDataSec : public BTF2TypeBase { + AsmPrinter *Asm; + std::vector> Vars; + +public: + BTF2KindDataSec(AsmPrinter *AsmPrt, uint32_t SecNameOff); + uint32_t getSize() override { + return BTF2TypeBase::getSize() + BTF2::BTFDataSecVarSize * Vars.size(); + } + void addDataSecEntry(uint32_t Id, const MCSymbol *Sym, uint32_t Size) { + Vars.push_back(std::make_tuple(Id, Sym, Size)); + BTFType.Info += 1; + } + void emitType(MCStreamer &OS) override; +}; + +class BTF2TypeFloat : public BTF2TypeBase { +public: + BTF2TypeFloat(uint32_t SizeInBits, uint32_t NameOff); +}; + +/// String table. +class BTF2StringTable { + uint32_t Size; + std::map OffsetToIdMap; + std::vector Table; + +public: + BTF2StringTable() : Size(0) {} + uint32_t getSize() { return Size; } + std::vector &getTable() { return Table; } + uint32_t addString(StringRef S); + void padStringTable(uint32_t PadLen); +}; + +class BTF2Debug : public DebugHandlerBase { +private: + MCStreamer &OS; + std::map DIToIdMap; + std::vector> TypeEntries; + std::map> DataSecEntries; + uint32_t ArrayIndexTypeId; + BTF2StringTable StringTable; + + uint32_t calcBasicType(const DIBasicType *BTy); + uint32_t calcSubroutineType(const DISubroutineType *STy, bool ForSubprog, + std::map &FuncArgNames); + uint32_t calcFwdDeclType(const DICompositeType *CTy, bool IsUnion); + uint32_t calcStructType(const DICompositeType *STy, bool IsStruct); + uint32_t calcArrayType(const DICompositeType *CTy); + uint32_t calcEnumType(const DICompositeType *ETy); + uint32_t calcCompositeType(const DICompositeType *CTy); + uint32_t calcDerivedType(const DIDerivedType *DTy); + uint32_t getOrCalcTypeEntry(const DIType *Ty); + + uint32_t addType(std::unique_ptr TypeEntry, const DIType *Ty); + void emitBTFSection(); + +protected: + void beginFunctionImpl(const MachineFunction *MF) override {} + void endFunctionImpl(const MachineFunction *MF) override {} + +public: + BTF2Debug(AsmPrinter *AP); + + uint32_t getArrayIndexTypeId() { + assert(ArrayIndexTypeId); + return ArrayIndexTypeId; + } + + size_t addString(StringRef S) { return StringTable.addString(S); } + void padStringTable(uint32_t PadLen) { StringTable.padStringTable(PadLen); } + + 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 {} + void endModule() override; +}; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.cpp b/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/BTF2Debug.cpp @@ -0,0 +1,645 @@ +//===----- llvm/lib/CodeGen/AsmPrinter/BPFDebug.cpp -----------------------===// +// +// 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 support for writing BTF debug info. +// +//===----------------------------------------------------------------------===// + +#include "BTF2Debug.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +static const char *BTFKindStr[] = { + "BTF_KIND_UNKN", + "BTF_KIND_INT", + "BTF_KIND_PTR", + "BTF_KIND_ARRAY", + "BTF_KIND_STRUCT", + "BTF_KIND_UNION", + "BTF_KIND_ENUM", + "BTF_KIND_FWD", + "BTF_KIND_TYPEDEF", + "BTF_KIND_VOLATILE", + "BTF_KIND_CONST", + "BTF_KIND_RESTRICT", + "BTF_KIND_FUNC", + "BTF_KIND_FUNC_PROTO", + "BTF_KIND_VAR", + "BTF_KIND_DATASEC", + "BTF_KIND_FLOAT", +}; + +/// Emit a BTF common type. +void BTF2TypeBase::emitType(MCStreamer &OS) { + OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) + ")"); + OS.emitInt32(BTFType.NameOff); + OS.AddComment("0x" + Twine::utohexstr(BTFType.Info)); + OS.emitInt32(BTFType.Info); + OS.emitInt32(BTFType.Size); +} + +BTF2TypeInt::BTF2TypeInt(uint32_t Encoding, uint32_t SizeInBits, + uint32_t OffsetInBits, uint32_t NameOff) { + // Translate IR int encoding to BTF int encoding. + uint8_t BTFEncoding; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + BTFEncoding = BTF2::INT_BOOL; + break; + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + BTFEncoding = BTF2::INT_SIGNED; + break; + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + BTFEncoding = 0; + break; + default: + llvm_unreachable("Unknown BTF2TypeInt Encoding"); + } + + Kind = BTF2::BTF_KIND_INT; + BTFType.NameOff = NameOff; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); + IntVal = (BTFEncoding << 24) | OffsetInBits << 16 | SizeInBits; +} + +void BTF2TypeInt::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + OS.AddComment("0x" + Twine::utohexstr(IntVal)); + OS.emitInt32(IntVal); +} + +BTF2TypeDerived::BTF2TypeDerived(const DIDerivedType *DTy, uint32_t NameOff) { + unsigned Tag = DTy->getTag(); + switch (Tag) { + case dwarf::DW_TAG_pointer_type: + Kind = BTF2::BTF_KIND_PTR; + break; + case dwarf::DW_TAG_const_type: + Kind = BTF2::BTF_KIND_CONST; + break; + case dwarf::DW_TAG_volatile_type: + Kind = BTF2::BTF_KIND_VOLATILE; + break; + case dwarf::DW_TAG_typedef: + Kind = BTF2::BTF_KIND_TYPEDEF; + break; + case dwarf::DW_TAG_restrict_type: + Kind = BTF2::BTF_KIND_RESTRICT; + break; + default: + llvm_unreachable("Unknown DIDerivedType Tag"); + } + BTFType.NameOff = NameOff; + BTFType.Info = Kind << 24; +} + +BTF2TypeFwd::BTF2TypeFwd(uint32_t NameOff, bool IsUnion) { + Kind = BTF2::BTF_KIND_FWD; + BTFType.NameOff = NameOff; + BTFType.Info = IsUnion << 31 | Kind << 24; + BTFType.Type = 0; +} + +BTF2TypeEnum::BTF2TypeEnum(const DICompositeType *ETy, uint32_t NameOff, uint32_t VLen) { + Kind = BTF2::BTF_KIND_ENUM; + BTFType.NameOff = NameOff; + BTFType.Info = Kind << 24 | VLen; + BTFType.Size = roundupToBytes(ETy->getSizeInBits()); +} + +void BTF2TypeEnum::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + for (const auto &Enum : EnumValues) { + OS.emitInt32(Enum.NameOff); + OS.emitInt32(Enum.Val); + } +} + +BTF2TypeArray::BTF2TypeArray(uint32_t ElemTypeId, uint32_t IndexTypeId, uint32_t NumElems) { + Kind = BTF2::BTF_KIND_ARRAY; + BTFType.NameOff = 0; + BTFType.Info = Kind << 24; + BTFType.Size = 0; + + ArrayInfo.ElemType = ElemTypeId; + ArrayInfo.IndexType = IndexTypeId; + ArrayInfo.Nelems = NumElems; +} + +void BTF2TypeArray::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + OS.emitInt32(ArrayInfo.ElemType); + OS.emitInt32(ArrayInfo.IndexType); + OS.emitInt32(ArrayInfo.Nelems); +} + +BTF2TypeStruct::BTF2TypeStruct(const DICompositeType *STy, bool IsStruct, + bool HasBitField, uint32_t NameOff, + uint32_t Vlen) { + Kind = IsStruct ? BTF2::BTF_KIND_STRUCT : BTF2::BTF_KIND_UNION; + BTFType.NameOff = NameOff; + BTFType.Info = (HasBitField << 31) | (Kind << 24) | Vlen; + BTFType.Size = roundupToBytes(STy->getSizeInBits()); +} + +void BTF2TypeStruct::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + for (const auto &Member : Members) { + OS.emitInt32(Member.NameOff); + OS.emitInt32(Member.Type); + OS.AddComment("0x" + Twine::utohexstr(Member.Offset)); + OS.emitInt32(Member.Offset); + } +} + +BTF2TypeFuncProto::BTF2TypeFuncProto(uint32_t VLen) { + Kind = BTF2::BTF_KIND_FUNC_PROTO; + BTFType.NameOff = 0; + BTFType.Info = (Kind << 24) | VLen; +} + +void BTF2TypeFuncProto::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + for (const auto &Param : Parameters) { + OS.emitInt32(Param.NameOff); + OS.emitInt32(Param.Type); + } +} + +BTF2TypeFunc::BTF2TypeFunc(uint32_t NameOff, uint32_t ProtoTypeId, + uint32_t Scope) { + BTFType.NameOff = NameOff; + Kind = BTF2::BTF_KIND_FUNC; + BTFType.Info = (Kind << 24) | Scope; + BTFType.Type = ProtoTypeId; +} + +BTF2KindVar::BTF2KindVar(uint32_t NameOff, uint32_t TypeId, uint32_t VarInfo) { + Kind = BTF2::BTF_KIND_VAR; + BTFType.NameOff = NameOff; + BTFType.Info = Kind << 24; + BTFType.Type = TypeId; + Info = VarInfo; +} + +void BTF2KindVar::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + OS.emitInt32(Info); +} + +BTF2KindDataSec::BTF2KindDataSec(AsmPrinter *AsmPrt, uint32_t SecNameOff) + : Asm(AsmPrt) { + Kind = BTF2::BTF_KIND_DATASEC; + BTFType.NameOff = SecNameOff; + BTFType.Info = Kind << 24; + BTFType.Size = 0; +} + +void BTF2KindDataSec::emitType(MCStreamer &OS) { + BTF2TypeBase::emitType(OS); + + for (const auto &V : Vars) { + OS.emitInt32(std::get<0>(V)); + Asm->emitLabelReference(std::get<1>(V), 4); + OS.emitInt32(std::get<2>(V)); + } +} + +BTF2TypeFloat::BTF2TypeFloat(uint32_t SizeInBits, uint32_t NameOff) { + Kind = BTF2::BTF_KIND_FLOAT; + BTFType.NameOff = NameOff; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); +} + +uint32_t BTF2StringTable::addString(StringRef S) { + for (auto &OffsetM : OffsetToIdMap) { + if (Table[OffsetM.second] == S) + return OffsetM.first; + } + uint32_t Offset = Size; + OffsetToIdMap[Offset] = Table.size(); + Table.push_back(std::string(S)); + Size += S.size() + 1; + return Offset; +} + +void BTF2StringTable::padStringTable(uint32_t PadLen) { + for (uint32_t i = 0; i < PadLen; i++) + Table.push_back(std::string("\0")); + Size += PadLen; +} + +BTF2Debug::BTF2Debug(AsmPrinter *AP) + : DebugHandlerBase(AP), OS(*Asm->OutStreamer), + ArrayIndexTypeId(0) { + addString("\0"); +} + +uint32_t BTF2Debug::addType(std::unique_ptr TypeEntry, + const DIType *Ty) { + uint32_t Id = TypeEntries.size() + 1; + TypeEntry->setId(Id); + if (Ty != nullptr) + DIToIdMap[Ty] = Id; + TypeEntries.push_back(std::move(TypeEntry)); + return Id; +} + +uint32_t BTF2Debug::calcBasicType(const DIBasicType *BTy) { + uint32_t Encoding = BTy->getEncoding(); + std::unique_ptr TypeEntry; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + TypeEntry = std::make_unique( + Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), + addString(BTy->getName())); + break; + case dwarf::DW_ATE_float: + TypeEntry = + std::make_unique(BTy->getSizeInBits(), + addString(BTy->getName())); + break; + default: + llvm_unreachable("Unknown BTF2TypeInt Encoding"); + } + + return addType(std::move(TypeEntry), BTy); +} + +uint32_t BTF2Debug::calcFwdDeclType(const DICompositeType *CTy, bool IsUnion) { + auto TypeEntry = std::make_unique(addString(CTy->getName()), IsUnion); + return addType(std::move(TypeEntry), CTy); +} + +uint32_t BTF2Debug::calcStructType(const DICompositeType *CTy, bool IsStruct) { + const DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + + // Check whether we have any bitfield members or not + bool HasBitField = false; + for (const auto *Element : Elements) { + auto E = cast(Element); + if (E->isBitField()) { + HasBitField = true; + break; + } + } + + auto TypeEntry = + std::make_unique(CTy, IsStruct, HasBitField, + addString(CTy->getName()), VLen); + BTF2TypeStruct *StructEntry = TypeEntry.get(); + uint32_t TypeId = addType(std::move(TypeEntry), CTy); + + for (const auto &Annotation : CTy->getAnnotations()) { + fprintf(stderr, "TODO (BTF2Debug.cpp): Add %s '%s' annotation '%s' to .BTF section\n", + IsStruct? "struct" : "union", + CTy->getName().str().c_str(), Annotation.str().c_str()); + } + + // Visit all struct members. + for (const auto *Element : Elements) { + struct BTF2::BTFMember BTFMember; + const auto *DDTy = cast(Element); + + for (const auto &Annotation : DDTy->getAnnotations()) { + fprintf(stderr, "TODO (BTF2Debug.cpp): Add field '%s' annotation '%s' to .BTF section\n", + DDTy->getName().str().c_str(), Annotation.str().c_str()); + } + + BTFMember.NameOff = addString(DDTy->getName()); + if (HasBitField) { + uint8_t BitFieldSize = DDTy->isBitField() ? DDTy->getSizeInBits() : 0; + BTFMember.Offset = BitFieldSize << 24 | DDTy->getOffsetInBits(); + } else { + BTFMember.Offset = DDTy->getOffsetInBits(); + } + const auto *BaseTy = DDTy->getBaseType(); + BTFMember.Type = getOrCalcTypeEntry(BaseTy); + StructEntry->Members.push_back(BTFMember); + } + + return TypeId; +} + +uint32_t BTF2Debug::calcArrayType(const DICompositeType *CTy) { + if (!ArrayIndexTypeId) { + auto TypeEntry = std::make_unique(dwarf::DW_ATE_unsigned, 32, + 0, addString("__ARRAY_SIZE_TYPE__")); + ArrayIndexTypeId = addType(std::move(TypeEntry), nullptr); + } + + const DIType *ElemType = CTy->getBaseType(); + uint32_t ElemTypeId = getOrCalcTypeEntry(ElemType); + + std::unique_ptr TypeEntry; + + // Visit array dimensions. + DINodeArray Elements = CTy->getElements(); + for (int I = Elements.size() - 1; I >= 0; --I) { + if (auto *Element = dyn_cast_or_null(Elements[I])) + if (Element->getTag() == dwarf::DW_TAG_subrange_type) { + const DISubrange *SR = cast(Element); + auto *CI = SR->getCount().dyn_cast(); + int64_t Count = CI->getSExtValue(); + + // For struct s { int b; char c[]; }, the c[] will be represented + // as an array with Count = -1. + TypeEntry = + std::make_unique(ElemTypeId, + ArrayIndexTypeId, + Count >= 0 ? Count : 0); + if (I == 0) + ElemTypeId = addType(std::move(TypeEntry), CTy); + else + ElemTypeId = addType(std::move(TypeEntry), nullptr); + } + } + + return ElemTypeId; +} + +uint32_t BTF2Debug::calcEnumType(const DICompositeType *CTy) { + DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + + auto TypeEntry = std::make_unique(CTy, addString(CTy->getName()), VLen); + BTF2TypeEnum *EnumType = TypeEntry.get(); + uint32_t TypeId = addType(std::move(TypeEntry), CTy); + + for (const auto Element : Elements) { + const auto *Enum = cast(Element); + + struct BTF2::BTFEnum BTFEnum; + BTFEnum.NameOff = addString(Enum->getName()); + uint32_t Value; + if (Enum->isUnsigned()) + Value = static_cast(Enum->getValue().getZExtValue()); + else + Value = static_cast(Enum->getValue().getSExtValue()); + BTFEnum.Val = Value; + EnumType->EnumValues.push_back(BTFEnum); + } + + return TypeId; +} + +uint32_t BTF2Debug::calcSubroutineType(const DISubroutineType *STy, + bool ForSubprog, + std::map &FuncArgNames) { + DITypeRefArray Elements = STy->getTypeArray(); + uint32_t VLen = Elements.size() - 1; + + // 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. + uint32_t TypeId; + auto TypeEntry = std::make_unique(VLen); + BTF2TypeFuncProto *FuncProtoType = TypeEntry.get(); + if (ForSubprog) + TypeId = addType(std::move(TypeEntry), nullptr); // For subprogram + else + TypeId = addType(std::move(TypeEntry), STy); // For func ptr + + auto RetType = Elements[0]; + FuncProtoType->setType(RetType ? getOrCalcTypeEntry(RetType) : 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 BTF2::BTFParam Param; + auto Element = Elements[I]; + if (Element) { + Param.NameOff = addString(FuncArgNames[I]); + Param.Type = getOrCalcTypeEntry(Element); + } else { + Param.NameOff = 0; + Param.Type = 0; + } + FuncProtoType->Parameters.push_back(Param); + } + + return TypeId; +} + +uint32_t BTF2Debug::calcCompositeType(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()) + return calcFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type); + else + return calcStructType(CTy, Tag == dwarf::DW_TAG_structure_type); + } else if (Tag == dwarf::DW_TAG_array_type) + return calcArrayType(CTy); + else if (Tag == dwarf::DW_TAG_enumeration_type) + return calcEnumType(CTy); + + llvm_unreachable("Unknown Composite Type"); +} + +uint32_t BTF2Debug::calcDerivedType(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) + return 0; + + auto TypeEntry = std::make_unique(DTy, addString(DTy->getName())); + BTF2TypeDerived *DerivedType = TypeEntry.get(); + uint32_t TypeId = addType(std::move(TypeEntry), DTy); + + uint32_t BaseTypeId; + const DIType *ResolvedType = DTy->getBaseType(); + if (!ResolvedType) { + assert((Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_const_type || + Tag == dwarf::DW_TAG_volatile_type) && + "Invalid null basetype"); + BaseTypeId = 0; + } else { + BaseTypeId = getOrCalcTypeEntry(ResolvedType); + } + DerivedType->setType(BaseTypeId); + + return TypeId; +} + +uint32_t BTF2Debug::getOrCalcTypeEntry(const DIType *Ty) { + if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { + return DIToIdMap[Ty]; + } + + if (const auto *BTy = dyn_cast(Ty)) + return calcBasicType(BTy); + else if (const auto *STy = dyn_cast(Ty)) { + std::map FuncArgNames; + return calcSubroutineType(STy, false, FuncArgNames); + } else if (const auto *CTy = dyn_cast(Ty)) + return calcCompositeType(CTy); + else if (const auto *DTy = dyn_cast(Ty)) + return calcDerivedType(DTy); + + llvm_unreachable("Unknown DIType"); +} + +void BTF2Debug::emitBTFSection() { + if (!TypeEntries.size() && StringTable.getSize() == 1) + return; + + MCContext &Ctx = OS.getContext(); + OS.SwitchSection(Ctx.getELFSection(".BTF", ELF::SHT_PROGBITS, ELF::SHF_ALLOC)); + + // Emit header + OS.AddComment("0x" + Twine::utohexstr(BTF2::MAGIC)); + OS.emitIntValue(BTF2::MAGIC, 2); + OS.emitInt8(BTF2::VERSION); + OS.emitInt8(0); + OS.emitInt32(BTF2::HeaderSize); + + uint32_t TypeLen = 0, StrLen; + for (const auto &TypeEntry : TypeEntries) + TypeLen += TypeEntry->getSize(); + StrLen = StringTable.getSize(); + + OS.emitInt32(0); + OS.emitInt32(TypeLen); + OS.emitInt32(TypeLen); + OS.emitInt32(StrLen); + + for (const auto &TypeEntry : TypeEntries) + TypeEntry->emitType(OS); + + 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 BTF2Debug::endModule() { + if (!Asm || !MMI->hasDebugInfo()) + return; + + const Module *M = MMI->getModule(); + + // Types may not be referenced by globals and functions + for (DICompileUnit *CUNode : M->debug_compile_units()) { + for (auto *Ty : CUNode->getEnumTypes()) { + getOrCalcTypeEntry(cast(Ty)); + } + for (auto *Ty : CUNode->getRetainedTypes()) { + getOrCalcTypeEntry(dyn_cast(Ty)); + } + } + + for (const GlobalVariable &Global: M->globals()) { + auto Linkage = Global.getLinkage(); + uint32_t GVarInfo; + if (Linkage == GlobalValue::InternalLinkage) + GVarInfo = BTF2::VAR_STATIC; + else if (Global.hasInitializer()) + GVarInfo = BTF2::VAR_GLOBAL_ALLOCATED; + else + continue; + + SmallVector GVs; + Global.getDebugInfo(GVs); + if (GVs.size() == 0) + continue; + + uint32_t GVTypeId; + for (auto *GVE : GVs) { + GVTypeId = getOrCalcTypeEntry(GVE->getVariable()->getType()); + break; + } + + auto VarEntry = + std::make_unique(addString(Global.getName()), GVTypeId, GVarInfo); + uint32_t VarId = addType(std::move(VarEntry), nullptr); + + StringRef SecName = Global.getSection(); + if (SecName != ".data..percpu") + continue; + + if (DataSecEntries.find(std::string(SecName)) == DataSecEntries.end()) { + DataSecEntries[std::string(SecName)] = + std::make_unique(Asm, addString(SecName)); + } + + const DataLayout &DL = Global.getParent()->getDataLayout(); + uint32_t Size = DL.getTypeAllocSize(Global.getType()->getElementType()); + + DataSecEntries[std::string(SecName)]->addDataSecEntry(VarId, + Asm->getSymbol(&Global), Size); + } + + for (const Function &Func: M->functions()) { + const DISubprogram *SP = Func.getSubprogram(); + if (!SP || !SP->isDefinition()) + continue; + + std::map FuncArgNames; + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) { + // Collect function arguments for subprogram func type. + uint32_t Arg = DV->getArg(); + if (!Arg) + continue; + + FuncArgNames[Arg] = DV->getName(); + + for (const auto &Annotation : DV->getAnnotations()) { + fprintf(stderr, "TODO (BTF2Debug.cpp): Add func arg '%s' annotation '%s' to .BTF section\n", + DV->getName().str().c_str(), Annotation.str().c_str()); + } + } + } + + uint32_t ProtoTypeId; + const auto *STy = cast(SP->getType()); + for (const auto &Annotation : STy->getAnnotations()) { + fprintf(stderr, "TODO (BTF2Debug.cpp): Add subroutine '%s' annotation '%s' to .BTF section\n", + SP->getName().str().c_str(), Annotation.str().c_str()); + } + + ProtoTypeId = calcSubroutineType(STy, true, FuncArgNames); + + uint8_t Scope = SP->isLocalToUnit() ? BTF2::FUNC_STATIC : BTF2::FUNC_GLOBAL; + auto FuncTypeEntry = + std::make_unique(addString(SP->getName()), ProtoTypeId, Scope); + addType(std::move(FuncTypeEntry), nullptr); + } + + for (auto &DataSec : DataSecEntries) + addType(std::move(DataSec.second), nullptr); + + // Make String section 4-byte aligned. + uint32_t StrLen = StringTable.getSize(); + uint32_t PadLen = ((StrLen + 3) & ~0x3) - StrLen; + if (PadLen) + padStringTable(PadLen); + + emitBTFSection(); +} diff --git a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt --- a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -6,6 +6,7 @@ AsmPrinter.cpp AsmPrinterDwarf.cpp AsmPrinterInlineAsm.cpp + BTF2Debug.cpp DbgEntityHistoryCalculator.cpp DebugHandlerBase.cpp DebugLocStream.cpp