clang supports arbitrary length ints using the _ExtInt extension. This
can be useful to hold very large values, e.g. 256 bit or 512 bit types.

Larger types (e.g. 1024 bits) are possible but I am unaware of a use
case for these.

This requires the _ExtInt extension to enabled for BPF in clang, which
is under review.

Link: https://clang.llvm.org/docs/LanguageExtensions.html#extended-integer-types
Link: https://reviews.llvm.org/D93103

Signed-off-by: Sean Young <s...@mess.org>
---
 Documentation/bpf/btf.rst      |  4 ++--
 include/uapi/linux/btf.h       |  2 +-
 tools/bpf/bpftool/btf_dumper.c | 39 ++++++++++++++++++++++++++++++++++
 tools/include/uapi/linux/btf.h |  2 +-
 4 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst
index 44dc789de2b4..784f1743dbc7 100644
--- a/Documentation/bpf/btf.rst
+++ b/Documentation/bpf/btf.rst
@@ -132,7 +132,7 @@ The following sections detail encoding of each kind.
 
   #define BTF_INT_ENCODING(VAL)   (((VAL) & 0x0f000000) >> 24)
   #define BTF_INT_OFFSET(VAL)     (((VAL) & 0x00ff0000) >> 16)
-  #define BTF_INT_BITS(VAL)       ((VAL)  & 0x000000ff)
+  #define BTF_INT_BITS(VAL)       ((VAL)  & 0x000003ff)
 
 The ``BTF_INT_ENCODING`` has the following attributes::
 
@@ -147,7 +147,7 @@ pretty print. At most one encoding can be specified for the 
int type.
 The ``BTF_INT_BITS()`` specifies the number of actual bits held by this int
 type. For example, a 4-bit bitfield encodes ``BTF_INT_BITS()`` equals to 4.
 The ``btf_type.size * 8`` must be equal to or greater than ``BTF_INT_BITS()``
-for the type. The maximum value of ``BTF_INT_BITS()`` is 128.
+for the type. The maximum value of ``BTF_INT_BITS()`` is 512.
 
 The ``BTF_INT_OFFSET()`` specifies the starting bit offset to calculate values
 for this int. For example, a bitfield struct member has:
diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h
index 5a667107ad2c..1696fd02b302 100644
--- a/include/uapi/linux/btf.h
+++ b/include/uapi/linux/btf.h
@@ -84,7 +84,7 @@ struct btf_type {
  */
 #define BTF_INT_ENCODING(VAL)  (((VAL) & 0x0f000000) >> 24)
 #define BTF_INT_OFFSET(VAL)    (((VAL) & 0x00ff0000) >> 16)
-#define BTF_INT_BITS(VAL)      ((VAL)  & 0x000000ff)
+#define BTF_INT_BITS(VAL)      ((VAL)  & 0x000003ff)
 
 /* Attributes stored in the BTF_INT_ENCODING */
 #define BTF_INT_SIGNED (1 << 0)
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index 0e9310727281..45ed45ea9962 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -271,6 +271,40 @@ static void btf_int128_print(json_writer_t *jw, const void 
*data,
        }
 }
 
+static void btf_bigint_print(json_writer_t *jw, const void *data, int nr_bits,
+                            bool is_plain_text)
+{
+       char buf[nr_bits / 4 + 1];
+       bool first = true;
+       int i;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+       for (i = 0; i < nr_bits / 64; i++) {
+#else
+       for (i = nr_bits / 64 - 1; i >= 0; i++) {
+#endif
+               __u64 v = ((__u64 *)data)[i];
+
+               if (first) {
+                       if (!v)
+                               continue;
+
+                       snprintf(buf, sizeof(buf), "%llx", v);
+
+                       first = false;
+               } else {
+                       size_t off = strlen(buf);
+
+                       snprintf(buf + off, sizeof(buf) - off, "%016llx", v);
+               }
+       }
+
+       if (is_plain_text)
+               jsonw_printf(jw, "0x%s", buf);
+       else
+               jsonw_printf(jw, "\"0x%s\"", buf);
+}
+
 static void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits,
                             __u16 right_shift_bits)
 {
@@ -373,6 +407,11 @@ static int btf_dumper_int(const struct btf_type *t, __u8 
bit_offset,
                return 0;
        }
 
+       if (nr_bits > 128) {
+               btf_bigint_print(jw, data, nr_bits, is_plain_text);
+               return 0;
+       }
+
        if (nr_bits == 128) {
                btf_int128_print(jw, data, is_plain_text);
                return 0;
diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h
index 5a667107ad2c..1696fd02b302 100644
--- a/tools/include/uapi/linux/btf.h
+++ b/tools/include/uapi/linux/btf.h
@@ -84,7 +84,7 @@ struct btf_type {
  */
 #define BTF_INT_ENCODING(VAL)  (((VAL) & 0x0f000000) >> 24)
 #define BTF_INT_OFFSET(VAL)    (((VAL) & 0x00ff0000) >> 16)
-#define BTF_INT_BITS(VAL)      ((VAL)  & 0x000000ff)
+#define BTF_INT_BITS(VAL)      ((VAL)  & 0x000003ff)
 
 /* Attributes stored in the BTF_INT_ENCODING */
 #define BTF_INT_SIGNED (1 << 0)
-- 
2.29.2

Reply via email to