blob: e201b495ef3be0776976e374c061a85c0bfaa280 [file] [log] [blame]
Lorenzo Colitti983eb512019-09-26 22:14:16 +09001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes888b7232024-10-28 14:31:20 +000017#include <stdbool.h>
Lorenzo Colitti983eb512019-09-26 22:14:16 +090018#include <stdint.h>
19#include <stdio.h>
Yuyang Huang32122582024-01-28 06:52:53 +090020#include <stdarg.h>
Lorenzo Colitti983eb512019-09-26 22:14:16 +090021
Maciej Żenczykowski63da3b22025-02-17 13:56:05 -080022#include "next/apf_defs.h"
23#include "next/apf.h"
Yuyang Huang32122582024-01-28 06:52:53 +090024#include "disassembler.h"
Lorenzo Colitti983eb512019-09-26 22:14:16 +090025
26// If "c" is of a signed type, generate a compile warning that gets promoted to an error.
27// This makes bounds checking simpler because ">= 0" can be avoided. Otherwise adding
28// superfluous ">= 0" with unsigned expressions generates compile warnings.
29#define ENFORCE_UNSIGNED(c) ((c)==(uint32_t)(c))
30
Yuyang Huang16a9e422024-01-29 09:35:06 +090031char print_buf[1024];
Yuyang Huang32122582024-01-28 06:52:53 +090032char* buf_ptr;
33int buf_remain;
Yuyang Huange7956d42024-04-08 21:06:55 +090034bool v6_mode = false;
Yuyang Huang32122582024-01-28 06:52:53 +090035
36__attribute__ ((format (printf, 1, 2) ))
37static void bprintf(const char* format, ...) {
38 va_list args;
39 va_start(args, format);
40 int ret = vsnprintf(buf_ptr, buf_remain, format, args);
41 va_end(args);
42 if (ret < 0) return;
43 if (ret >= buf_remain) ret = buf_remain;
44 buf_ptr += ret;
45 buf_remain -= ret;
46}
47
48static void print_opcode(const char* opcode) {
49 bprintf("%-12s", opcode);
Lorenzo Colitti983eb512019-09-26 22:14:16 +090050}
51
52// Mapping from opcode number to opcode name.
53static const char* opcode_names [] = {
54 [LDB_OPCODE] = "ldb",
55 [LDH_OPCODE] = "ldh",
56 [LDW_OPCODE] = "ldw",
57 [LDBX_OPCODE] = "ldbx",
58 [LDHX_OPCODE] = "ldhx",
59 [LDWX_OPCODE] = "ldwx",
60 [ADD_OPCODE] = "add",
61 [MUL_OPCODE] = "mul",
62 [DIV_OPCODE] = "div",
63 [AND_OPCODE] = "and",
64 [OR_OPCODE] = "or",
65 [SH_OPCODE] = "sh",
66 [LI_OPCODE] = "li",
67 [JMP_OPCODE] = "jmp",
68 [JEQ_OPCODE] = "jeq",
69 [JNE_OPCODE] = "jne",
70 [JGT_OPCODE] = "jgt",
71 [JLT_OPCODE] = "jlt",
72 [JSET_OPCODE] = "jset",
Yuyang Huang06857372024-02-06 05:19:07 +090073 [JBSMATCH_OPCODE] = NULL,
Lorenzo Colitti983eb512019-09-26 22:14:16 +090074 [LDDW_OPCODE] = "lddw",
75 [STDW_OPCODE] = "stdw",
Yuyang Huang5c6ce182023-10-24 18:49:57 +090076 [WRITE_OPCODE] = "write",
Maciej Żenczykowskie0ffcb92024-05-11 08:34:27 -070077 [JNSET_OPCODE] = "jnset",
Lorenzo Colitti983eb512019-09-26 22:14:16 +090078};
79
Yuyang Huang32122582024-01-28 06:52:53 +090080static void print_jump_target(uint32_t target, uint32_t program_len) {
Lorenzo Colitti983eb512019-09-26 22:14:16 +090081 if (target == program_len) {
Yuyang Huang32122582024-01-28 06:52:53 +090082 bprintf("PASS");
Lorenzo Colitti983eb512019-09-26 22:14:16 +090083 } else if (target == program_len + 1) {
Yuyang Huang32122582024-01-28 06:52:53 +090084 bprintf("DROP");
Lorenzo Colitti983eb512019-09-26 22:14:16 +090085 } else {
Yuyang Huang32122582024-01-28 06:52:53 +090086 bprintf("%u", target);
Lorenzo Colitti983eb512019-09-26 22:14:16 +090087 }
88}
89
Yuyang Huang591860d2024-02-06 06:58:30 +090090const char* apf_disassemble(const uint8_t* program, uint32_t program_len, uint32_t* const ptr2pc) {
Yuyang Huang32122582024-01-28 06:52:53 +090091 buf_ptr = print_buf;
92 buf_remain = sizeof(print_buf);
Yuyang Huang591860d2024-02-06 06:58:30 +090093 if (*ptr2pc > program_len + 1) {
94 bprintf("pc is overflow: pc %d, program_len: %d", *ptr2pc, program_len);
Yuyang Huang32122582024-01-28 06:52:53 +090095 return print_buf;
Lorenzo Colitti983eb512019-09-26 22:14:16 +090096 }
97
Yuyang Huang591860d2024-02-06 06:58:30 +090098 bprintf("%8u: ", *ptr2pc);
Yuyang Huang32122582024-01-28 06:52:53 +090099
Yuyang Huang591860d2024-02-06 06:58:30 +0900100 if (*ptr2pc == program_len) {
Yuyang Huang32122582024-01-28 06:52:53 +0900101 bprintf("PASS");
Yuyang Huang591860d2024-02-06 06:58:30 +0900102 ++(*ptr2pc);
Yuyang Huang32122582024-01-28 06:52:53 +0900103 return print_buf;
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900104 }
105
Yuyang Huang591860d2024-02-06 06:58:30 +0900106 if (*ptr2pc == program_len + 1) {
Yuyang Huang32122582024-01-28 06:52:53 +0900107 bprintf("DROP");
Yuyang Huang591860d2024-02-06 06:58:30 +0900108 ++(*ptr2pc);
Yuyang Huang32122582024-01-28 06:52:53 +0900109 return print_buf;
110 }
111
Yuyang Huang591860d2024-02-06 06:58:30 +0900112 const uint8_t bytecode = program[(*ptr2pc)++];
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900113 const uint32_t opcode = EXTRACT_OPCODE(bytecode);
Yuyang Huang32122582024-01-28 06:52:53 +0900114
115#define PRINT_OPCODE() print_opcode(opcode_names[opcode])
Yuyang Huang186a80f2024-02-06 10:24:08 +0900116#define DECODE_IMM(length) ({ \
117 uint32_t value = 0; \
118 for (uint32_t i = 0; i < (length) && *ptr2pc < program_len; i++) \
119 value = (value << 8) | program[(*ptr2pc)++]; \
120 value;})
Yuyang Huangaea452e2023-11-01 18:14:45 +0900121
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900122 const uint32_t reg_num = EXTRACT_REGISTER(bytecode);
123 // All instructions have immediate fields, so load them now.
124 const uint32_t len_field = EXTRACT_IMM_LENGTH(bytecode);
125 uint32_t imm = 0;
126 int32_t signed_imm = 0;
127 if (len_field != 0) {
128 const uint32_t imm_len = 1 << (len_field - 1);
Yuyang Huang186a80f2024-02-06 10:24:08 +0900129 imm = DECODE_IMM(imm_len);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900130 // Sign extend imm into signed_imm.
131 signed_imm = imm << ((4 - imm_len) * 8);
132 signed_imm >>= (4 - imm_len) * 8;
133 }
134 switch (opcode) {
Yuyang Huang2b7763f2024-01-29 06:34:01 +0900135 case PASSDROP_OPCODE:
136 if (reg_num == 0) {
137 print_opcode("pass");
138 } else {
139 print_opcode("drop");
140 }
Yuyang Huangddd3b862024-01-29 11:46:16 +0900141 if (imm > 0) {
Yuyang Huang19e74c32024-04-09 01:22:06 +0900142 bprintf("counter=%d", imm);
Yuyang Huang2b7763f2024-01-29 06:34:01 +0900143 }
144 break;
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900145 case LDB_OPCODE:
146 case LDH_OPCODE:
147 case LDW_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900148 PRINT_OPCODE();
149 bprintf("r%d, [%u]", reg_num, imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900150 break;
151 case LDBX_OPCODE:
152 case LDHX_OPCODE:
153 case LDWX_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900154 PRINT_OPCODE();
Maciej Żenczykowski8dee6332023-09-05 02:28:26 +0000155 if (imm) {
Yuyang Huang32122582024-01-28 06:52:53 +0900156 bprintf("r%d, [r1+%u]", reg_num, imm);
Maciej Żenczykowski8dee6332023-09-05 02:28:26 +0000157 } else {
Yuyang Huang32122582024-01-28 06:52:53 +0900158 bprintf("r%d, [r1]", reg_num);
Maciej Żenczykowski8dee6332023-09-05 02:28:26 +0000159 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900160 break;
161 case JMP_OPCODE:
Yuyang Huang16a9e422024-01-29 09:35:06 +0900162 if (reg_num == 0) {
163 PRINT_OPCODE();
Yuyang Huang591860d2024-02-06 06:58:30 +0900164 print_jump_target(*ptr2pc + imm, program_len);
Yuyang Huang16a9e422024-01-29 09:35:06 +0900165 } else {
Yuyang Huange7956d42024-04-08 21:06:55 +0900166 v6_mode = true;
Yuyang Huang16a9e422024-01-29 09:35:06 +0900167 print_opcode("data");
Yuyang Huang61e63d22024-02-04 07:19:33 +0900168 bprintf("%d, ", imm);
Yuyang Huang16a9e422024-01-29 09:35:06 +0900169 uint32_t len = imm;
Yuyang Huang591860d2024-02-06 06:58:30 +0900170 while (len--) bprintf("%02x", program[(*ptr2pc)++]);
Yuyang Huang16a9e422024-01-29 09:35:06 +0900171 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900172 break;
173 case JEQ_OPCODE:
174 case JNE_OPCODE:
175 case JGT_OPCODE:
176 case JLT_OPCODE:
Maciej Żenczykowskie0ffcb92024-05-11 08:34:27 -0700177 case JSET_OPCODE:
178 case JNSET_OPCODE: {
Yuyang Huang32122582024-01-28 06:52:53 +0900179 PRINT_OPCODE();
180 bprintf("r0, ");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900181 // Load second immediate field.
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900182 if (reg_num == 1) {
Yuyang Huang32122582024-01-28 06:52:53 +0900183 bprintf("r1, ");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900184 } else if (len_field == 0) {
Yuyang Huang32122582024-01-28 06:52:53 +0900185 bprintf("0, ");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900186 } else {
Yuyang Huang186a80f2024-02-06 10:24:08 +0900187 uint32_t cmp_imm = DECODE_IMM(1 << (len_field - 1));
Yuyang Huang32122582024-01-28 06:52:53 +0900188 bprintf("0x%x, ", cmp_imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900189 }
Yuyang Huang591860d2024-02-06 06:58:30 +0900190 print_jump_target(*ptr2pc + imm, program_len);
Yuyang Huang79fa1212024-02-04 07:42:51 +0900191 break;
192 }
Yuyang Huang06857372024-02-06 05:19:07 +0900193 case JBSMATCH_OPCODE: {
Yuyang Huang79fa1212024-02-04 07:42:51 +0900194 if (reg_num == 0) {
Yuyang Huang06857372024-02-06 05:19:07 +0900195 print_opcode("jbsne");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900196 } else {
Yuyang Huang06857372024-02-06 05:19:07 +0900197 print_opcode("jbseq");
Yuyang Huang79fa1212024-02-04 07:42:51 +0900198 }
199 bprintf("r0, ");
Yuyang Huang6df7e7b2024-04-26 17:58:20 +0900200 const uint32_t cmp_imm = DECODE_IMM(1 << (len_field - 1));
201 const uint32_t cnt = (cmp_imm >> 11) + 1; // 1+, up to 32 fits in u16
202 const uint32_t len = cmp_imm & 2047; // 0..2047
203 bprintf("0x%x, ", len);
204 print_jump_target(*ptr2pc + imm + cnt * len, program_len);
Yuyang Huang79fa1212024-02-04 07:42:51 +0900205 bprintf(", ");
Yuyang Huang6df7e7b2024-04-26 17:58:20 +0900206 if (cnt > 1) {
207 bprintf("{ ");
208 }
209 for (uint32_t i = 0; i < cnt; ++i) {
210 for (uint32_t j = 0; j < len; ++j) {
211 uint8_t byte = program[(*ptr2pc)++];
212 bprintf("%02x", byte);
213 }
214 if (i != cnt - 1) {
215 bprintf(", ");
216 }
217 }
218 if (cnt > 1) {
219 bprintf(" }");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900220 }
221 break;
222 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900223 case SH_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900224 PRINT_OPCODE();
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900225 if (reg_num) {
Yuyang Huang32122582024-01-28 06:52:53 +0900226 bprintf("r0, r1");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900227 } else {
Yuyang Huang32122582024-01-28 06:52:53 +0900228 bprintf("r0, %d", signed_imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900229 }
230 break;
Maciej Żenczykowskibea1b992023-09-03 16:09:04 +0000231 case ADD_OPCODE:
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900232 case MUL_OPCODE:
233 case DIV_OPCODE:
234 case AND_OPCODE:
235 case OR_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900236 PRINT_OPCODE();
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900237 if (reg_num) {
Yuyang Huang32122582024-01-28 06:52:53 +0900238 bprintf("r0, r1");
Maciej Żenczykowskib64968d2023-09-05 23:08:11 +0000239 } else if (!imm && opcode == DIV_OPCODE) {
Yuyang Huang32122582024-01-28 06:52:53 +0900240 bprintf("pass (div 0)");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900241 } else {
Yuyang Huang32122582024-01-28 06:52:53 +0900242 bprintf("r0, %u", imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900243 }
244 break;
245 case LI_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900246 PRINT_OPCODE();
247 bprintf("r%d, %d", reg_num, signed_imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900248 break;
249 case EXT_OPCODE:
250 if (
251// If LDM_EXT_OPCODE is 0 and imm is compared with it, a compiler error will result,
252// instead just enforce that imm is unsigned (so it's always greater or equal to 0).
253#if LDM_EXT_OPCODE == 0
254 ENFORCE_UNSIGNED(imm) &&
255#else
256 imm >= LDM_EXT_OPCODE &&
257#endif
258 imm < (LDM_EXT_OPCODE + MEMORY_ITEMS)) {
Yuyang Huang32122582024-01-28 06:52:53 +0900259 print_opcode("ldm");
260 bprintf("r%d, m[%u]", reg_num, imm - LDM_EXT_OPCODE);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900261 } else if (imm >= STM_EXT_OPCODE && imm < (STM_EXT_OPCODE + MEMORY_ITEMS)) {
Yuyang Huang32122582024-01-28 06:52:53 +0900262 print_opcode("stm");
263 bprintf("r%d, m[%u]", reg_num, imm - STM_EXT_OPCODE);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900264 } else switch (imm) {
265 case NOT_EXT_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900266 print_opcode("not");
267 bprintf("r%d", reg_num);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900268 break;
269 case NEG_EXT_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900270 print_opcode("neg");
271 bprintf("r%d", reg_num);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900272 break;
273 case SWAP_EXT_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900274 print_opcode("swap");
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900275 break;
276 case MOV_EXT_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900277 print_opcode("mov");
278 bprintf("r%d, r%d", reg_num, reg_num ^ 1);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900279 break;
Yuyang Huanga3416612024-01-26 08:18:30 +0900280 case ALLOCATE_EXT_OPCODE:
Yuyang Huang037d3df2024-01-29 06:52:24 +0900281 print_opcode("allocate");
282 if (reg_num == 0) {
283 bprintf("r%d", reg_num);
284 } else {
Yuyang Huang186a80f2024-02-06 10:24:08 +0900285 uint32_t alloc_len = DECODE_IMM(2);
Yuyang Huang037d3df2024-01-29 06:52:24 +0900286 bprintf("%d", alloc_len);
287 }
Yuyang Huang9aece5c2023-10-16 17:45:35 +0900288 break;
Maciej Żenczykowskid02a6912024-02-09 22:37:40 -0800289 case TRANSMIT_EXT_OPCODE:
290 print_opcode(reg_num ? "transmitudp" : "transmit");
291 u8 ip_ofs = DECODE_IMM(1);
292 u8 csum_ofs = DECODE_IMM(1);
293 if (csum_ofs < 255) {
294 u8 csum_start = DECODE_IMM(1);
295 u16 partial_csum = DECODE_IMM(2);
296 bprintf("ip_ofs=%d, csum_ofs=%d, csum_start=%d, partial_csum=0x%04x",
297 ip_ofs, csum_ofs, csum_start, partial_csum);
298 } else {
299 bprintf("ip_ofs=%d", ip_ofs);
Yuyang Huanga96ba552024-01-29 07:15:08 +0900300 }
Yuyang Huang9aece5c2023-10-16 17:45:35 +0900301 break;
Yuyang Huange2507e32024-01-30 03:36:31 +0900302 case EWRITE1_EXT_OPCODE: print_opcode("ewrite1"); bprintf("r%d", reg_num); break;
303 case EWRITE2_EXT_OPCODE: print_opcode("ewrite2"); bprintf("r%d", reg_num); break;
304 case EWRITE4_EXT_OPCODE: print_opcode("ewrite4"); bprintf("r%d", reg_num); break;
Yuyang Huangf6ed43c2024-02-03 15:34:20 +0900305 case EPKTDATACOPYIMM_EXT_OPCODE:
306 case EPKTDATACOPYR1_EXT_OPCODE: {
307 if (reg_num == 0) {
308 print_opcode("epktcopy");
Yuyang Huangaea452e2023-11-01 18:14:45 +0900309 } else {
Yuyang Huangf6ed43c2024-02-03 15:34:20 +0900310 print_opcode("edatacopy");
Yuyang Huangaea452e2023-11-01 18:14:45 +0900311 }
Yuyang Huangf6ed43c2024-02-03 15:34:20 +0900312 if (imm == EPKTDATACOPYIMM_EXT_OPCODE) {
Yuyang Huang186a80f2024-02-06 10:24:08 +0900313 uint32_t len = DECODE_IMM(1);
Yuyang Huang1a149582024-02-06 12:40:53 +0900314 bprintf(" src=r0, len=%d", len);
Yuyang Huangf6ed43c2024-02-03 15:34:20 +0900315 } else {
Yuyang Huang1a149582024-02-06 12:40:53 +0900316 bprintf(" src=r0, len=r1");
Yuyang Huangf6ed43c2024-02-03 15:34:20 +0900317 }
Yuyang Huangaea452e2023-11-01 18:14:45 +0900318
Yuyang Huangaea452e2023-11-01 18:14:45 +0900319 break;
320 }
Yuyang Huang8098da12024-02-14 22:00:51 +0900321 case JDNSQMATCH_EXT_OPCODE: // 43
322 case JDNSAMATCH_EXT_OPCODE: // 44
323 case JDNSQMATCHSAFE_EXT_OPCODE: // 45
324 case JDNSAMATCHSAFE_EXT_OPCODE: { // 46
Yuyang Huang869a3742024-02-07 04:01:29 +0900325 uint32_t offs = DECODE_IMM(1 << (len_field - 1));
Yuyang Huang8098da12024-02-14 22:00:51 +0900326 int qtype = -1;
327 switch(imm) {
328 case JDNSQMATCH_EXT_OPCODE:
329 print_opcode(reg_num ? "jdnsqeq" : "jdnsqne");
330 qtype = DECODE_IMM(1);
331 break;
332 case JDNSQMATCHSAFE_EXT_OPCODE:
333 print_opcode(reg_num ? "jdnsqeqsafe" : "jdnsqnesafe");
334 qtype = DECODE_IMM(1);
335 break;
336 case JDNSAMATCH_EXT_OPCODE:
337 print_opcode(reg_num ? "jdnsaeq" : "jdnsane"); break;
338 case JDNSAMATCHSAFE_EXT_OPCODE:
339 print_opcode(reg_num ? "jdnsaeqsafe" : "jdnsanesafe"); break;
340 default:
341 bprintf("unknown_ext %u", imm); break;
Yuyang Huang7c7d8fe2024-02-04 09:38:32 +0900342 }
343 bprintf("r0, ");
Yuyang Huang591860d2024-02-06 06:58:30 +0900344 uint32_t end = *ptr2pc;
Yuyang Huang7c7d8fe2024-02-04 09:38:32 +0900345 while (end + 1 < program_len && !(program[end] == 0 && program[end + 1] == 0)) {
346 end++;
347 }
348 end += 2;
349 print_jump_target(end + offs, program_len);
Yuyang Huang869a3742024-02-07 04:01:29 +0900350 bprintf(", ");
Yuyang Huang8098da12024-02-14 22:00:51 +0900351 if (imm == JDNSQMATCH_EXT_OPCODE || imm == JDNSQMATCHSAFE_EXT_OPCODE) {
Yuyang Huang869a3742024-02-07 04:01:29 +0900352 bprintf("%d, ", qtype);
353 }
Yuyang Huang591860d2024-02-06 06:58:30 +0900354 while (*ptr2pc < end) {
355 uint8_t byte = program[(*ptr2pc)++];
Yuyang Huangd486dd02025-02-18 15:38:14 +0900356 // value == 0xff is a wildcard that consumes the whole label.
Yuyang Huang869a3742024-02-07 04:01:29 +0900357 // values < 0x40 could be lengths, but - and 0..9 are in practice usually
358 // too long to be lengths so print them as characters. All other chars < 0x40
359 // are not valid in dns character.
Yuyang Huangd486dd02025-02-18 15:38:14 +0900360 if (byte == 0xff) {
361 bprintf("(*)");
362 } else if (byte == '-' || (byte >= '0' && byte <= '9') || byte >= 0x40) {
Yuyang Huang869a3742024-02-07 04:01:29 +0900363 bprintf("%c", byte);
364 } else {
365 bprintf("(%d)", byte);
366 }
Yuyang Huang7c7d8fe2024-02-04 09:38:32 +0900367 }
368 break;
369 }
Yuyang Huangeda43352024-04-21 19:38:56 +0900370 case JONEOF_EXT_OPCODE: {
371 const uint32_t imm_len = 1 << (len_field - 1);
372 uint32_t jump_offs = DECODE_IMM(imm_len);
373 uint8_t imm3 = DECODE_IMM(1);
374 bool jmp = imm3 & 1;
375 uint8_t len = ((imm3 >> 1) & 3) + 1;
376 uint8_t cnt = (imm3 >> 3) + 2;
377 if (jmp) {
378 print_opcode("jnoneof");
379 } else {
380 print_opcode("joneof");
381 }
382 bprintf("r%d, ", reg_num);
383 print_jump_target(*ptr2pc + jump_offs + cnt * len, program_len);
384 bprintf(", { ");
385 while (cnt--) {
386 uint32_t v = DECODE_IMM(len);
387 if (cnt) {
388 bprintf("%d, ", v);
389 } else {
390 bprintf("%d ", v);
391 }
392 }
393 bprintf("}");
394 break;
395 }
Yuyang Huange8da73e2024-04-30 18:02:01 +0900396 case EXCEPTIONBUFFER_EXT_OPCODE: {
397 uint32_t buf_size = DECODE_IMM(2);
398 print_opcode("debugbuf");
399 bprintf("size=%d", buf_size);
400 break;
401 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900402 default:
Yuyang Huang32122582024-01-28 06:52:53 +0900403 bprintf("unknown_ext %u", imm);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900404 break;
405 }
406 break;
407 case LDDW_OPCODE:
408 case STDW_OPCODE:
Yuyang Huang32122582024-01-28 06:52:53 +0900409 PRINT_OPCODE();
Yuyang Huange7956d42024-04-08 21:06:55 +0900410 if (v6_mode) {
411 if (opcode == LDDW_OPCODE) {
Maciej Żenczykowskia7ad6eb2024-04-08 22:44:24 -0700412 bprintf("r%u, counter=%d", reg_num, imm);
Yuyang Huange7956d42024-04-08 21:06:55 +0900413 } else {
Maciej Żenczykowskia7ad6eb2024-04-08 22:44:24 -0700414 bprintf("counter=%d, r%u", imm, reg_num);
Yuyang Huange7956d42024-04-08 21:06:55 +0900415 }
Maciej Żenczykowski8dee6332023-09-05 02:28:26 +0000416 } else {
Yuyang Huange7956d42024-04-08 21:06:55 +0900417 if (signed_imm > 0) {
418 bprintf("r%u, [r%u+%d]", reg_num, reg_num ^ 1, signed_imm);
419 } else if (signed_imm < 0) {
420 bprintf("r%u, [r%u-%d]", reg_num, reg_num ^ 1, -signed_imm);
421 } else {
422 bprintf("r%u, [r%u]", reg_num, reg_num ^ 1);
423 }
Maciej Żenczykowski8dee6332023-09-05 02:28:26 +0000424 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900425 break;
Yuyang Huang5c6ce182023-10-24 18:49:57 +0900426 case WRITE_OPCODE: {
Yuyang Huang32122582024-01-28 06:52:53 +0900427 PRINT_OPCODE();
Yuyang Huang5c6ce182023-10-24 18:49:57 +0900428 uint32_t write_len = 1 << (len_field - 1);
429 if (write_len > 0) {
Yuyang Huang32122582024-01-28 06:52:53 +0900430 bprintf("0x");
Yuyang Huang5c6ce182023-10-24 18:49:57 +0900431 }
432 for (uint32_t i = 0; i < write_len; ++i) {
433 uint8_t byte =
434 (uint8_t) ((imm >> (write_len - 1 - i) * 8) & 0xff);
Yuyang Huang32122582024-01-28 06:52:53 +0900435 bprintf("%02x", byte);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900436
Yuyang Huang5c6ce182023-10-24 18:49:57 +0900437 }
438 break;
439 }
Yuyang Huanga3416612024-01-26 08:18:30 +0900440 case PKTDATACOPY_OPCODE: {
Yuyang Huangaea452e2023-11-01 18:14:45 +0900441 if (reg_num == 0) {
Yuyang Huangfb0e1672024-02-07 06:28:46 +0900442 print_opcode("pktcopy");
Yuyang Huangaea452e2023-11-01 18:14:45 +0900443 } else {
Yuyang Huangfb0e1672024-02-07 06:28:46 +0900444 print_opcode("datacopy");
Yuyang Huangaea452e2023-11-01 18:14:45 +0900445 }
Yuyang Huang7dd27fa2024-01-30 04:05:18 +0900446 uint32_t src_offs = imm;
Yuyang Huang186a80f2024-02-06 10:24:08 +0900447 uint32_t copy_len = DECODE_IMM(1);
Yuyang Huang1a149582024-02-06 12:40:53 +0900448 bprintf("src=%d, len=%d", src_offs, copy_len);
Yuyang Huangaea452e2023-11-01 18:14:45 +0900449 break;
450 }
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900451 // Unknown opcode
452 default:
Yuyang Huang32122582024-01-28 06:52:53 +0900453 bprintf("unknown %u", opcode);
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900454 break;
455 }
Yuyang Huang32122582024-01-28 06:52:53 +0900456 return print_buf;
Lorenzo Colitti983eb512019-09-26 22:14:16 +0900457}