From dc1c43d726c87e18fae33cb26f2cd05dbd1fdfa5 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 20 Apr 2022 15:07:08 -0700 Subject: [PATCH] [BPF] Add BTF 64bit enum value support Current BTF only supports 32-bit value. For example, enum T { VAL = 0xffffFFFF00000008 }; the generated BTF looks like .long 16 # BTF_KIND_ENUM(id = 4) .long 100663297 # 0x6000001 .long 8 .long 18 .long 8 The encoded value is 8 which equals to (uint32_t)0xffffFFFF00000008 and this is incorrect. This patch introduced BTF_KIND_ENUM64 which permits to encode 64-bit value. The format for each enumerator looks like: .long name_offset .long (uint32_t)value # lower-32 bit value .long value >> 32 # high-32 bit value We use two 32-bit values to represent a 64-bit value as current BTF type subsection has 4-byte alignment and gaps are not permitted in the subsection. This patch also added support for kflag (the bit 31 of CommonType.Info) such that kflag = 1 implies the value is signed and kflag = 0 implies the value is unsigned. The kernel UAPI enumerator definition is struct btf_enum { __u32 name_off; __s32 val; }; so kflag = 0 with unsigned value provides backward compatability. With this patch, for enum T { VAL = 0xffffFFFF00000008 }; the generated BTF looks like .long 16 # BTF_KIND_ENUM64(id = 4) .long 3187671053 # 0x13000001 .long 8 .long 18 .long 8 # 0x8 .long 4294967295 # 0xffffffff and the enumerator value and signedness are encoded correctly. Differential Revision: https://reviews.llvm.org/D124641 --- llvm/lib/Target/BPF/BTF.def | 1 + llvm/lib/Target/BPF/BTF.h | 10 +++ llvm/lib/Target/BPF/BTFDebug.cpp | 68 +++++++++++++++++-- llvm/lib/Target/BPF/BTFDebug.h | 16 ++++- llvm/test/CodeGen/BPF/BTF/enum-basic.ll | 2 +- ...nsic-typeinfo-enum-value-opaque-pointer.ll | 2 +- .../BPF/CORE/intrinsic-typeinfo-enum-value.ll | 23 ++++++- 7 files changed, 113 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/BPF/BTF.def b/llvm/lib/Target/BPF/BTF.def index 0ae4194bc512..1de0e51b4757 100644 --- a/llvm/lib/Target/BPF/BTF.def +++ b/llvm/lib/Target/BPF/BTF.def @@ -33,5 +33,6 @@ HANDLE_BTF_KIND(15, DATASEC) HANDLE_BTF_KIND(16, FLOAT) HANDLE_BTF_KIND(17, DECL_TAG) HANDLE_BTF_KIND(18, TYPE_TAG) +HANDLE_BTF_KIND(19, ENUM64) #undef HANDLE_BTF_KIND diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h index e54b97cd49a9..4540054aaf34 100644 --- a/llvm/lib/Target/BPF/BTF.h +++ b/llvm/lib/Target/BPF/BTF.h @@ -60,6 +60,7 @@ enum { CommonTypeSize = 12, BTFArraySize = 12, BTFEnumSize = 8, + BTFEnum64Size = 12, BTFMemberSize = 12, BTFParamSize = 8, BTFDataSecVarSize = 12, @@ -145,6 +146,15 @@ struct BTFEnum { int32_t Val; ///< Enum member value }; +/// BTF_KIND_ENUM64 is followed by multiple "struct BTFEnum64". +/// The exact number of BTFEnum64 is stored in the vlen (of the +/// info in "struct CommonType"). +struct BTFEnum64 { + uint32_t NameOff; ///< Enum name offset in the string table + uint32_t Val_Lo32; ///< Enum member lo32 value + uint32_t Val_Hi32; ///< Enum member hi32 value +}; + /// BTF_KIND_ARRAY is followed by one "struct BTFArray". struct BTFArray { uint32_t ElemType; ///< Element type diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp index 03bb1f67992e..4e23180227bd 100644 --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -162,9 +162,10 @@ void BTFTypeInt::emitType(MCStreamer &OS) { OS.emitInt32(IntVal); } -BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen) : ETy(ETy) { +BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen, + bool IsSigned) : ETy(ETy) { Kind = BTF::BTF_KIND_ENUM; - BTFType.Info = Kind << 24 | VLen; + BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; BTFType.Size = roundupToBytes(ETy->getSizeInBits()); } @@ -200,6 +201,48 @@ void BTFTypeEnum::emitType(MCStreamer &OS) { } } +BTFTypeEnum64::BTFTypeEnum64(const DICompositeType *ETy, uint32_t VLen, + bool IsSigned) : ETy(ETy) { + Kind = BTF::BTF_KIND_ENUM64; + BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; + BTFType.Size = roundupToBytes(ETy->getSizeInBits()); +} + +void BTFTypeEnum64::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(ETy->getName()); + + DINodeArray Elements = ETy->getElements(); + for (const auto Element : Elements) { + const auto *Enum = cast(Element); + + struct BTF::BTFEnum64 BTFEnum; + BTFEnum.NameOff = BDebug.addString(Enum->getName()); + uint64_t Value; + if (Enum->isUnsigned()) + Value = static_cast(Enum->getValue().getZExtValue()); + else + Value = static_cast(Enum->getValue().getSExtValue()); + BTFEnum.Val_Lo32 = Value; + BTFEnum.Val_Hi32 = Value >> 32; + EnumValues.push_back(BTFEnum); + } +} + +void BTFTypeEnum64::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Enum : EnumValues) { + OS.emitInt32(Enum.NameOff); + OS.AddComment("0x" + Twine::utohexstr(Enum.Val_Lo32)); + OS.emitInt32(Enum.Val_Lo32); + OS.AddComment("0x" + Twine::utohexstr(Enum.Val_Hi32)); + OS.emitInt32(Enum.Val_Hi32); + } +} + BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) { Kind = BTF::BTF_KIND_ARRAY; BTFType.NameOff = 0; @@ -674,8 +717,25 @@ void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { if (VLen > BTF::MAX_VLEN) return; - auto TypeEntry = std::make_unique(CTy, VLen); - TypeId = addType(std::move(TypeEntry), CTy); + bool IsSigned = false; + unsigned NumBits = 32; + // No BaseType implies forward declaration in which case a + // BTFTypeEnum with Vlen = 0 is emitted. + if (CTy->getBaseType() != nullptr) { + const auto *BTy = cast(CTy->getBaseType()); + IsSigned = BTy->getEncoding() == dwarf::DW_ATE_signed || + BTy->getEncoding() == dwarf::DW_ATE_signed_char; + NumBits = BTy->getSizeInBits(); + } + + if (NumBits <= 32) { + auto TypeEntry = std::make_unique(CTy, VLen, IsSigned); + TypeId = addType(std::move(TypeEntry), CTy); + } else { + assert(NumBits == 64); + auto TypeEntry = std::make_unique(CTy, VLen, IsSigned); + TypeId = addType(std::move(TypeEntry), CTy); + } // No need to visit base type as BTF does not encode it. } diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h index e328b19e6c9c..1ad8ec5d918c 100644 --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -103,7 +103,7 @@ class BTFTypeEnum : public BTFTypeBase { std::vector EnumValues; public: - BTFTypeEnum(const DICompositeType *ETy, uint32_t NumValues); + BTFTypeEnum(const DICompositeType *ETy, uint32_t NumValues, bool IsSigned); uint32_t getSize() override { return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnumSize; } @@ -218,6 +218,20 @@ public: void emitType(MCStreamer &OS) override; }; +/// Handle 64-bit enumerate type. +class BTFTypeEnum64 : public BTFTypeBase { + const DICompositeType *ETy; + std::vector EnumValues; + +public: + BTFTypeEnum64(const DICompositeType *ETy, uint32_t NumValues, bool IsSigned); + uint32_t getSize() override { + return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnum64Size; + } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + class BTFTypeTypeTag : public BTFTypeBase { const DIDerivedType *DTy; StringRef Tag; diff --git a/llvm/test/CodeGen/BPF/BTF/enum-basic.ll b/llvm/test/CodeGen/BPF/BTF/enum-basic.ll index 49114a56c059..9a82a36c8975 100644 --- a/llvm/test/CodeGen/BPF/BTF/enum-basic.ll +++ b/llvm/test/CodeGen/BPF/BTF/enum-basic.ll @@ -22,7 +22,7 @@ ; CHECK-NEXT: .long 28 ; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long 0 # BTF_KIND_ENUM(id = 1) -; CHECK-NEXT: .long 100663298 # 0x6000002 +; CHECK-NEXT: .long 2248146946 # 0x86000002 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long -1 diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll index 2acf942d3503..b6013bb07590 100644 --- a/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll @@ -36,7 +36,7 @@ entry: ; CHECK: r{{[0-9]+}} = -2147483648 ll ; CHECK: exit -; CHECK: .long 16 # BTF_KIND_ENUM(id = 4) +; CHECK: .long 16 # BTF_KIND_ENUM64(id = 4) ; CHECK: .long 57 # BTF_KIND_TYPEDEF(id = 5) ; CHECK: .ascii ".text" # string offset=10 diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value.ll index 3fa6ae1b22b3..7692c4c432b2 100644 --- a/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value.ll +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value.ll @@ -36,14 +36,33 @@ entry: ; CHECK: r{{[0-9]+}} = -2147483648 ll ; CHECK: exit -; CHECK: .long 16 # BTF_KIND_ENUM(id = 4) -; CHECK: .long 57 # BTF_KIND_TYPEDEF(id = 5) +; CHECK: .long 16 # BTF_KIND_ENUM64(id = 4) +; CHECK-NEXT: .long 2466250754 # 0x93000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 4294967196 # 0xffffff9c +; CHECK-NEXT: .long 4294967295 # 0xffffffff +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 4294934528 # 0xffff8000 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 57 # BTF_KIND_TYPEDEF(id = 5) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # BTF_KIND_ENUM64(id = 6) +; CHECK-NEXT: .long 318767105 # 0x13000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 62 +; CHECK-NEXT: .long 2147483648 # 0x80000000 +; CHECK-NEXT: .long 4294967295 # 0xffffffff ; CHECK: .ascii ".text" # string offset=10 ; CHECK: .ascii "AA" # string offset=16 +; CHECK: .ascii "VAL1" # string offset=19 +; CHECK: .ascii "VAL2" # string offset=24 ; CHECK: .byte 48 # string offset=29 ; CHECK: .byte 49 # string offset=55 ; CHECK: .ascii "__BB" # string offset=57 +; CHECK: .ascii "VAL10" # string offset=62 ; CHECK: .long 16 # FieldReloc ; CHECK-NEXT: .long 10 # Field reloc section string offset=10