1 1.7 christos /* $NetBSD: bpf_image.c,v 1.7 2024/09/02 15:33:36 christos Exp $ */ 2 1.2 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996 5 1.1 christos * The Regents of the University of California. All rights reserved. 6 1.1 christos * 7 1.1 christos * Redistribution and use in source and binary forms, with or without 8 1.1 christos * modification, are permitted provided that: (1) source code distributions 9 1.1 christos * retain the above copyright notice and this paragraph in its entirety, (2) 10 1.1 christos * distributions including binary code include the above copyright notice and 11 1.1 christos * this paragraph in its entirety in the documentation or other materials 12 1.1 christos * provided with the distribution, and (3) all advertising materials mentioning 13 1.1 christos * features or use of this software display the following acknowledgement: 14 1.1 christos * ``This product includes software developed by the University of California, 15 1.1 christos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 1.1 christos * the University nor the names of its contributors may be used to endorse 17 1.1 christos * or promote products derived from this software without specific prior 18 1.1 christos * written permission. 19 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 1.1 christos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 1.1 christos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 1.1 christos */ 23 1.1 christos 24 1.2 christos #include <sys/cdefs.h> 25 1.7 christos __RCSID("$NetBSD: bpf_image.c,v 1.7 2024/09/02 15:33:36 christos Exp $"); 26 1.1 christos 27 1.4 christos #include <config.h> 28 1.1 christos 29 1.4 christos #include <pcap-types.h> 30 1.1 christos 31 1.1 christos #include <stdio.h> 32 1.1 christos #include <string.h> 33 1.1 christos 34 1.6 christos #ifdef __linux__ 35 1.6 christos #include <linux/types.h> 36 1.6 christos #include <linux/if_packet.h> 37 1.6 christos #include <linux/filter.h> 38 1.6 christos 39 1.6 christos /* 40 1.6 christos * We want our versions of these #defines, not Linux's version. 41 1.6 christos * (The two should be the same; if not, we have a problem; all BPF 42 1.6 christos * implementations *should* be source-compatible supersets of ours.) 43 1.6 christos */ 44 1.6 christos #undef BPF_STMT 45 1.6 christos #undef BPF_JUMP 46 1.6 christos #endif 47 1.6 christos 48 1.1 christos #include "pcap-int.h" 49 1.1 christos 50 1.7 christos #include "thread-local.h" 51 1.7 christos 52 1.1 christos #ifdef HAVE_OS_PROTO_H 53 1.1 christos #include "os-proto.h" 54 1.1 christos #endif 55 1.1 christos 56 1.6 christos #ifdef SKF_AD_OFF 57 1.6 christos /* 58 1.6 christos * Symbolic names for offsets that refer to the special Linux BPF locations. 59 1.6 christos */ 60 1.6 christos static const char *offsets[SKF_AD_MAX] = { 61 1.6 christos #ifdef SKF_AD_PROTOCOL 62 1.6 christos [SKF_AD_PROTOCOL] = "proto", 63 1.6 christos #endif 64 1.6 christos #ifdef SKF_AD_PKTTYPE 65 1.6 christos [SKF_AD_PKTTYPE] = "type", 66 1.6 christos #endif 67 1.6 christos #ifdef SKF_AD_IFINDEX 68 1.6 christos [SKF_AD_IFINDEX] = "ifidx", 69 1.6 christos #endif 70 1.6 christos #ifdef SKF_AD_NLATTR 71 1.6 christos [SKF_AD_NLATTR] = "nla", 72 1.6 christos #endif 73 1.6 christos #ifdef SKF_AD_NLATTR_NEST 74 1.6 christos [SKF_AD_NLATTR_NEST] = "nlan", 75 1.6 christos #endif 76 1.6 christos #ifdef SKF_AD_MARK 77 1.6 christos [SKF_AD_MARK] = "mark", 78 1.6 christos #endif 79 1.6 christos #ifdef SKF_AD_QUEUE 80 1.6 christos [SKF_AD_QUEUE] = "queue", 81 1.6 christos #endif 82 1.6 christos #ifdef SKF_AD_HATYPE 83 1.6 christos [SKF_AD_HATYPE] = "hatype", 84 1.6 christos #endif 85 1.6 christos #ifdef SKF_AD_RXHASH 86 1.6 christos [SKF_AD_RXHASH] = "rxhash", 87 1.6 christos #endif 88 1.6 christos #ifdef SKF_AD_CPU 89 1.6 christos [SKF_AD_CPU] = "cpu", 90 1.6 christos #endif 91 1.6 christos #ifdef SKF_AD_ALU_XOR_X 92 1.6 christos [SKF_AD_ALU_XOR_X] = "xor_x", 93 1.6 christos #endif 94 1.6 christos #ifdef SKF_AD_VLAN_TAG 95 1.6 christos [SKF_AD_VLAN_TAG] = "vlan_tci", 96 1.6 christos #endif 97 1.6 christos #ifdef SKF_AD_VLAN_TAG_PRESENT 98 1.6 christos [SKF_AD_VLAN_TAG_PRESENT] = "vlanp", 99 1.6 christos #endif 100 1.6 christos #ifdef SKF_AD_PAY_OFFSET 101 1.6 christos [SKF_AD_PAY_OFFSET] = "poff", 102 1.6 christos #endif 103 1.6 christos #ifdef SKF_AD_RANDOM 104 1.6 christos [SKF_AD_RANDOM] = "random", 105 1.6 christos #endif 106 1.6 christos #ifdef SKF_AD_VLAN_TPID 107 1.6 christos [SKF_AD_VLAN_TPID] = "vlan_tpid" 108 1.6 christos #endif 109 1.6 christos }; 110 1.6 christos #endif 111 1.6 christos 112 1.6 christos static void 113 1.6 christos bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p) 114 1.6 christos { 115 1.6 christos #ifdef SKF_AD_OFF 116 1.6 christos const char *sym; 117 1.6 christos 118 1.6 christos /* 119 1.6 christos * It's an absolute load. 120 1.6 christos * Is the offset a special Linux offset that we know about? 121 1.6 christos */ 122 1.6 christos if (p->k >= (bpf_u_int32)SKF_AD_OFF && 123 1.6 christos p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) && 124 1.6 christos (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) { 125 1.6 christos /* 126 1.6 christos * Yes. Print the offset symbolically. 127 1.6 christos */ 128 1.6 christos (void)snprintf(buf, bufsize, "[%s]", sym); 129 1.6 christos } else 130 1.6 christos #endif 131 1.6 christos (void)snprintf(buf, bufsize, "[%d]", p->k); 132 1.6 christos } 133 1.6 christos 134 1.1 christos char * 135 1.4 christos bpf_image(const struct bpf_insn *p, int n) 136 1.1 christos { 137 1.4 christos const char *op; 138 1.7 christos static thread_local char image[256]; 139 1.4 christos char operand_buf[64]; 140 1.4 christos const char *operand; 141 1.1 christos 142 1.1 christos switch (p->code) { 143 1.1 christos 144 1.1 christos default: 145 1.1 christos op = "unimp"; 146 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code); 147 1.4 christos operand = operand_buf; 148 1.1 christos break; 149 1.1 christos 150 1.1 christos case BPF_RET|BPF_K: 151 1.1 christos op = "ret"; 152 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 153 1.4 christos operand = operand_buf; 154 1.1 christos break; 155 1.1 christos 156 1.1 christos case BPF_RET|BPF_A: 157 1.1 christos op = "ret"; 158 1.4 christos operand = ""; 159 1.1 christos break; 160 1.1 christos 161 1.1 christos case BPF_LD|BPF_W|BPF_ABS: 162 1.1 christos op = "ld"; 163 1.6 christos bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); 164 1.4 christos operand = operand_buf; 165 1.1 christos break; 166 1.1 christos 167 1.1 christos case BPF_LD|BPF_H|BPF_ABS: 168 1.1 christos op = "ldh"; 169 1.6 christos bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); 170 1.4 christos operand = operand_buf; 171 1.1 christos break; 172 1.1 christos 173 1.1 christos case BPF_LD|BPF_B|BPF_ABS: 174 1.1 christos op = "ldb"; 175 1.6 christos bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); 176 1.4 christos operand = operand_buf; 177 1.1 christos break; 178 1.1 christos 179 1.1 christos case BPF_LD|BPF_W|BPF_LEN: 180 1.1 christos op = "ld"; 181 1.4 christos operand = "#pktlen"; 182 1.1 christos break; 183 1.1 christos 184 1.1 christos case BPF_LD|BPF_W|BPF_IND: 185 1.1 christos op = "ld"; 186 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); 187 1.4 christos operand = operand_buf; 188 1.1 christos break; 189 1.1 christos 190 1.1 christos case BPF_LD|BPF_H|BPF_IND: 191 1.1 christos op = "ldh"; 192 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); 193 1.4 christos operand = operand_buf; 194 1.1 christos break; 195 1.1 christos 196 1.1 christos case BPF_LD|BPF_B|BPF_IND: 197 1.1 christos op = "ldb"; 198 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); 199 1.4 christos operand = operand_buf; 200 1.1 christos break; 201 1.1 christos 202 1.1 christos case BPF_LD|BPF_IMM: 203 1.1 christos op = "ld"; 204 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 205 1.4 christos operand = operand_buf; 206 1.1 christos break; 207 1.1 christos 208 1.1 christos case BPF_LDX|BPF_IMM: 209 1.1 christos op = "ldx"; 210 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 211 1.4 christos operand = operand_buf; 212 1.1 christos break; 213 1.1 christos 214 1.1 christos case BPF_LDX|BPF_MSH|BPF_B: 215 1.1 christos op = "ldxb"; 216 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k); 217 1.4 christos operand = operand_buf; 218 1.1 christos break; 219 1.1 christos 220 1.1 christos case BPF_LD|BPF_MEM: 221 1.1 christos op = "ld"; 222 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); 223 1.4 christos operand = operand_buf; 224 1.1 christos break; 225 1.1 christos 226 1.1 christos case BPF_LDX|BPF_MEM: 227 1.1 christos op = "ldx"; 228 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); 229 1.4 christos operand = operand_buf; 230 1.1 christos break; 231 1.1 christos 232 1.1 christos case BPF_ST: 233 1.1 christos op = "st"; 234 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); 235 1.4 christos operand = operand_buf; 236 1.1 christos break; 237 1.1 christos 238 1.1 christos case BPF_STX: 239 1.1 christos op = "stx"; 240 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); 241 1.4 christos operand = operand_buf; 242 1.1 christos break; 243 1.1 christos 244 1.1 christos case BPF_JMP|BPF_JA: 245 1.1 christos op = "ja"; 246 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k); 247 1.4 christos operand = operand_buf; 248 1.1 christos break; 249 1.1 christos 250 1.1 christos case BPF_JMP|BPF_JGT|BPF_K: 251 1.1 christos op = "jgt"; 252 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 253 1.4 christos operand = operand_buf; 254 1.1 christos break; 255 1.1 christos 256 1.1 christos case BPF_JMP|BPF_JGE|BPF_K: 257 1.1 christos op = "jge"; 258 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 259 1.4 christos operand = operand_buf; 260 1.1 christos break; 261 1.1 christos 262 1.1 christos case BPF_JMP|BPF_JEQ|BPF_K: 263 1.1 christos op = "jeq"; 264 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 265 1.4 christos operand = operand_buf; 266 1.1 christos break; 267 1.1 christos 268 1.1 christos case BPF_JMP|BPF_JSET|BPF_K: 269 1.1 christos op = "jset"; 270 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 271 1.4 christos operand = operand_buf; 272 1.1 christos break; 273 1.1 christos 274 1.1 christos case BPF_JMP|BPF_JGT|BPF_X: 275 1.1 christos op = "jgt"; 276 1.4 christos operand = "x"; 277 1.1 christos break; 278 1.1 christos 279 1.1 christos case BPF_JMP|BPF_JGE|BPF_X: 280 1.1 christos op = "jge"; 281 1.4 christos operand = "x"; 282 1.1 christos break; 283 1.1 christos 284 1.1 christos case BPF_JMP|BPF_JEQ|BPF_X: 285 1.1 christos op = "jeq"; 286 1.4 christos operand = "x"; 287 1.1 christos break; 288 1.1 christos 289 1.1 christos case BPF_JMP|BPF_JSET|BPF_X: 290 1.1 christos op = "jset"; 291 1.4 christos operand = "x"; 292 1.1 christos break; 293 1.1 christos 294 1.1 christos case BPF_ALU|BPF_ADD|BPF_X: 295 1.1 christos op = "add"; 296 1.4 christos operand = "x"; 297 1.1 christos break; 298 1.1 christos 299 1.1 christos case BPF_ALU|BPF_SUB|BPF_X: 300 1.1 christos op = "sub"; 301 1.4 christos operand = "x"; 302 1.1 christos break; 303 1.1 christos 304 1.1 christos case BPF_ALU|BPF_MUL|BPF_X: 305 1.1 christos op = "mul"; 306 1.4 christos operand = "x"; 307 1.1 christos break; 308 1.1 christos 309 1.1 christos case BPF_ALU|BPF_DIV|BPF_X: 310 1.1 christos op = "div"; 311 1.4 christos operand = "x"; 312 1.1 christos break; 313 1.1 christos 314 1.2 christos case BPF_ALU|BPF_MOD|BPF_X: 315 1.2 christos op = "mod"; 316 1.4 christos operand = "x"; 317 1.2 christos break; 318 1.2 christos 319 1.1 christos case BPF_ALU|BPF_AND|BPF_X: 320 1.1 christos op = "and"; 321 1.4 christos operand = "x"; 322 1.1 christos break; 323 1.1 christos 324 1.1 christos case BPF_ALU|BPF_OR|BPF_X: 325 1.1 christos op = "or"; 326 1.4 christos operand = "x"; 327 1.1 christos break; 328 1.1 christos 329 1.2 christos case BPF_ALU|BPF_XOR|BPF_X: 330 1.2 christos op = "xor"; 331 1.4 christos operand = "x"; 332 1.2 christos break; 333 1.2 christos 334 1.1 christos case BPF_ALU|BPF_LSH|BPF_X: 335 1.1 christos op = "lsh"; 336 1.4 christos operand = "x"; 337 1.1 christos break; 338 1.1 christos 339 1.1 christos case BPF_ALU|BPF_RSH|BPF_X: 340 1.1 christos op = "rsh"; 341 1.4 christos operand = "x"; 342 1.1 christos break; 343 1.1 christos 344 1.1 christos case BPF_ALU|BPF_ADD|BPF_K: 345 1.1 christos op = "add"; 346 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 347 1.4 christos operand = operand_buf; 348 1.1 christos break; 349 1.1 christos 350 1.1 christos case BPF_ALU|BPF_SUB|BPF_K: 351 1.1 christos op = "sub"; 352 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 353 1.4 christos operand = operand_buf; 354 1.1 christos break; 355 1.1 christos 356 1.1 christos case BPF_ALU|BPF_MUL|BPF_K: 357 1.1 christos op = "mul"; 358 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 359 1.4 christos operand = operand_buf; 360 1.1 christos break; 361 1.1 christos 362 1.1 christos case BPF_ALU|BPF_DIV|BPF_K: 363 1.1 christos op = "div"; 364 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 365 1.4 christos operand = operand_buf; 366 1.1 christos break; 367 1.1 christos 368 1.2 christos case BPF_ALU|BPF_MOD|BPF_K: 369 1.2 christos op = "mod"; 370 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 371 1.4 christos operand = operand_buf; 372 1.2 christos break; 373 1.2 christos 374 1.1 christos case BPF_ALU|BPF_AND|BPF_K: 375 1.1 christos op = "and"; 376 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 377 1.4 christos operand = operand_buf; 378 1.1 christos break; 379 1.1 christos 380 1.1 christos case BPF_ALU|BPF_OR|BPF_K: 381 1.1 christos op = "or"; 382 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 383 1.4 christos operand = operand_buf; 384 1.1 christos break; 385 1.1 christos 386 1.2 christos case BPF_ALU|BPF_XOR|BPF_K: 387 1.2 christos op = "xor"; 388 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); 389 1.4 christos operand = operand_buf; 390 1.2 christos break; 391 1.2 christos 392 1.1 christos case BPF_ALU|BPF_LSH|BPF_K: 393 1.1 christos op = "lsh"; 394 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 395 1.4 christos operand = operand_buf; 396 1.1 christos break; 397 1.1 christos 398 1.1 christos case BPF_ALU|BPF_RSH|BPF_K: 399 1.1 christos op = "rsh"; 400 1.6 christos (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); 401 1.4 christos operand = operand_buf; 402 1.1 christos break; 403 1.1 christos 404 1.1 christos case BPF_ALU|BPF_NEG: 405 1.1 christos op = "neg"; 406 1.4 christos operand = ""; 407 1.1 christos break; 408 1.1 christos 409 1.1 christos case BPF_MISC|BPF_TAX: 410 1.1 christos op = "tax"; 411 1.4 christos operand = ""; 412 1.1 christos break; 413 1.1 christos 414 1.1 christos case BPF_MISC|BPF_TXA: 415 1.1 christos op = "txa"; 416 1.4 christos operand = ""; 417 1.1 christos break; 418 1.1 christos } 419 1.2 christos if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) { 420 1.6 christos (void)snprintf(image, sizeof image, 421 1.2 christos "(%03d) %-8s %-16s jt %d\tjf %d", 422 1.2 christos n, op, operand, n + 1 + p->jt, n + 1 + p->jf); 423 1.2 christos } else { 424 1.6 christos (void)snprintf(image, sizeof image, 425 1.2 christos "(%03d) %-8s %s", 426 1.2 christos n, op, operand); 427 1.2 christos } 428 1.1 christos return image; 429 1.1 christos } 430