ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3 from 23384/dev

Add semantic AML validation plus typed resource and field metadata IR

+343 -9
+9 -4
src/dc.c
··· 266 266 break; 267 267 case TOBI_IR_FIELD: 268 268 indent(sb, ind); 269 - tobi_sb_printf(sb, "%s %s flags=0x%llx {\n", n->str ? n->str : "field", 270 - n->name ? n->name : "<field>", (unsigned long long)n->value); 269 + tobi_sb_printf(sb, "%s %s", n->str ? n->str : "field", n->name ? n->name : "<field>"); 270 + if (n->target) { 271 + tobi_sb_printf(sb, " backing=%s", n->target); 272 + } 273 + tobi_sb_printf(sb, " flags=0x%llx access=%u lock=%u update=%u {\n", 274 + (unsigned long long)n->value, n->access_type, n->lock_rule, n->update_rule); 271 275 for (size_t i = 0; i < n->child_len; i++) { 272 276 indent(sb, ind + 1); 273 277 if (n->child[i]->kind == TOBI_IR_FIELD_ELEM) { 274 - tobi_sb_printf(sb, "%s: %llu", n->child[i]->name ? n->child[i]->name : "<field>", 275 - (unsigned long long)n->child[i]->value); 278 + tobi_sb_printf(sb, "%s @%llu:%llu", n->child[i]->name ? n->child[i]->name : "<field>", 279 + (unsigned long long)n->child[i]->bit_off, 280 + (unsigned long long)n->child[i]->bit_len); 276 281 if (n->child[i]->str) { 277 282 tobi_sb_printf(sb, " /* %s */", n->child[i]->str); 278 283 }
+7
src/ir.c
··· 23 23 free(node->name); 24 24 free(node->path); 25 25 free(node->str); 26 + free(node->target); 26 27 free(node); 27 28 } 28 29 ··· 52 53 node->str = tobi_xstrdup(s ? s : ""); 53 54 } 54 55 56 + void tobi_ir_set_target(tobi_ir *node, const char *s) { 57 + free(node->target); 58 + node->target = tobi_xstrdup(s ? s : ""); 59 + } 60 + 55 61 const char *tobi_ir_kind_name(tobi_ir_kind kind) { 56 62 switch (kind) { 57 63 case TOBI_IR_ROOT: return "root"; ··· 67 73 case TOBI_IR_FIELD_ELEM: return "field_elem"; 68 74 case TOBI_IR_MUTEX: return "mutex"; 69 75 case TOBI_IR_EVENT: return "event"; 76 + case TOBI_IR_RESOURCE: return "resource"; 70 77 case TOBI_IR_BUFFER: return "buffer"; 71 78 case TOBI_IR_PACKAGE: return "package"; 72 79 case TOBI_IR_INTEGER: return "integer";
+9
src/ir.h
··· 18 18 TOBI_IR_FIELD_ELEM, 19 19 TOBI_IR_MUTEX, 20 20 TOBI_IR_EVENT, 21 + TOBI_IR_RESOURCE, 21 22 TOBI_IR_BUFFER, 22 23 TOBI_IR_PACKAGE, 23 24 TOBI_IR_INTEGER, ··· 42 43 char *name; 43 44 char *path; 44 45 char *str; 46 + char *target; 45 47 uint64_t value; 48 + uint64_t bit_off; 49 + uint64_t bit_len; 46 50 uint32_t raw_op; 51 + unsigned access_type; 52 + unsigned lock_rule; 53 + unsigned update_rule; 47 54 unsigned method_args; 48 55 unsigned method_serialized; 49 56 unsigned method_sync; ··· 63 70 void tobi_ir_set_path(tobi_ir *node, const char *s); 64 71 65 72 void tobi_ir_set_str(tobi_ir *node, const char *s); 73 + 74 + void tobi_ir_set_target(tobi_ir *node, const char *s); 66 75 67 76 const char *tobi_ir_kind_name(tobi_ir_kind kind); 68 77
+19 -1
src/js.c
··· 35 35 tobi_sb_add(sb, "\"string\":"); 36 36 tobi_json_string(sb, n->str); 37 37 } 38 + if (n->target) { 39 + comma(sb, &first); 40 + tobi_sb_add(sb, "\"target\":"); 41 + tobi_json_string(sb, n->target); 42 + } 38 43 if (n->kind == TOBI_IR_INTEGER || n->kind == TOBI_IR_PACKAGE || n->kind == TOBI_IR_FIELD || 39 - n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION) { 44 + n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION || 45 + n->kind == TOBI_IR_RESOURCE) { 40 46 comma(sb, &first); 41 47 tobi_sb_printf(sb, "\"value\":%llu", (unsigned long long)n->value); 42 48 } ··· 51 57 tobi_sb_printf(sb, "\"serialized\":%s", n->method_serialized ? "true" : "false"); 52 58 comma(sb, &first); 53 59 tobi_sb_printf(sb, "\"sync\":%u", n->method_sync); 60 + } 61 + if (n->bit_len || n->access_type || n->lock_rule || n->update_rule) { 62 + comma(sb, &first); 63 + tobi_sb_printf(sb, "\"bit_offset\":%llu", (unsigned long long)n->bit_off); 64 + comma(sb, &first); 65 + tobi_sb_printf(sb, "\"bit_length\":%llu", (unsigned long long)n->bit_len); 66 + comma(sb, &first); 67 + tobi_sb_printf(sb, "\"access_type\":%u", n->access_type); 68 + comma(sb, &first); 69 + tobi_sb_printf(sb, "\"lock_rule\":%u", n->lock_rule); 70 + comma(sb, &first); 71 + tobi_sb_printf(sb, "\"update_rule\":%u", n->update_rule); 54 72 } 55 73 comma(sb, &first); 56 74 tobi_sb_add(sb, "\"children\":[");
+236 -4
src/p.c
··· 324 324 return n; 325 325 } 326 326 327 - static void parse_field_list(parser *p, tobi_rd *body, tobi_ir *n) { 327 + static void apply_field_meta(tobi_ir *e, uint64_t bit_off, uint64_t bit_len, uint8_t flags) { 328 + e->bit_off = bit_off; 329 + e->bit_len = bit_len; 330 + e->access_type = flags & 0x0fu; 331 + e->lock_rule = (flags >> 4) & 0x01u; 332 + e->update_rule = (flags >> 5) & 0x03u; 333 + } 334 + 335 + static void parse_field_list(parser *p, tobi_rd *body, tobi_ir *n, uint8_t flags) { 336 + uint64_t bit_pos = 0; 328 337 while (tobi_rd_left(body) > 0) { 329 338 size_t foff = tobi_rd_off(body); 330 339 uint8_t b = 0; ··· 342 351 tobi_ir *e = tobi_ir_new(TOBI_IR_FIELD_ELEM, foff, tobi_rd_off(body) - foff); 343 352 tobi_ir_set_name(e, "<reserved>"); 344 353 e->value = bits; 354 + apply_field_meta(e, bit_pos, bits, flags); 345 355 tobi_ir_add(n, e); 356 + bit_pos += bits; 346 357 continue; 347 358 } 348 359 if (b == 0x01) { ··· 395 406 tobi_ir *e = tobi_ir_new(TOBI_IR_FIELD_ELEM, foff, tobi_rd_off(body) - foff); 396 407 tobi_ir_set_name(e, fname); 397 408 e->value = bits; 409 + apply_field_meta(e, bit_pos, bits, flags); 398 410 ns_declare_name(p, TOBI_NS_FIELD, fname, foff, 0, 0, 0, NULL); 399 411 tobi_ir_add(n, e); 412 + bit_pos += bits; 400 413 free(fname); 401 414 } 402 415 } ··· 419 432 tobi_ir_set_str(n, label); 420 433 if (raw == 0x5b81u) { 421 434 tobi_ir_set_name(n, first); 435 + char *path = tobi_ns_resolve_path(p->ns, p->scope, first); 436 + tobi_ir_set_target(n, path); 437 + free(path); 422 438 } else if (raw == 0x5b86u) { 423 439 char *data = NULL; 424 440 if (!parse_namestring_diag(p, &body, &data)) { ··· 432 448 tobi_sb_add(&nm, ","); 433 449 tobi_sb_add(&nm, data); 434 450 tobi_ir_set_name(n, nm.buf); 451 + tobi_sb target; 452 + tobi_sb_init(&target); 453 + char *idx_path = tobi_ns_resolve_path(p->ns, p->scope, first); 454 + char *data_path = tobi_ns_resolve_path(p->ns, p->scope, data); 455 + tobi_sb_add(&target, "index="); 456 + tobi_sb_add(&target, idx_path); 457 + tobi_sb_add(&target, " data="); 458 + tobi_sb_add(&target, data_path); 459 + tobi_ir_set_target(n, target.buf); 460 + free(idx_path); 461 + free(data_path); 462 + tobi_sb_free(&target); 435 463 tobi_sb_free(&nm); 436 464 free(data); 437 465 } else { ··· 447 475 tobi_sb_add(&nm, ","); 448 476 tobi_sb_add(&nm, bank); 449 477 tobi_ir_set_name(n, nm.buf); 478 + tobi_sb target; 479 + tobi_sb_init(&target); 480 + char *region_path = tobi_ns_resolve_path(p->ns, p->scope, first); 481 + char *bank_path = tobi_ns_resolve_path(p->ns, p->scope, bank); 482 + tobi_sb_add(&target, "region="); 483 + tobi_sb_add(&target, region_path); 484 + tobi_sb_add(&target, " bank="); 485 + tobi_sb_add(&target, bank_path); 486 + tobi_ir_set_target(n, target.buf); 487 + free(region_path); 488 + free(bank_path); 489 + tobi_sb_free(&target); 450 490 tobi_sb_free(&nm); 451 491 free(bank); 452 492 tobi_ir *bank_value = parse_expr(p, &body, depth + 1); ··· 459 499 diag(p, TOBI_DIAG_ERROR, tobi_rd_off(&body), "truncated field flags"); 460 500 } 461 501 n->value = flags; 462 - parse_field_list(p, &body, n); 502 + n->access_type = flags & 0x0fu; 503 + n->lock_rule = (flags >> 4) & 0x01u; 504 + n->update_rule = (flags >> 5) & 0x03u; 505 + parse_field_list(p, &body, n, flags); 463 506 rd->pos = body_start + body_len; 464 507 free(first); 465 508 return n; ··· 904 947 } 905 948 } 906 949 907 - static char *decode_resource_template(const uint8_t *data, size_t len) { 950 + static uint16_t res_u16(const uint8_t *p) { 951 + return (uint16_t)p[0] | ((uint16_t)p[1] << 8); 952 + } 953 + 954 + static uint32_t res_u32(const uint8_t *p) { 955 + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); 956 + } 957 + 958 + static uint64_t res_u64(const uint8_t *p) { 959 + return (uint64_t)res_u32(p) | ((uint64_t)res_u32(p + 4) << 32); 960 + } 961 + 962 + static void add_res_node(tobi_ir *parent, const char *label, size_t off, size_t len, 963 + uint32_t tag, size_t payload_len, const char *detail) { 964 + tobi_ir *r = tobi_ir_new(TOBI_IR_RESOURCE, off, len); 965 + r->raw_op = tag; 966 + r->value = payload_len; 967 + tobi_ir_set_name(r, label); 968 + if (detail) { 969 + tobi_ir_set_str(r, detail); 970 + } 971 + tobi_ir_add(parent, r); 972 + } 973 + 974 + static char *small_res_detail(unsigned name, const uint8_t *p, size_t len) { 975 + tobi_sb sb; 976 + tobi_sb_init(&sb); 977 + if (name == 0x04 && len >= 2) { 978 + tobi_sb_printf(&sb, "irq_mask=0x%x", (unsigned)res_u16(p)); 979 + if (len >= 3) { 980 + tobi_sb_printf(&sb, " flags=0x%x", (unsigned)p[2]); 981 + } 982 + } else if (name == 0x05 && len >= 2) { 983 + tobi_sb_printf(&sb, "dma_mask=0x%x flags=0x%x", (unsigned)p[0], (unsigned)p[1]); 984 + } else if (name == 0x08 && len >= 7) { 985 + tobi_sb_printf(&sb, "decode=0x%x min=0x%x max=0x%x align=%u length=%u", 986 + (unsigned)p[0], (unsigned)res_u16(p + 1), (unsigned)res_u16(p + 3), 987 + (unsigned)p[5], (unsigned)p[6]); 988 + } else if (name == 0x09 && len >= 3) { 989 + tobi_sb_printf(&sb, "base=0x%x length=%u", (unsigned)res_u16(p), (unsigned)p[2]); 990 + } else if (name == 0x0f && len >= 1) { 991 + tobi_sb_printf(&sb, "checksum=0x%x", (unsigned)p[0]); 992 + } else { 993 + tobi_sb_printf(&sb, "bytes=%zu", len); 994 + } 995 + return tobi_sb_take(&sb); 996 + } 997 + 998 + static char *large_res_detail(unsigned name, const uint8_t *p, size_t len) { 999 + tobi_sb sb; 1000 + tobi_sb_init(&sb); 1001 + if (name == 0x02 && len >= 12) { 1002 + tobi_sb_printf(&sb, "space=0x%x width=%u offset=%u access=%u address=0x%x", 1003 + (unsigned)p[0], (unsigned)p[1], (unsigned)p[2], (unsigned)p[3], 1004 + (unsigned)res_u64(p + 4)); 1005 + } else if ((name == 0x05 || name == 0x06) && len >= 9) { 1006 + tobi_sb_printf(&sb, "write=0x%x min=0x%x max=0x%x align=0x%x length=0x%x", 1007 + (unsigned)p[0], (unsigned)res_u32(p + 1), (unsigned)res_u32(p + 5), 1008 + len >= 13 ? (unsigned)res_u32(p + 9) : 0u, 1009 + len >= 17 ? (unsigned)res_u32(p + 13) : 0u); 1010 + } else if (name == 0x07 && len >= 23) { 1011 + tobi_sb_printf(&sb, "rtype=0x%x flags=0x%x gran=0x%x min=0x%x max=0x%x trans=0x%x length=0x%x", 1012 + (unsigned)p[0], (unsigned)p[1], (unsigned)res_u32(p + 3), 1013 + (unsigned)res_u32(p + 7), (unsigned)res_u32(p + 11), 1014 + (unsigned)res_u32(p + 15), (unsigned)res_u32(p + 19)); 1015 + } else if (name == 0x08 && len >= 13) { 1016 + tobi_sb_printf(&sb, "rtype=0x%x flags=0x%x gran=0x%x min=0x%x max=0x%x", 1017 + (unsigned)p[0], (unsigned)p[1], (unsigned)res_u16(p + 3), 1018 + (unsigned)res_u16(p + 5), (unsigned)res_u16(p + 7)); 1019 + } else if (name == 0x09 && len >= 2) { 1020 + unsigned count = len >= 2 ? (unsigned)p[1] : 0u; 1021 + tobi_sb_printf(&sb, "flags=0x%x interrupts=%u", (unsigned)p[0], count); 1022 + } else if (name == 0x0a && len >= 43) { 1023 + tobi_sb_printf(&sb, "rtype=0x%x flags=0x%x gran=0x%llx min=0x%llx max=0x%llx length=0x%llx", 1024 + (unsigned)p[0], (unsigned)p[1], (unsigned long long)res_u64(p + 3), 1025 + (unsigned long long)res_u64(p + 11), (unsigned long long)res_u64(p + 19), 1026 + (unsigned long long)res_u64(p + 35)); 1027 + } else if (name == 0x0c && len >= 2) { 1028 + tobi_sb_printf(&sb, "revision=%u type=0x%x", (unsigned)p[0], (unsigned)p[1]); 1029 + } else if (name == 0x0e && len >= 2) { 1030 + tobi_sb_printf(&sb, "revision=%u type=0x%x", (unsigned)p[0], (unsigned)p[1]); 1031 + } else { 1032 + tobi_sb_printf(&sb, "bytes=%zu", len); 1033 + } 1034 + return tobi_sb_take(&sb); 1035 + } 1036 + 1037 + static char *decode_resource_template(tobi_ir *parent, const uint8_t *data, size_t len, size_t base) { 908 1038 if (!data || len == 0) { 909 1039 return NULL; 910 1040 } ··· 929 1059 if (!label) { 930 1060 label = "LargeItem"; 931 1061 } 1062 + char *detail = large_res_detail(name, data + pos, item_len); 1063 + add_res_node(parent, label, base + pos - 3u, item_len + 3u, tag, item_len, detail); 1064 + free(detail); 932 1065 if (any) { 933 1066 tobi_sb_add(&sb, "; "); 934 1067 } ··· 945 1078 if (!label) { 946 1079 label = "SmallItem"; 947 1080 } 1081 + char *detail = small_res_detail(name, data + pos, item_len); 1082 + add_res_node(parent, label, base + pos - 1u, item_len + 1u, tag, item_len, detail); 1083 + free(detail); 948 1084 if (any) { 949 1085 tobi_sb_add(&sb, "; "); 950 1086 } ··· 983 1119 const uint8_t *bytes = body.data + body.pos; 984 1120 size_t byte_len = tobi_rd_left(&body); 985 1121 tobi_hex(&hex, bytes, byte_len); 986 - char *res = decode_resource_template(bytes, byte_len); 1122 + char *res = decode_resource_template(n, bytes, byte_len, body.base + body.pos); 987 1123 if (res) { 988 1124 tobi_sb_add(&hex, " resources="); 989 1125 tobi_sb_add(&hex, res); ··· 1157 1293 add_expr_children(p, rd, depth, n, 2); 1158 1294 tobi_ir *dst = ref_from_name(p, rd, off, "bad create-field namestring"); 1159 1295 if (dst) { 1296 + if (dst->path && dst->path[0] == '\\') { 1297 + ns_declare_path(p, TOBI_NS_FIELD, dst->path, dst->off, 0, op, 0, NULL); 1298 + } 1160 1299 tobi_ir_add(n, dst); 1161 1300 } 1162 1301 n->len = tobi_rd_off(rd) - off; ··· 1406 1545 } 1407 1546 } 1408 1547 1548 + static void sem_diag(parser *p, size_t off, const char *fmt, ...) { 1549 + va_list ap; 1550 + va_start(ap, fmt); 1551 + va_list cp; 1552 + va_copy(cp, ap); 1553 + int n = vsnprintf(NULL, 0, fmt, cp); 1554 + va_end(cp); 1555 + if (n < 0) { 1556 + n = 0; 1557 + } 1558 + char *msg = tobi_xmalloc((size_t)n + 1); 1559 + (void)vsnprintf(msg, (size_t)n + 1, fmt, ap); 1560 + va_end(ap); 1561 + diag(p, p->strict ? TOBI_DIAG_ERROR : TOBI_DIAG_WARN, off, "%s", msg); 1562 + free(msg); 1563 + } 1564 + 1565 + static int semantic_alias_cycle_from(const tobi_ns *ns, const tobi_ns_ent *start) { 1566 + const tobi_ns_ent *cur = start; 1567 + for (unsigned depth = 0; cur && cur->kind == TOBI_NS_ALIAS && cur->target; depth++) { 1568 + if (depth > ns->len) { 1569 + return 1; 1570 + } 1571 + const tobi_ns_ent *next = tobi_ns_find_const(ns, cur->target); 1572 + if (!next) { 1573 + return 0; 1574 + } 1575 + if (next == start) { 1576 + return 1; 1577 + } 1578 + cur = next; 1579 + } 1580 + return 0; 1581 + } 1582 + 1583 + static int semantic_ref_is_value(const tobi_ir *parent) { 1584 + if (!parent) { 1585 + return 1; 1586 + } 1587 + if (parent->kind == TOBI_IR_EXPR && parent->name) { 1588 + if (strncmp(parent->name, "create_", 7) == 0 || strcmp(parent->name, "cond_ref_of") == 0 || 1589 + strcmp(parent->name, "load") == 0 || strcmp(parent->name, "ref_of") == 0 || 1590 + strcmp(parent->name, "acquire") == 0 || strcmp(parent->name, "wait") == 0 || 1591 + strcmp(parent->name, "signal") == 0 || strcmp(parent->name, "reset") == 0 || 1592 + strcmp(parent->name, "release") == 0) { 1593 + return 0; 1594 + } 1595 + } 1596 + return 1; 1597 + } 1598 + 1599 + static void semantic_walk(parser *p, const tobi_ir *n, const tobi_ir *parent) { 1600 + if (!n) { 1601 + return; 1602 + } 1603 + if (n->kind == TOBI_IR_CALL && n->path && n->path[0] == '\\') { 1604 + const tobi_ns_ent *ent = tobi_ns_find_const(p->ns, n->path); 1605 + if (!ent || ent->kind != TOBI_NS_METHOD) { 1606 + sem_diag(p, n->off, "unresolved AML method call %s", n->path); 1607 + } else if (n->child_len != (size_t)ent->args) { 1608 + sem_diag(p, n->off, "AML method call %s has %zu args but namespace declares %u", 1609 + n->path, n->child_len, ent->args); 1610 + } 1611 + } else if (n->kind == TOBI_IR_REF && n->path && n->path[0] == '\\' && semantic_ref_is_value(parent)) { 1612 + const tobi_ns_ent *ent = tobi_ns_find_const(p->ns, n->path); 1613 + if (!ent) { 1614 + sem_diag(p, n->off, "unresolved AML namespace reference %s", n->path); 1615 + } 1616 + } 1617 + for (size_t i = 0; i < n->child_len; i++) { 1618 + semantic_walk(p, n->child[i], n); 1619 + } 1620 + } 1621 + 1622 + static void semantic_validate(parser *p, const tobi_ir *root) { 1623 + for (size_t i = 0; i < p->ns->len; i++) { 1624 + const tobi_ns_ent *e = &p->ns->items[i]; 1625 + if (e->external && e->kind == TOBI_NS_METHOD) { 1626 + sem_diag(p, e->off, "external AML method %s remains unresolved", e->path); 1627 + } 1628 + if (e->kind == TOBI_NS_ALIAS) { 1629 + if (e->target && !tobi_ns_find_const(p->ns, e->target)) { 1630 + sem_diag(p, e->off, "AML alias %s targets unresolved object %s", e->path, e->target); 1631 + } else if (semantic_alias_cycle_from(p->ns, e)) { 1632 + sem_diag(p, e->off, "AML alias cycle includes %s", e->path); 1633 + } 1634 + } 1635 + } 1636 + semantic_walk(p, root, NULL); 1637 + } 1638 + 1409 1639 int tobi_parse(const uint8_t *data, size_t len, int strict, tobi_parse_result *out) { 1410 1640 memset(out, 0, sizeof(*out)); 1411 1641 tobi_diag_init(&out->diag); ··· 1428 1658 tobi_rd_init(&rd, data + out->meta.aml_off, out->meta.aml_len, out->meta.aml_off); 1429 1659 (void)parse_term_list(&p, &rd, out->root, 0); 1430 1660 } 1661 + semantic_validate(&p, out->root); 1431 1662 parser_free(&p); 1432 1663 return !(strict && tobi_diag_has_error(&out->diag)); 1433 1664 } ··· 1476 1707 tobi_ir_add(out->root, file); 1477 1708 } 1478 1709 } 1710 + semantic_validate(&p, out->root); 1479 1711 parser_free(&p); 1480 1712 free(metas); 1481 1713 return ok && !(strict && tobi_diag_has_error(&out->diag));
+23
test/t_js.c
··· 20 20 T_CHECK(strstr(s, ",]") == NULL); 21 21 free(s); 22 22 tobi_parse_result_free(&r); 23 + 24 + uint8_t res[] = {0x11,0x05,0x0a,0x02,0x79,0x00}; 25 + T_CHECK(tobi_parse(res, sizeof(res), 0, &r)); 26 + s = tobi_js_emit(&r); 27 + T_STR(s, "\"kind\":\"resource\""); 28 + T_STR(s, "\"name\":\"EndTag\""); 29 + T_STR(s, "\"string\":\"checksum=0x0\""); 30 + T_CHECK(strstr(s, ",}") == NULL); 31 + T_CHECK(strstr(s, ",]") == NULL); 32 + free(s); 33 + tobi_parse_result_free(&r); 34 + 35 + uint8_t fld[] = {0x5b,0x80,'R','E','G','0',0x01,0x0a,0x10,0x0a,0x04,0x5b,0x81,0x0b,'R','E','G','0',0x00,'F','L','D','0',0x08}; 36 + T_CHECK(tobi_parse(fld, sizeof(fld), 0, &r)); 37 + s = tobi_js_emit(&r); 38 + T_STR(s, "\"target\":\"\\\\REG0\""); 39 + T_STR(s, "\"bit_offset\":0"); 40 + T_STR(s, "\"bit_length\":8"); 41 + T_STR(s, "\"access_type\":0"); 42 + T_CHECK(strstr(s, ",}") == NULL); 43 + T_CHECK(strstr(s, ",]") == NULL); 44 + free(s); 45 + tobi_parse_result_free(&r); 23 46 return 0; 24 47 }
+40
test/t_p.c
··· 63 63 T_CHECK(r.root->child_len == 1); 64 64 T_CHECK(r.root->child[0]->child[0]->kind == TOBI_IR_BUFFER); 65 65 T_STR(r.root->child[0]->child[0]->str, "EndTag"); 66 + T_CHECK(r.root->child[0]->child[0]->child_len == 2); 67 + T_CHECK(r.root->child[0]->child[0]->child[1]->kind == TOBI_IR_RESOURCE); 68 + T_CHECK(strcmp(r.root->child[0]->child[0]->child[1]->name, "EndTag") == 0); 69 + T_STR(r.root->child[0]->child[0]->child[1]->str, "checksum=0x0"); 70 + tobi_parse_result_free(&r); 71 + 72 + uint8_t io_res[] = {0x11,0x0d,0x0a,0x09,0x47,0x01,0x00,0x10,0xff,0x10,0x01,0x08,0x79,0x00}; 73 + T_CHECK(parse_ok(io_res, sizeof(io_res), &r)); 74 + T_CHECK(r.root->child_len == 1); 75 + T_CHECK(r.root->child[0]->kind == TOBI_IR_BUFFER); 76 + T_CHECK(r.root->child[0]->child_len == 3); 77 + T_CHECK(r.root->child[0]->child[1]->kind == TOBI_IR_RESOURCE); 78 + T_CHECK(strcmp(r.root->child[0]->child[1]->name, "IO") == 0); 79 + T_STR(r.root->child[0]->child[1]->str, "min=0x1000"); 66 80 tobi_parse_result_free(&r); 67 81 68 82 uint8_t fld[] = {0x5b,0x80,'R','E','G','0',0x01,0x0a,0x10,0x0a,0x04,0x5b,0x81,0x0b,'R','E','G','0',0x00,'F','L','D','0',0x08}; ··· 70 84 T_CHECK(r.root->child_len == 2); 71 85 T_CHECK(r.root->child[1]->kind == TOBI_IR_FIELD); 72 86 T_CHECK(r.root->child[1]->child_len == 1); 87 + T_STR(r.root->child[1]->target, "\\REG0"); 88 + T_CHECK(r.root->child[1]->access_type == 0); 73 89 T_CHECK(tobi_ns_find_const(&r.ns, "\\REG0") != NULL); 74 90 const tobi_ns_ent *fe = tobi_ns_find_const(&r.ns, "\\FLD0"); 75 91 T_CHECK(fe != NULL && fe->kind == TOBI_NS_FIELD); 92 + T_CHECK(r.root->child[1]->child[0]->bit_off == 0); 93 + T_CHECK(r.root->child[1]->child[0]->bit_len == 8); 76 94 T_CHECK(r.diag.len == 0); 77 95 tobi_parse_result_free(&r); 78 96 ··· 81 99 T_CHECK(r.root->child_len == 1); 82 100 T_CHECK(r.root->child[0]->kind == TOBI_IR_FIELD); 83 101 T_CHECK(strcmp(r.root->child[0]->str, "IndexField") == 0); 102 + T_STR(r.root->child[0]->target, "index=\\IDX0 data=\\DAT0"); 84 103 T_CHECK(r.root->child[0]->child_len == 1); 85 104 T_CHECK(strcmp(r.root->child[0]->child[0]->name, "IFLD") == 0); 105 + T_CHECK(r.root->child[0]->child[0]->bit_len == 8); 86 106 tobi_parse_result_free(&r); 87 107 88 108 uint8_t bfld[] = {0x5b,0x87,0x11,'R','E','G','0','B','N','K','0',0x0a,0x01,0x00,'B','F','L','D',0x08}; ··· 90 110 T_CHECK(r.root->child_len == 1); 91 111 T_CHECK(r.root->child[0]->kind == TOBI_IR_FIELD); 92 112 T_CHECK(strcmp(r.root->child[0]->str, "BankField") == 0); 113 + T_STR(r.root->child[0]->target, "region=\\REG0 bank=\\BNK0"); 93 114 T_CHECK(r.root->child[0]->child_len == 2); 94 115 T_CHECK(r.root->child[0]->child[0]->kind == TOBI_IR_INTEGER); 95 116 T_CHECK(r.root->child[0]->child[1]->kind == TOBI_IR_FIELD_ELEM); ··· 245 266 tobi_parse_result_free(&r); 246 267 T_CHECK(!tobi_parse(dup_name, sizeof(dup_name), 1, &r)); 247 268 T_CHECK(tobi_diag_has_error(&r.diag)); 269 + tobi_parse_result_free(&r); 270 + 271 + uint8_t unresolved_ref[] = {0x14,0x0b,'U','N','R','0',0x00,0xa4,'N','O','P','E'}; 272 + T_CHECK(tobi_parse(unresolved_ref, sizeof(unresolved_ref), 0, &r)); 273 + T_CHECK(r.diag.len == 1); 274 + T_CHECK(r.diag.items[0].level == TOBI_DIAG_WARN); 275 + T_STR(r.diag.items[0].msg, "unresolved AML namespace reference"); 276 + tobi_parse_result_free(&r); 277 + T_CHECK(!tobi_parse(unresolved_ref, sizeof(unresolved_ref), 1, &r)); 278 + T_CHECK(tobi_diag_has_error(&r.diag)); 279 + tobi_parse_result_free(&r); 280 + 281 + uint8_t alias_cycle[] = { 282 + 0x06,'A','L','B','0','A','L','A','0', 283 + 0x06,'A','L','A','0','A','L','B','0' 284 + }; 285 + T_CHECK(tobi_parse(alias_cycle, sizeof(alias_cycle), 0, &r)); 286 + T_CHECK(r.diag.len >= 1); 287 + T_STR(r.diag.items[0].msg, "alias cycle"); 248 288 tobi_parse_result_free(&r); 249 289 return 0; 250 290 }