xref: /aosp_15_r20/external/bcc/tests/python/test_disassembler.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) Clevernet
3*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
4*387f9dfdSAndroid Build Coastguard Worker
5*387f9dfdSAndroid Build Coastguard Worker# test program for the 'disassemble_func' and 'decode_table' methods
6*387f9dfdSAndroid Build Coastguard Worker
7*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
8*387f9dfdSAndroid Build Coastguard Workerfrom bcc import disassembler
9*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct
10*387f9dfdSAndroid Build Coastguard Workerimport random
11*387f9dfdSAndroid Build Coastguard Workerfrom unittest import main, TestCase
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Workerclass BPFInstr(ct.Structure):
14*387f9dfdSAndroid Build Coastguard Worker    _pack_ = 1
15*387f9dfdSAndroid Build Coastguard Worker    _fields_ = [('opcode', ct.c_uint8),
16*387f9dfdSAndroid Build Coastguard Worker                ('dst', ct.c_uint8, 4),
17*387f9dfdSAndroid Build Coastguard Worker                ('src', ct.c_uint8, 4),
18*387f9dfdSAndroid Build Coastguard Worker                ('offset', ct.c_int16),
19*387f9dfdSAndroid Build Coastguard Worker                ('imm', ct.c_int32)]
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerclass TestDisassembler(TestCase):
22*387f9dfdSAndroid Build Coastguard Worker    opcodes = [(0x04, "%dst += %imm"),
23*387f9dfdSAndroid Build Coastguard Worker               (0x05, "goto %off <%jmp>"),
24*387f9dfdSAndroid Build Coastguard Worker               (0x07, "%dst += %imm"),
25*387f9dfdSAndroid Build Coastguard Worker               (0x0c, "%dst += %src"),
26*387f9dfdSAndroid Build Coastguard Worker               (0x0f, "%dst += %src"),
27*387f9dfdSAndroid Build Coastguard Worker               (0x14, "%dst -= %imm"),
28*387f9dfdSAndroid Build Coastguard Worker               (0x15, "if %dst == %imm goto pc%off <%jmp>"),
29*387f9dfdSAndroid Build Coastguard Worker               (0x17, "%dst -= %imm"),
30*387f9dfdSAndroid Build Coastguard Worker               #(0x18, "lddw"),
31*387f9dfdSAndroid Build Coastguard Worker               (0x1c, "%dst -= %src"),
32*387f9dfdSAndroid Build Coastguard Worker               (0x1d, "if %dst == %src goto pc%off <%jmp>"),
33*387f9dfdSAndroid Build Coastguard Worker               (0x1f, "%dst -= %src"),
34*387f9dfdSAndroid Build Coastguard Worker               (0x20, "r0 = *(u32*)skb[%imm]"),
35*387f9dfdSAndroid Build Coastguard Worker               (0x24, "%dst *= %imm"),
36*387f9dfdSAndroid Build Coastguard Worker               (0x25, "if %dst > %imm goto pc%off <%jmp>"),
37*387f9dfdSAndroid Build Coastguard Worker               (0x27, "%dst *= %imm"),
38*387f9dfdSAndroid Build Coastguard Worker               (0x28, "r0 = *(u16*)skb[%imm]"),
39*387f9dfdSAndroid Build Coastguard Worker               (0x2c, "%dst *= %src"),
40*387f9dfdSAndroid Build Coastguard Worker               (0x2d, "if %dst > %src goto pc%off <%jmp>"),
41*387f9dfdSAndroid Build Coastguard Worker               (0x2f, "%dst *= %src"),
42*387f9dfdSAndroid Build Coastguard Worker               (0x30, "r0 = *(u8*)skb[%imm]"),
43*387f9dfdSAndroid Build Coastguard Worker               (0x34, "%dst /= %imm"),
44*387f9dfdSAndroid Build Coastguard Worker               (0x35, "if %dst >= %imm goto pc%off <%jmp>"),
45*387f9dfdSAndroid Build Coastguard Worker               (0x37, "%dst /= %imm"),
46*387f9dfdSAndroid Build Coastguard Worker               (0x38, "r0 = *(u64*)skb[%imm]"),
47*387f9dfdSAndroid Build Coastguard Worker               (0x3c, "%dst /= %src"),
48*387f9dfdSAndroid Build Coastguard Worker               (0x3d, "if %dst >= %src goto pc%off <%jmp>"),
49*387f9dfdSAndroid Build Coastguard Worker               (0x3f, "%dst /= %src"),
50*387f9dfdSAndroid Build Coastguard Worker               (0x40, "r0 = *(u32*)skb[%src %sim]"),
51*387f9dfdSAndroid Build Coastguard Worker               (0x44, "%dst |= %ibw"),
52*387f9dfdSAndroid Build Coastguard Worker               (0x45, "if %dst & %imm goto pc%off <%jmp>"),
53*387f9dfdSAndroid Build Coastguard Worker               (0x47, "%dst |= %ibw"),
54*387f9dfdSAndroid Build Coastguard Worker               (0x48, "r0 = *(u16*)skb[%src %sim]"),
55*387f9dfdSAndroid Build Coastguard Worker               (0x4c, "%dst |= %src"),
56*387f9dfdSAndroid Build Coastguard Worker               (0x4d, "if %dst & %src goto pc%off <%jmp>"),
57*387f9dfdSAndroid Build Coastguard Worker               (0x4f, "%dst |= %src"),
58*387f9dfdSAndroid Build Coastguard Worker               (0x50, "r0 = *(u8*)skb[%src %sim]"),
59*387f9dfdSAndroid Build Coastguard Worker               (0x54, "%dst &= %ibw"),
60*387f9dfdSAndroid Build Coastguard Worker               (0x55, "if %dst != %imm goto pc%off <%jmp>"),
61*387f9dfdSAndroid Build Coastguard Worker               (0x57, "%dst &= %ibw"),
62*387f9dfdSAndroid Build Coastguard Worker               (0x58, "r0 = *(u64*)skb[%src %sim]"),
63*387f9dfdSAndroid Build Coastguard Worker               (0x5c, "%dst &= %src"),
64*387f9dfdSAndroid Build Coastguard Worker               (0x5d, "if %dst != %src goto pc%off <%jmp>"),
65*387f9dfdSAndroid Build Coastguard Worker               (0x5f, "%dst &= %src"),
66*387f9dfdSAndroid Build Coastguard Worker               (0x61, "%dst = *(u32*)(%src %off)"),
67*387f9dfdSAndroid Build Coastguard Worker               (0x62, "*(u32*)(%dst %off) = %imm"),
68*387f9dfdSAndroid Build Coastguard Worker               (0x63, "*(u32*)(%dst %off) = %src"),
69*387f9dfdSAndroid Build Coastguard Worker               (0x64, "%dst <<= %imm"),
70*387f9dfdSAndroid Build Coastguard Worker               (0x65, "if %dst s> %imm goto pc%off <%jmp>"),
71*387f9dfdSAndroid Build Coastguard Worker               (0x67, "%dst <<= %imm"),
72*387f9dfdSAndroid Build Coastguard Worker               (0x69, "%dst = *(u16*)(%src %off)"),
73*387f9dfdSAndroid Build Coastguard Worker               (0x6a, "*(u16*)(%dst %off) = %imm"),
74*387f9dfdSAndroid Build Coastguard Worker               (0x6b, "*(u16*)(%dst %off) = %src"),
75*387f9dfdSAndroid Build Coastguard Worker               (0x6c, "%dst <<= %src"),
76*387f9dfdSAndroid Build Coastguard Worker               (0x6d, "if %dst s> %src goto pc%off <%jmp>"),
77*387f9dfdSAndroid Build Coastguard Worker               (0x6f, "%dst <<= %src"),
78*387f9dfdSAndroid Build Coastguard Worker               (0x71, "%dst = *(u8*)(%src %off)"),
79*387f9dfdSAndroid Build Coastguard Worker               (0x72, "*(u8*)(%dst %off) = %imm"),
80*387f9dfdSAndroid Build Coastguard Worker               (0x73, "*(u8*)(%dst %off) = %src"),
81*387f9dfdSAndroid Build Coastguard Worker               (0x74, "%dst >>= %imm"),
82*387f9dfdSAndroid Build Coastguard Worker               (0x75, "if %dst s>= %imm goto pc%off <%jmp>"),
83*387f9dfdSAndroid Build Coastguard Worker               (0x77, "%dst >>= %imm"),
84*387f9dfdSAndroid Build Coastguard Worker               (0x79, "%dst = *(u64*)(%src %off)"),
85*387f9dfdSAndroid Build Coastguard Worker               (0x7a, "*(u64*)(%dst %off) = %imm"),
86*387f9dfdSAndroid Build Coastguard Worker               (0x7b, "*(u64*)(%dst %off) = %src"),
87*387f9dfdSAndroid Build Coastguard Worker               (0x7c, "%dst >>= %src"),
88*387f9dfdSAndroid Build Coastguard Worker               (0x7d, "if %dst s>= %src goto pc%off <%jmp>"),
89*387f9dfdSAndroid Build Coastguard Worker               (0x7f, "%dst >>= %src"),
90*387f9dfdSAndroid Build Coastguard Worker               (0x84, "%dst = ~ (u32)%dst"),
91*387f9dfdSAndroid Build Coastguard Worker               #(0x85, "call"),
92*387f9dfdSAndroid Build Coastguard Worker               (0x87, "%dst = ~ (u64)%dst"),
93*387f9dfdSAndroid Build Coastguard Worker               (0x94, "%dst %= %imm"),
94*387f9dfdSAndroid Build Coastguard Worker               (0x95, "exit"),
95*387f9dfdSAndroid Build Coastguard Worker               (0x97, "%dst %= %imm"),
96*387f9dfdSAndroid Build Coastguard Worker               (0x9c, "%dst %= %src"),
97*387f9dfdSAndroid Build Coastguard Worker               (0x9f, "%dst %= %src"),
98*387f9dfdSAndroid Build Coastguard Worker               (0xa4, "%dst ^= %ibw"),
99*387f9dfdSAndroid Build Coastguard Worker               (0xa5, "if %dst < %imm goto pc%off <%jmp>"),
100*387f9dfdSAndroid Build Coastguard Worker               (0xa7, "%dst ^= %ibw"),
101*387f9dfdSAndroid Build Coastguard Worker               (0xac, "%dst ^= %src"),
102*387f9dfdSAndroid Build Coastguard Worker               (0xad, "if %dst < %src goto pc%off <%jmp>"),
103*387f9dfdSAndroid Build Coastguard Worker               (0xaf, "%dst ^= %src"),
104*387f9dfdSAndroid Build Coastguard Worker               (0xb4, "%dst = %imm"),
105*387f9dfdSAndroid Build Coastguard Worker               (0xb5, "if %dst <= %imm goto pc%off <%jmp>"),
106*387f9dfdSAndroid Build Coastguard Worker               (0xb7, "%dst = %imm"),
107*387f9dfdSAndroid Build Coastguard Worker               (0xbc, "%dst = %src"),
108*387f9dfdSAndroid Build Coastguard Worker               (0xbd, "if %dst <= %src goto pc%off <%jmp>"),
109*387f9dfdSAndroid Build Coastguard Worker               (0xbf, "%dst = %src"),
110*387f9dfdSAndroid Build Coastguard Worker               (0xc4, "%dst s>>= %imm"),
111*387f9dfdSAndroid Build Coastguard Worker               (0xc5, "if %dst s< %imm goto pc%off <%jmp>"),
112*387f9dfdSAndroid Build Coastguard Worker               (0xc7, "%dst s>>= %imm"),
113*387f9dfdSAndroid Build Coastguard Worker               (0xcc, "%dst s>>= %src"),
114*387f9dfdSAndroid Build Coastguard Worker               (0xcd, "if %dst s< %src goto pc%off <%jmp>"),
115*387f9dfdSAndroid Build Coastguard Worker               (0xcf, "%dst s>>= %src"),
116*387f9dfdSAndroid Build Coastguard Worker               (0xd5, "if %dst s<= %imm goto pc%off <%jmp>"),
117*387f9dfdSAndroid Build Coastguard Worker               (0xdc, "%dst endian %src"),
118*387f9dfdSAndroid Build Coastguard Worker               (0xdd, "if %dst s<= %imm goto pc%off <%jmp>"),]
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker    @classmethod
121*387f9dfdSAndroid Build Coastguard Worker    def build_instr(cls, op):
122*387f9dfdSAndroid Build Coastguard Worker        dst = random.randint(0, 0xf)
123*387f9dfdSAndroid Build Coastguard Worker        src = random.randint(0, 0xf)
124*387f9dfdSAndroid Build Coastguard Worker        offset = random.randint(0, 0xffff)
125*387f9dfdSAndroid Build Coastguard Worker        imm = random.randint(0, 0xffffffff)
126*387f9dfdSAndroid Build Coastguard Worker        return BPFInstr(op, dst, src, offset, imm)
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker    @classmethod
129*387f9dfdSAndroid Build Coastguard Worker    def format_instr(cls, instr, fmt):
130*387f9dfdSAndroid Build Coastguard Worker        uimm = ct.c_uint32(instr.imm).value
131*387f9dfdSAndroid Build Coastguard Worker        return (fmt.replace("%dst", "r%d" % (instr.dst))
132*387f9dfdSAndroid Build Coastguard Worker                   .replace("%src", "r%d" % (instr.src))
133*387f9dfdSAndroid Build Coastguard Worker                   .replace("%imm", "%d" % (instr.imm))
134*387f9dfdSAndroid Build Coastguard Worker                   .replace("%ibw", "0x%x" % (uimm))
135*387f9dfdSAndroid Build Coastguard Worker                   .replace("%sim", "%+d" % (instr.imm))
136*387f9dfdSAndroid Build Coastguard Worker                   .replace("%off", "%+d" % (instr.offset))
137*387f9dfdSAndroid Build Coastguard Worker                   .replace("%jmp", "%d" % (instr.offset + 1)))
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker    def test_func(self):
140*387f9dfdSAndroid Build Coastguard Worker        b = BPF(text=b"""
141*387f9dfdSAndroid Build Coastguard Worker            struct key_t {int a; short b; struct {int c:4; int d:8;} e;} __attribute__((__packed__));
142*387f9dfdSAndroid Build Coastguard Worker            BPF_HASH(test_map, struct key_t);
143*387f9dfdSAndroid Build Coastguard Worker            int test_func(void)
144*387f9dfdSAndroid Build Coastguard Worker            {
145*387f9dfdSAndroid Build Coastguard Worker                return 1;
146*387f9dfdSAndroid Build Coastguard Worker            }""")
147*387f9dfdSAndroid Build Coastguard Worker
148*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(
149*387f9dfdSAndroid Build Coastguard Worker            """Disassemble of BPF program b'test_func':
150*387f9dfdSAndroid Build Coastguard Worker   0: (b7) r0 = 1
151*387f9dfdSAndroid Build Coastguard Worker   1: (95) exit""",
152*387f9dfdSAndroid Build Coastguard Worker            b.disassemble_func(b"test_func"))
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker        def _assert_equal_ignore_fd_id(s1, s2):
155*387f9dfdSAndroid Build Coastguard Worker            # In first line of string like
156*387f9dfdSAndroid Build Coastguard Worker            #    Layout of BPF map test_map (type HASH, FD 3, ID 0):
157*387f9dfdSAndroid Build Coastguard Worker            # Ignore everything from FD to end-of-line
158*387f9dfdSAndroid Build Coastguard Worker            # Compare rest of string normally
159*387f9dfdSAndroid Build Coastguard Worker            s1_lines = s1.split('\n')
160*387f9dfdSAndroid Build Coastguard Worker            s2_lines = s2.split('\n')
161*387f9dfdSAndroid Build Coastguard Worker            s1_first_cut = s1_lines[0]
162*387f9dfdSAndroid Build Coastguard Worker            s1_first_cut = s1_first_cut[0:s1_first_cut.index("FD")]
163*387f9dfdSAndroid Build Coastguard Worker            s2_first_cut = s2_lines[0]
164*387f9dfdSAndroid Build Coastguard Worker            s2_first_cut = s2_first_cut[0:s2_first_cut.index("FD")]
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker            self.assertEqual(s1_first_cut, s2_first_cut)
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker            s1_rest = '\n'.join(s1_lines[1:])
169*387f9dfdSAndroid Build Coastguard Worker            s2_rest = '\n'.join(s2_lines[1:])
170*387f9dfdSAndroid Build Coastguard Worker            self.assertEqual(s1_rest, s2_rest)
171*387f9dfdSAndroid Build Coastguard Worker
172*387f9dfdSAndroid Build Coastguard Worker        _assert_equal_ignore_fd_id(
173*387f9dfdSAndroid Build Coastguard Worker            """Layout of BPF map b'test_map' (type HASH, FD 3, ID 0):
174*387f9dfdSAndroid Build Coastguard Worker  struct {
175*387f9dfdSAndroid Build Coastguard Worker    int a;
176*387f9dfdSAndroid Build Coastguard Worker    short b;
177*387f9dfdSAndroid Build Coastguard Worker    struct {
178*387f9dfdSAndroid Build Coastguard Worker      int c:4;
179*387f9dfdSAndroid Build Coastguard Worker      int d:8;
180*387f9dfdSAndroid Build Coastguard Worker    } e;
181*387f9dfdSAndroid Build Coastguard Worker  } key;
182*387f9dfdSAndroid Build Coastguard Worker  unsigned long long value;""",
183*387f9dfdSAndroid Build Coastguard Worker            b.decode_table(b"test_map"))
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker    def test_bpf_isa(self):
186*387f9dfdSAndroid Build Coastguard Worker        for op, instr_fmt in self.opcodes:
187*387f9dfdSAndroid Build Coastguard Worker            instr_fmt
188*387f9dfdSAndroid Build Coastguard Worker            if instr_fmt is None:
189*387f9dfdSAndroid Build Coastguard Worker                continue
190*387f9dfdSAndroid Build Coastguard Worker            instr = self.build_instr(op)
191*387f9dfdSAndroid Build Coastguard Worker            instr_str = ct.string_at(ct.addressof(instr), ct.sizeof(instr))
192*387f9dfdSAndroid Build Coastguard Worker            target_text = self.format_instr(instr, instr_fmt)
193*387f9dfdSAndroid Build Coastguard Worker            self.assertEqual(disassembler.disassemble_str(instr_str)[0],
194*387f9dfdSAndroid Build Coastguard Worker                             "%4d: (%02x) %s" % (0, op, target_text))
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__":
197*387f9dfdSAndroid Build Coastguard Worker    main()
198