#include "da.h" #include "nm.h" #include "op.h" #include "rd.h" #include "str.h" #include #include #include static void raw_bytes(tobi_sb *sb, const tobi_rd *rd, size_t start, size_t end) { tobi_sb_add(sb, " raw="); size_t n = end > start ? end - start : 0; size_t max = n > 8 ? 8 : n; for (size_t i = 0; i < max && start + i < rd->len; i++) { tobi_sb_printf(sb, "%02x", rd->data[start + i]); if (i + 1 < max) { tobi_sb_ch(sb, ' '); } } if (n > max) { tobi_sb_add(sb, " ..."); } } static void skip_simple_arg(tobi_rd *rd) { uint8_t op = 0; if (!tobi_rd_u8(rd, &op)) { return; } if (op == 0x0a) { (void)tobi_rd_skip(rd, 1); } else if (op == 0x0b) { (void)tobi_rd_skip(rd, 2); } else if (op == 0x0c) { (void)tobi_rd_skip(rd, 4); } else if (op == 0x0e) { (void)tobi_rd_skip(rd, 8); } else if (op == 0x0d) { while (tobi_rd_left(rd) > 0) { uint8_t c = 0; (void)tobi_rd_u8(rd, &c); if (c == 0) { break; } } } } static void walk(tobi_sb *sb, tobi_rd *rd, unsigned depth) { if (depth > 64) { tobi_sb_printf(sb, "0x%04zx: \n", tobi_rd_off(rd)); rd->pos = rd->len; return; } while (tobi_rd_left(rd) > 0) { size_t start = rd->pos; size_t off = tobi_rd_off(rd); uint8_t op = 0; if (!tobi_rd_u8(rd, &op)) { break; } uint16_t code = op; const tobi_op *meta = NULL; if (op == 0x5b) { uint8_t ext = 0; if (!tobi_rd_u8(rd, &ext)) { tobi_sb_printf(sb, "0x%04zx: ExtOpPrefix truncated raw=5b\n", off); return; } code = (uint16_t)(0x5b00u | ext); meta = tobi_op_find_ext(ext); } else { meta = tobi_op_find(op); } if (!meta && (op == '\\' || op == '^' || op == 0x2e || op == 0x2f || tobi_nm_is_lead(op))) { rd->pos = start; char *nm = NULL; if (tobi_nm_namestring(rd, &nm)) { tobi_sb_printf(sb, "0x%04zx: NameString name=%s", off, nm); raw_bytes(sb, rd, start, rd->pos); tobi_sb_ch(sb, '\n'); free(nm); continue; } rd->pos = start + 1; } const char *name = meta ? meta->name : "UnknownOp"; const char *operands = tobi_op_operands(code); int decoded_pseudo = 0; char extra[128]; extra[0] = '\0'; if (op == 0x0a) { uint8_t v = 0; if (tobi_rd_u8(rd, &v)) { (void)snprintf(extra, sizeof(extra), " value=0x%x", (unsigned)v); } } else if (op == 0x0b) { uint16_t v = 0; if (tobi_rd_u16(rd, &v)) { (void)snprintf(extra, sizeof(extra), " value=0x%x", (unsigned)v); } } else if (op == 0x0c) { uint32_t v = 0; if (tobi_rd_u32(rd, &v)) { (void)snprintf(extra, sizeof(extra), " value=0x%x", (unsigned)v); } } else if (op == 0x0e) { uint64_t v = 0; if (tobi_rd_u64(rd, &v)) { (void)snprintf(extra, sizeof(extra), " value=0x%llx", (unsigned long long)v); } } else if (op == 0x0d) { size_t s = rd->pos; while (rd->pos < rd->len && rd->data[rd->pos] != 0) { rd->pos++; } size_t n = rd->pos - s; if (rd->pos < rd->len) { rd->pos++; } (void)snprintf(extra, sizeof(extra), " strlen=%zu", n); } else if (op >= 0x60 && op <= 0x67) { (void)snprintf(extra, sizeof(extra), " name=Local%u", (unsigned)(op - 0x60)); name = "LocalObj"; decoded_pseudo = 1; } else if (op >= 0x68 && op <= 0x6e) { (void)snprintf(extra, sizeof(extra), " name=Arg%u", (unsigned)(op - 0x68)); name = "ArgObj"; decoded_pseudo = 1; } else if (op == 0x08 || op == 0x06 || code == 0x5b80 || code == 0x5b01 || code == 0x5b02) { char *nm = NULL; if (tobi_nm_namestring(rd, &nm)) { (void)snprintf(extra, sizeof(extra), " name=%s", nm); free(nm); } if (op == 0x06) { char *dst = NULL; if (tobi_nm_namestring(rd, &dst)) { size_t used = strlen(extra); (void)snprintf(extra + used, sizeof(extra) - used, " target=%s", dst); free(dst); } } } tobi_sb_printf(sb, "0x%04zx: %s", off, name); if (operands && operands[0]) { tobi_sb_printf(sb, " operands=%s", operands); } if (meta && meta->has_pkg_len) { size_t pkg_start = rd->pos; size_t pkg_len = 0; size_t enc = 0; if (!tobi_rd_pkg_len(rd, &pkg_len, &enc)) { raw_bytes(sb, rd, start, rd->pos); tobi_sb_add(sb, " malformed-pkglen\n"); return; } size_t body_start = rd->pos; size_t end = pkg_start + pkg_len; if (end > rd->len || end < body_start) { end = rd->len; tobi_sb_add(sb, " truncated"); } tobi_sb_printf(sb, " pkglen=%zu", pkg_len); if (code == 0x10 || code == 0x14 || code == 0x5b82 || code == 0x5b83 || code == 0x5b81) { tobi_rd copy = *rd; char *nm = NULL; if (tobi_nm_namestring(©, &nm)) { tobi_sb_add(sb, " name="); tobi_sb_add(sb, nm); free(nm); } } raw_bytes(sb, rd, start, body_start); tobi_sb_ch(sb, '\n'); tobi_rd sub; tobi_rd_init(&sub, rd->data + body_start, end - body_start, rd->base + body_start); if (code == 0x11) { skip_simple_arg(&sub); tobi_sb_printf(sb, "0x%04zx: BufferData len=%zu ", tobi_rd_off(&sub), tobi_rd_left(&sub)); raw_bytes(sb, &sub, sub.pos, sub.len); tobi_sb_ch(sb, '\n'); } else if (code == 0x14) { char *nm = NULL; if (tobi_nm_namestring(&sub, &nm)) { free(nm); (void)tobi_rd_skip(&sub, 1); } } else if (code == 0x10 || code == 0x5b82) { char *nm = NULL; if (tobi_nm_namestring(&sub, &nm)) { free(nm); } } else if (code == 0x5b81) { char *nm = NULL; if (tobi_nm_namestring(&sub, &nm)) { free(nm); (void)tobi_rd_skip(&sub, 1); } } else if (code == 0xa0 || code == 0xa2) { (void)tobi_rd_skip(&sub, 1); } if (code != 0x11) { walk(sb, &sub, depth + 1); } rd->pos = end; } else { tobi_sb_add(sb, extra); raw_bytes(sb, rd, start, rd->pos); if (!meta && !decoded_pseudo) { tobi_sb_printf(sb, " opcode=0x%x", (unsigned)code); } tobi_sb_ch(sb, '\n'); } } } char *tobi_da_emit(const uint8_t *data, size_t len, const tobi_input_meta *meta) { tobi_sb sb; tobi_sb_init(&sb); size_t off = meta ? meta->aml_off : 0; size_t alen = meta ? meta->aml_len : len; if (off > len || alen > len - off) { off = 0; alen = len; } tobi_rd rd; tobi_rd_init(&rd, data + off, alen, off); walk(&sb, &rd, 0); return tobi_sb_take(&sb); }