brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.9 KiB · c574d0f Raw
296 lines · python
1#!/usr/bin/env python32 3# Ad-hoc script to print BTF file in a readable format.4# Follows the same printing conventions as bpftool with format 'raw'.5# Usage:6#7#   ./print_btf.py <btf_file>8#9# Parameters:10#11#   <btf_file> :: a file name or '-' to read from stdin.12#13# Intended usage:14#15#   llvm-objcopy --dump-section .BTF=- <input> | ./print_btf.py -16#17# Kernel documentation contains detailed format description:18#   https://www.kernel.org/doc/html/latest/bpf/btf.html19 20import struct21import ctypes22import sys23 24 25class SafeDict(dict):26    def __getitem__(self, key):27        try:28            return dict.__getitem__(self, key)29        except KeyError:30            return f"<BAD_KEY: {key}>"31 32 33KINDS = SafeDict(34    {35        0: "UNKN",36        1: "INT",37        2: "PTR",38        3: "ARRAY",39        4: "STRUCT",40        5: "UNION",41        6: "ENUM",42        7: "FWD",43        8: "TYPEDEF",44        9: "VOLATILE",45        10: "CONST",46        11: "RESTRICT",47        12: "FUNC",48        13: "FUNC_PROTO",49        14: "VAR",50        15: "DATASEC",51        16: "FLOAT",52        17: "DECL_TAG",53        18: "TYPE_TAG",54        19: "ENUM64",55    }56)57 58INT_ENCODING = SafeDict(59    {0 << 0: "(none)", 1 << 0: "SIGNED", 1 << 1: "CHAR", 1 << 2: "BOOL"}60)61 62ENUM_ENCODING = SafeDict({0: "UNSIGNED", 1: "SIGNED"})63 64FUNC_LINKAGE = SafeDict({0: "static", 1: "global", 2: "extern"})65 66VAR_LINKAGE = SafeDict({0: "static", 1: "global", 2: "extern"})67 68FWD_KIND = SafeDict(69    {70        0: "struct",71        1: "union",72    }73)74 75for val, name in KINDS.items():76    globals()["BTF_KIND_" + name] = val77 78 79def warn(message):80    print(message, file=sys.stderr)81 82 83def print_btf(filename):84    if filename == "-":85        buf = sys.stdin.buffer.read()86    else:87        with open(filename, "rb") as file:88            buf = file.read()89 90    fmt_cache = {}91    endian_pfx = ">"  # big endian92    off = 093 94    def unpack(fmt):95        nonlocal off, endian_pfx96        fmt = endian_pfx + fmt97        if fmt not in fmt_cache:98            fmt_cache[fmt] = struct.Struct(fmt)99        st = fmt_cache[fmt]100        r = st.unpack_from(buf, off)101        off += st.size102        return r103 104    # Use magic number at the header start to determine endianness105    (magic,) = unpack("H")106    if magic == 0xEB9F:107        endian_pfx = ">"  # big endian108    elif magic == 0x9FEB:109        endian_pfx = "<"  # little endian110    else:111        warn(f"Unexpected BTF magic: {magic:02x}")112        return113 114    # Rest of the header115    version, flags, hdr_len = unpack("BBI")116    type_off, type_len, str_off, str_len = unpack("IIII")117 118    # Offsets in the header are relative to the end of a header119    type_off += hdr_len120    str_off += hdr_len121    off = hdr_len122    type_end = type_off + type_len123 124    def string(rel_off):125        try:126            start = str_off + rel_off127            end = buf.index(b"\0", start)128            if start == end:129                return "(anon)"130            return buf[start:end].decode("utf8")131        except ValueError as e:132            warn(f"Can't get string at offset {str_off} + {rel_off}: {e}")133            return f"<BAD_STRING {rel_off}>"134 135    idx = 1136    while off < type_end:137        name_off, info, size = unpack("III")138        kind = (info >> 24) & 0x1F139        vlen = info & 0xFFFF140        kflag = info >> 31141        kind_name = KINDS[kind]142        name = string(name_off)143 144        def warn_nonzero(val, name):145            nonlocal idx146            if val != 0:147                warn(f"<{idx}> {name} should be 0 but is {val}")148 149        if kind == BTF_KIND_INT:150            (info,) = unpack("I")151            encoding = (info & 0x0F000000) >> 24152            offset = (info & 0x00FF0000) >> 16153            bits = info & 0x000000FF154            enc_name = INT_ENCODING[encoding]155            print(156                f"[{idx}] {kind_name} '{name}' size={size} "157                f"bits_offset={offset} "158                f"nr_bits={bits} encoding={enc_name}"159            )160            warn_nonzero(kflag, "kflag")161            warn_nonzero(vlen, "vlen")162 163        elif kind in [164            BTF_KIND_PTR,165            BTF_KIND_CONST,166            BTF_KIND_VOLATILE,167            BTF_KIND_RESTRICT,168        ]:169            print(f"[{idx}] {kind_name} '{name}' type_id={size}")170            warn_nonzero(name_off, "name_off")171            warn_nonzero(kflag, "kflag")172            warn_nonzero(vlen, "vlen")173 174        elif kind == BTF_KIND_ARRAY:175            warn_nonzero(name_off, "name_off")176            warn_nonzero(kflag, "kflag")177            warn_nonzero(vlen, "vlen")178            warn_nonzero(size, "size")179            type, index_type, nelems = unpack("III")180            print(181                f"[{idx}] {kind_name} '{name}' type_id={type} "182                f"index_type_id={index_type} nr_elems={nelems}"183            )184 185        elif kind in [BTF_KIND_STRUCT, BTF_KIND_UNION]:186            print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}")187            if kflag not in [0, 1]:188                warn(f"<{idx}> kflag should 0 or 1: {kflag}")189            for _ in range(0, vlen):190                name_off, type, offset = unpack("III")191                if kflag == 0:192                    print(193                        f"\t'{string(name_off)}' type_id={type} "194                        f"bits_offset={offset}"195                    )196                else:197                    bits_offset = offset & 0xFFFFFF198                    bitfield_size = offset >> 24199                    print(200                        f"\t'{string(name_off)}' type_id={type} "201                        f"bits_offset={bits_offset} "202                        f"bitfield_size={bitfield_size}"203                    )204 205        elif kind == BTF_KIND_ENUM:206            encoding = ENUM_ENCODING[kflag]207            print(208                f"[{idx}] {kind_name} '{name}' encoding={encoding} "209                f"size={size} vlen={vlen}"210            )211            for _ in range(0, vlen):212                (name_off,) = unpack("I")213                (val,) = unpack("i" if kflag == 1 else "I")214                print(f"\t'{string(name_off)}' val={val}")215 216        elif kind == BTF_KIND_ENUM64:217            encoding = ENUM_ENCODING[kflag]218            print(219                f"[{idx}] {kind_name} '{name}' encoding={encoding} "220                f"size={size} vlen={vlen}"221            )222            for _ in range(0, vlen):223                name_off, lo, hi = unpack("III")224                val = hi << 32 | lo225                if kflag == 1:226                    val = ctypes.c_long(val).value227                print(f"\t'{string(name_off)}' val={val}LL")228 229        elif kind == BTF_KIND_FWD:230            print(f"[{idx}] {kind_name} '{name}' fwd_kind={FWD_KIND[kflag]}")231            warn_nonzero(vlen, "vlen")232            warn_nonzero(size, "size")233 234        elif kind in [BTF_KIND_TYPEDEF, BTF_KIND_TYPE_TAG]:235            print(f"[{idx}] {kind_name} '{name}' type_id={size}")236            warn_nonzero(kflag, "kflag")237            warn_nonzero(kflag, "vlen")238 239        elif kind == BTF_KIND_FUNC:240            linkage = FUNC_LINKAGE[vlen]241            print(f"[{idx}] {kind_name} '{name}' type_id={size} " f"linkage={linkage}")242            warn_nonzero(kflag, "kflag")243 244        elif kind == BTF_KIND_FUNC_PROTO:245            print(f"[{idx}] {kind_name} '{name}' ret_type_id={size} " f"vlen={vlen}")246            warn_nonzero(name_off, "name_off")247            warn_nonzero(kflag, "kflag")248            for _ in range(0, vlen):249                name_off, type = unpack("II")250                print(f"\t'{string(name_off)}' type_id={type}")251 252        elif kind == BTF_KIND_VAR:253            (linkage,) = unpack("I")254            linkage = VAR_LINKAGE[linkage]255            print(f"[{idx}] {kind_name} '{name}' type_id={size}, " f"linkage={linkage}")256            warn_nonzero(kflag, "kflag")257            warn_nonzero(vlen, "vlen")258 259        elif kind == BTF_KIND_DATASEC:260            print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}")261            warn_nonzero(kflag, "kflag")262            warn_nonzero(size, "size")263            for _ in range(0, vlen):264                type, offset, size = unpack("III")265                print(f"\ttype_id={type} offset={offset} size={size}")266 267        elif kind == BTF_KIND_FLOAT:268            print(f"[{idx}] {kind_name} '{name}' size={size}")269            warn_nonzero(kflag, "kflag")270            warn_nonzero(vlen, "vlen")271 272        elif kind == BTF_KIND_DECL_TAG:273            (component_idx,) = unpack("i")274            print(275                f"[{idx}] {kind_name} '{name}' type_id={size} "276                + f"component_idx={component_idx}"277            )278            warn_nonzero(kflag, "kflag")279            warn_nonzero(vlen, "vlen")280 281        else:282            warn(283                f"<{idx}> Unexpected entry: kind={kind_name} "284                f"name_off={name_off} "285                f"vlen={vlen} kflag={kflag} size={size}"286            )287 288        idx += 1289 290 291if __name__ == "__main__":292    if len(sys.argv) != 2:293        warn(f"Usage: {sys.argv[0]} <btf_file>")294        sys.exit(1)295    print_btf(sys.argv[1])296