Merge task/crash705: list the compound physics shape's children in the crash report (#705)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Valiantsin DzerakhandClaude Opus 5.5 committed 2026-11-10 10:20:07 +03:00
commit 1503b17f7d
2 files changed
+79

No files matched your search

+42
View File
@@ -10,6 +10,7 @@
#include "cfg.h"
#include "host.h"
#include "kernel.h"
#include "layout.h"
#include "platform/platform.h"
#define STACK 0x10000
@@ -744,7 +745,36 @@ static void test_platform(void) {
static uint64_t crash_host_words[6] = {0, 0, 0x5ca1ab1e0c0de001ull, 0, 0, 0};
static uint64_t crash_guest_words[6] = {0, 0, 0x5ca1ab1e0c0de002ull, 0, 0, 0};
// The compound shape note (main.c crash_compound_shape, 1.2.1): a shape of 3 records whose child 0 has no shape, child
// 1 has one but its live bit is clear, child 2 is live and filled.
static uint64_t crash_shape[0x1a0 / 8], crash_records[3 * 0x78 / 8], crash_child_shape;
static void crash_shape_fill(Cpu *c) {
uint8_t *s = (uint8_t *)crash_shape, *r = (uint8_t *)crash_records;
static const char *const names[3] = {"PartA", "PartB", "PartC"};
for (int i = 0; i < 3; i++) {
uint64_t name = (uint64_t)(uintptr_t)(r + i * 0x78 + 0x14);
memcpy(r + i * 0x78 + 8, &name, 8);
memcpy(r + i * 0x78 + 0x14, names[i], strlen(names[i]) + 1);
}
uint64_t child = (uint64_t)(uintptr_t)&crash_child_shape, vt = MOD_MAIN_BASE + 0x45e1218;
uint64_t rec = (uint64_t)(uintptr_t)crash_records;
uint32_t n = 3, bits = 0x5;
memcpy(r + 0x78, &child, 8);
memcpy(r + 2 * 0x78, &child, 8);
memcpy(s, &vt, 8);
memcpy(s + 0x78, &n, 4);
memcpy(s + 0x80, &rec, 8);
memcpy(s + 0x88, &bits, 4);
memcpy(s + 0x190, &n, 4);
c->x[20] = (uint64_t)(uintptr_t)crash_shape;
c->x[21] = 0x1000038;
c->x[30] = MOD_MAIN_BASE + 0xe056d4;
}
static void crash_child_main(Cpu *c) {
const char *mode = getenv(CRASH_CHILD_ENV);
if (mode && !strcmp(mode, "shape")) crash_shape_fill(c);
c->x[19] = (uint64_t)(uintptr_t)&crash_guest_words[2];
c->sp -= 0x100; // a frame on the guest stack, as a crashing function has
__asm__ volatile("movq %0, %%rbx\n\tmovq 0x10, %%rax" : : "r"(&crash_host_words[2]) : "rax", "rbx", "memory");
@@ -779,6 +809,18 @@ static void test_crash_report(void) {
"crash report: no memory commit line");
printf("crash report: exit code %d, host registers, code bytes, memory at rbx and x19, guest stack, commit %s\n", code,
failures ? "checked with failures" : "present");
if (rt_game_version != 121) return;
code = plat_run_self(CRASH_CHILD_ENV, "shape", out, sizeof out, 30000);
CHECK(report_line(out, " compound shape ", line, sizeof line) && strstr(line, "3 children, 3 records") &&
strstr(line, "live bits: 00000005"),
"crash report: no compound shape line (%s)", strstr(out, "compound shape") ? line : "none");
CHECK(report_line(out, "child 0:", line, sizeof line) && strstr(line, "shape 0 \"PartA\""),
"crash report: child 0 should have no shape (%s)", line);
CHECK(report_line(out, "child 1:", line, sizeof line) && strstr(line, "(off) \"PartB\""),
"crash report: child 1 should be off (%s)", line);
CHECK(report_line(out, "child 2:", line, sizeof line) && !strstr(line, "(off)") && strstr(line, "\"PartC\""),
"crash report: child 2 should be live (%s)", line);
printf("crash report, compound shape: exit code %d, %s\n", code, failures ? "checked with failures" : "children listed");
}
int probe_kernel(void) {
+37
View File
@@ -30,6 +30,7 @@
#include "cfg.h"
#include "host.h"
#include "layout.h"
#include "platform/platform.h"
#include "sha256.h"
@@ -284,6 +285,41 @@ static void crash_memory(const PlatCrash *x, const Cpu *c) {
(unsigned long long)s[i + 1], (unsigned long long)s[i + 2], (unsigned long long)s[i + 3]);
}
// 1.2.1: a fault right after a compound physics shape was asked for its first child's material (the call returning to
// main+0xe056d4 reads the result without a check). The shape (vtable main+0x45e1218, built by main+0x7359fc) is in x20
// there. It returns null when no child slot is both live (bitmap at +0x88) and filled (shape pointer at +0 of the
// 0x78-byte records at +0x80). Every child is filled when the shape is built, so the list tells children removed later
// (null shape) from children switched off (clear bit), and the names name the object. Runs only in the crash handler.
static void crash_compound_shape(const Cpu *c) {
if (!c || rt_game_version != 121 || c->x[30] != MOD_MAIN_BASE + 0xe056d4) return;
uint64_t shape = c->x[20];
if (!readable(shape, 0x1a0) || LD64(shape) != MOD_MAIN_BASE + 0x45e1218) {
rt_logf(" compound shape: x20 %#llx is not one\n", (unsigned long long)shape);
return;
}
uint32_t children = LD32(shape + 0x190), records = LD32(shape + 0x78);
uint64_t rec = LD64(shape + 0x80);
rt_logf(" compound shape %#llx (holder %#llx): %u children, %u records at %#llx, live bits:",
(unsigned long long)shape, (unsigned long long)(c->x[21] - 0x38), children, records,
(unsigned long long)rec);
uint32_t n = children > 0x400 ? 0x400 : children; // the bitmap holds 0x400 bits
for (uint32_t w = 0; w < (n + 31) / 32; w++) rt_logf(" %08x", LD32(shape + 0x88 + 4 * w));
rt_log_raw("\n", 1);
if (records > 0x400 || !readable(rec, (uint64_t)records * 0x78)) return;
for (uint32_t i = 0; i < records; i++) {
uint64_t r = rec + (uint64_t)i * 0x78, child = LD64(r), s = LD64(r + 8);
char name[33];
size_t k = 0;
for (; k < 32 && readable(s + k, 1); k++) {
name[k] = *(const char *)(uintptr_t)(s + k);
if (!name[k]) break;
}
name[k] = 0;
int live = LD32(shape + 0x88 + 4 * (i >> 5)) >> (i & 31) & 1;
rt_logf(" child %3u: shape %#llx%s \"%s\"\n", i, (unsigned long long)child, live ? "" : " (off)", name);
}
}
static void crash_handler(const PlatCrash *x) {
static volatile int32_t busy;
if (plat_xchg32(&busy, 1)) plat_exit(71);
@@ -349,6 +385,7 @@ static void crash_handler(const PlatCrash *x) {
rt_logf(" not on a guest thread\n");
}
crash_memory(x, c);
crash_compound_shape(c);
kern_free_cores_note();
fflush(stderr);
plat_exit(71);