[BPF] Add BTF 64bit enum value support
authorYonghong Song <yhs@fb.com>
Wed, 20 Apr 2022 22:07:08 +0000 (15:07 -0700)
committerYonghong Song <yhs@fb.com>
Mon, 6 Jun 2022 18:35:50 +0000 (11:35 -0700)
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
llvm/lib/Target/BPF/BTF.h
llvm/lib/Target/BPF/BTFDebug.cpp
llvm/lib/Target/BPF/BTFDebug.h
llvm/test/CodeGen/BPF/BTF/enum-basic.ll
llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll
llvm/test/CodeGen/BPF/CORE/intrinsic-typeinfo-enum-value.ll

index 0ae4194..1de0e51 100644 (file)
@@ -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
index e54b97c..4540054 100644 (file)
@@ -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
index 03bb1f6..4e23180 100644 (file)
@@ -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<DIEnumerator>(Element);
+
+    struct BTF::BTFEnum64 BTFEnum;
+    BTFEnum.NameOff = BDebug.addString(Enum->getName());
+    uint64_t Value;
+    if (Enum->isUnsigned())
+      Value = static_cast<uint64_t>(Enum->getValue().getZExtValue());
+    else
+      Value = static_cast<uint64_t>(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<BTFTypeEnum>(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<DIBasicType>(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<BTFTypeEnum>(CTy, VLen, IsSigned);
+    TypeId = addType(std::move(TypeEntry), CTy);
+  } else {
+    assert(NumBits == 64);
+    auto TypeEntry = std::make_unique<BTFTypeEnum64>(CTy, VLen, IsSigned);
+    TypeId = addType(std::move(TypeEntry), CTy);
+  }
   // No need to visit base type as BTF does not encode it.
 }
 
index e328b19..1ad8ec5 100644 (file)
@@ -103,7 +103,7 @@ class BTFTypeEnum : public BTFTypeBase {
   std::vector<struct BTF::BTFEnum> 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<struct BTF::BTFEnum64> 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;
index 49114a5..9a82a36 100644 (file)
@@ -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
index 2acf942..b6013bb 100644 (file)
@@ -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
index 3fa6ae1..7692c4c 100644 (file)
@@ -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