CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
296 lines
8.9 KiB
Python
296 lines
8.9 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Ad-hoc script to print BTF file in a readable format.
|
|
# Follows the same printing conventions as bpftool with format 'raw'.
|
|
# Usage:
|
|
#
|
|
# ./print_btf.py <btf_file>
|
|
#
|
|
# Parameters:
|
|
#
|
|
# <btf_file> :: a file name or '-' to read from stdin.
|
|
#
|
|
# Intended usage:
|
|
#
|
|
# llvm-objcopy --dump-section .BTF=- <input> | ./print_btf.py -
|
|
#
|
|
# Kernel documentation contains detailed format description:
|
|
# https://www.kernel.org/doc/html/latest/bpf/btf.html
|
|
|
|
import struct
|
|
import ctypes
|
|
import sys
|
|
|
|
|
|
class SafeDict(dict):
|
|
def __getitem__(self, key):
|
|
try:
|
|
return dict.__getitem__(self, key)
|
|
except KeyError:
|
|
return f"<BAD_KEY: {key}>"
|
|
|
|
|
|
KINDS = SafeDict(
|
|
{
|
|
0: "UNKN",
|
|
1: "INT",
|
|
2: "PTR",
|
|
3: "ARRAY",
|
|
4: "STRUCT",
|
|
5: "UNION",
|
|
6: "ENUM",
|
|
7: "FWD",
|
|
8: "TYPEDEF",
|
|
9: "VOLATILE",
|
|
10: "CONST",
|
|
11: "RESTRICT",
|
|
12: "FUNC",
|
|
13: "FUNC_PROTO",
|
|
14: "VAR",
|
|
15: "DATASEC",
|
|
16: "FLOAT",
|
|
17: "DECL_TAG",
|
|
18: "TYPE_TAG",
|
|
19: "ENUM64",
|
|
}
|
|
)
|
|
|
|
INT_ENCODING = SafeDict(
|
|
{0 << 0: "(none)", 1 << 0: "SIGNED", 1 << 1: "CHAR", 1 << 2: "BOOL"}
|
|
)
|
|
|
|
ENUM_ENCODING = SafeDict({0: "UNSIGNED", 1: "SIGNED"})
|
|
|
|
FUNC_LINKAGE = SafeDict({0: "static", 1: "global", 2: "extern"})
|
|
|
|
VAR_LINKAGE = SafeDict({0: "static", 1: "global", 2: "extern"})
|
|
|
|
FWD_KIND = SafeDict(
|
|
{
|
|
0: "struct",
|
|
1: "union",
|
|
}
|
|
)
|
|
|
|
for val, name in KINDS.items():
|
|
globals()["BTF_KIND_" + name] = val
|
|
|
|
|
|
def warn(message):
|
|
print(message, file=sys.stderr)
|
|
|
|
|
|
def print_btf(filename):
|
|
if filename == "-":
|
|
buf = sys.stdin.buffer.read()
|
|
else:
|
|
with open(filename, "rb") as file:
|
|
buf = file.read()
|
|
|
|
fmt_cache = {}
|
|
endian_pfx = ">" # big endian
|
|
off = 0
|
|
|
|
def unpack(fmt):
|
|
nonlocal off, endian_pfx
|
|
fmt = endian_pfx + fmt
|
|
if fmt not in fmt_cache:
|
|
fmt_cache[fmt] = struct.Struct(fmt)
|
|
st = fmt_cache[fmt]
|
|
r = st.unpack_from(buf, off)
|
|
off += st.size
|
|
return r
|
|
|
|
# Use magic number at the header start to determine endianness
|
|
(magic,) = unpack("H")
|
|
if magic == 0xEB9F:
|
|
endian_pfx = ">" # big endian
|
|
elif magic == 0x9FEB:
|
|
endian_pfx = "<" # little endian
|
|
else:
|
|
warn(f"Unexpected BTF magic: {magic:02x}")
|
|
return
|
|
|
|
# Rest of the header
|
|
version, flags, hdr_len = unpack("BBI")
|
|
type_off, type_len, str_off, str_len = unpack("IIII")
|
|
|
|
# Offsets in the header are relative to the end of a header
|
|
type_off += hdr_len
|
|
str_off += hdr_len
|
|
off = hdr_len
|
|
type_end = type_off + type_len
|
|
|
|
def string(rel_off):
|
|
try:
|
|
start = str_off + rel_off
|
|
end = buf.index(b"\0", start)
|
|
if start == end:
|
|
return "(anon)"
|
|
return buf[start:end].decode("utf8")
|
|
except ValueError as e:
|
|
warn(f"Can't get string at offset {str_off} + {rel_off}: {e}")
|
|
return f"<BAD_STRING {rel_off}>"
|
|
|
|
idx = 1
|
|
while off < type_end:
|
|
name_off, info, size = unpack("III")
|
|
kind = (info >> 24) & 0x1F
|
|
vlen = info & 0xFFFF
|
|
kflag = info >> 31
|
|
kind_name = KINDS[kind]
|
|
name = string(name_off)
|
|
|
|
def warn_nonzero(val, name):
|
|
nonlocal idx
|
|
if val != 0:
|
|
warn(f"<{idx}> {name} should be 0 but is {val}")
|
|
|
|
if kind == BTF_KIND_INT:
|
|
(info,) = unpack("I")
|
|
encoding = (info & 0x0F000000) >> 24
|
|
offset = (info & 0x00FF0000) >> 16
|
|
bits = info & 0x000000FF
|
|
enc_name = INT_ENCODING[encoding]
|
|
print(
|
|
f"[{idx}] {kind_name} '{name}' size={size} "
|
|
f"bits_offset={offset} "
|
|
f"nr_bits={bits} encoding={enc_name}"
|
|
)
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
|
|
elif kind in [
|
|
BTF_KIND_PTR,
|
|
BTF_KIND_CONST,
|
|
BTF_KIND_VOLATILE,
|
|
BTF_KIND_RESTRICT,
|
|
]:
|
|
print(f"[{idx}] {kind_name} '{name}' type_id={size}")
|
|
warn_nonzero(name_off, "name_off")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
|
|
elif kind == BTF_KIND_ARRAY:
|
|
warn_nonzero(name_off, "name_off")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
warn_nonzero(size, "size")
|
|
type, index_type, nelems = unpack("III")
|
|
print(
|
|
f"[{idx}] {kind_name} '{name}' type_id={type} "
|
|
f"index_type_id={index_type} nr_elems={nelems}"
|
|
)
|
|
|
|
elif kind in [BTF_KIND_STRUCT, BTF_KIND_UNION]:
|
|
print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}")
|
|
if kflag not in [0, 1]:
|
|
warn(f"<{idx}> kflag should 0 or 1: {kflag}")
|
|
for _ in range(0, vlen):
|
|
name_off, type, offset = unpack("III")
|
|
if kflag == 0:
|
|
print(
|
|
f"\t'{string(name_off)}' type_id={type} "
|
|
f"bits_offset={offset}"
|
|
)
|
|
else:
|
|
bits_offset = offset & 0xFFFFFF
|
|
bitfield_size = offset >> 24
|
|
print(
|
|
f"\t'{string(name_off)}' type_id={type} "
|
|
f"bits_offset={bits_offset} "
|
|
f"bitfield_size={bitfield_size}"
|
|
)
|
|
|
|
elif kind == BTF_KIND_ENUM:
|
|
encoding = ENUM_ENCODING[kflag]
|
|
print(
|
|
f"[{idx}] {kind_name} '{name}' encoding={encoding} "
|
|
f"size={size} vlen={vlen}"
|
|
)
|
|
for _ in range(0, vlen):
|
|
(name_off,) = unpack("I")
|
|
(val,) = unpack("i" if kflag == 1 else "I")
|
|
print(f"\t'{string(name_off)}' val={val}")
|
|
|
|
elif kind == BTF_KIND_ENUM64:
|
|
encoding = ENUM_ENCODING[kflag]
|
|
print(
|
|
f"[{idx}] {kind_name} '{name}' encoding={encoding} "
|
|
f"size={size} vlen={vlen}"
|
|
)
|
|
for _ in range(0, vlen):
|
|
name_off, lo, hi = unpack("III")
|
|
val = hi << 32 | lo
|
|
if kflag == 1:
|
|
val = ctypes.c_long(val).value
|
|
print(f"\t'{string(name_off)}' val={val}LL")
|
|
|
|
elif kind == BTF_KIND_FWD:
|
|
print(f"[{idx}] {kind_name} '{name}' fwd_kind={FWD_KIND[kflag]}")
|
|
warn_nonzero(vlen, "vlen")
|
|
warn_nonzero(size, "size")
|
|
|
|
elif kind in [BTF_KIND_TYPEDEF, BTF_KIND_TYPE_TAG]:
|
|
print(f"[{idx}] {kind_name} '{name}' type_id={size}")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(kflag, "vlen")
|
|
|
|
elif kind == BTF_KIND_FUNC:
|
|
linkage = FUNC_LINKAGE[vlen]
|
|
print(f"[{idx}] {kind_name} '{name}' type_id={size} " f"linkage={linkage}")
|
|
warn_nonzero(kflag, "kflag")
|
|
|
|
elif kind == BTF_KIND_FUNC_PROTO:
|
|
print(f"[{idx}] {kind_name} '{name}' ret_type_id={size} " f"vlen={vlen}")
|
|
warn_nonzero(name_off, "name_off")
|
|
warn_nonzero(kflag, "kflag")
|
|
for _ in range(0, vlen):
|
|
name_off, type = unpack("II")
|
|
print(f"\t'{string(name_off)}' type_id={type}")
|
|
|
|
elif kind == BTF_KIND_VAR:
|
|
(linkage,) = unpack("I")
|
|
linkage = VAR_LINKAGE[linkage]
|
|
print(f"[{idx}] {kind_name} '{name}' type_id={size}, " f"linkage={linkage}")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
|
|
elif kind == BTF_KIND_DATASEC:
|
|
print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(size, "size")
|
|
for _ in range(0, vlen):
|
|
type, offset, size = unpack("III")
|
|
print(f"\ttype_id={type} offset={offset} size={size}")
|
|
|
|
elif kind == BTF_KIND_FLOAT:
|
|
print(f"[{idx}] {kind_name} '{name}' size={size}")
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
|
|
elif kind == BTF_KIND_DECL_TAG:
|
|
(component_idx,) = unpack("i")
|
|
print(
|
|
f"[{idx}] {kind_name} '{name}' type_id={size} "
|
|
+ f"component_idx={component_idx}"
|
|
)
|
|
warn_nonzero(kflag, "kflag")
|
|
warn_nonzero(vlen, "vlen")
|
|
|
|
else:
|
|
warn(
|
|
f"<{idx}> Unexpected entry: kind={kind_name} "
|
|
f"name_off={name_off} "
|
|
f"vlen={vlen} kflag={kflag} size={size}"
|
|
)
|
|
|
|
idx += 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 2:
|
|
warn(f"Usage: {sys.argv[0]} <btf_file>")
|
|
sys.exit(1)
|
|
print_btf(sys.argv[1])
|