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