Skip to content

Commit 33b2229

Browse files
committed
Runtime diag extended with translate_insn
1 parent 7e0830e commit 33b2229

7 files changed

Lines changed: 401 additions & 47 deletions

File tree

TODO.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
- [ ] Add CI target to run benchmarks and record baselines (tolerant thresholds)
4242
- [ ] Diagnostics + trap model (structured, stable)
4343
- [ ] Define stable trap/error codes (decode/verify, OOB, div0, unsupported-op, ABI failure, OOM/fuel)
44+
- [x] Fuel exhaustion (structured trap)
45+
- [x] Out-of-bounds memory access (structured trap)
46+
- [x] Division/mod by zero (structured trap)
47+
- [ ] Unsupported opcode (structured trap)
48+
- [ ] ABI misuse / host-call failure (structured trap)
49+
- [ ] OOM (structured trap)
4450
- [ ] Extend runtime diagnostics to include trap category + best-effort PC/offset
4551
- [ ] Ensure all failures are fail-closed (no host crashes, no UB)
4652
- [ ] Implement code cache keyed by (module hash, mem_base, mem_size, policy flags)
@@ -50,6 +56,11 @@
5056
- [ ] Define and implement trap/abort behavior (decode error, OOB, div0, unsupported op)
5157
- [ ] Plumb trap reporting from translated code back to runtime API (no printf-only failures)
5258
- [ ] Add negative tests for each trap category (including edge-case pointer/len ABI misuse)
59+
- [x] Fuel trap smoke coverage
60+
- [x] OOB trap smoke coverage (JIT-only)
61+
- [x] DIV0 trap smoke coverage (JIT-only)
62+
- [ ] Unsupported-op smoke coverage
63+
- [ ] ABI misuse smoke coverage
5364
- [x] Add differential test harness: run the same module under a reference runner and under the JIT; compare rc/stdout/stderr
5465
- [x] Add a tiny `zrt` CLI runner (executes `.zasm.bin` via `zasm_rt`) for test harness usage
5566
- [ ] Compare against a reference runner (choose one):

include/zasm_rt.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ typedef enum zasm_rt_err {
2828
typedef enum zasm_rt_trap {
2929
ZASM_RT_TRAP_NONE = 0,
3030
ZASM_RT_TRAP_FUEL = 1,
31+
ZASM_RT_TRAP_OOB = 2,
32+
ZASM_RT_TRAP_DIV0 = 3,
3133
} zasm_rt_trap_t;
3234

3335
/* Translation/execution target selection.
@@ -95,6 +97,14 @@ typedef struct zasm_rt_diag {
9597
zasm_verify_err_t verify_err;
9698
size_t verify_off;
9799
uint8_t verify_opcode;
100+
101+
/* Optional translate detail (when err==TRANSLATE_FAIL).
102+
* translate_err uses zxc_err_t numeric values.
103+
*/
104+
uint32_t translate_err;
105+
size_t translate_off;
106+
uint8_t translate_opcode;
107+
uint32_t translate_insn;
98108
} zasm_rt_diag_t;
99109

100110
typedef struct zasm_rt_engine zasm_rt_engine_t;

src/common/zasm_rt.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ static void diag_reset(zasm_rt_diag_t* diag) {
176176
diag->bin_tag[0] = '\0';
177177
}
178178

179+
static uint32_t u32_le(const uint8_t* p) {
180+
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) |
181+
((uint32_t)p[3] << 24);
182+
}
183+
179184
static zasm_rt_err_t diag_fail(zasm_rt_diag_t* diag, zasm_rt_err_t err) {
180185
if (diag) diag->err = err;
181186
return err;
@@ -524,10 +529,9 @@ zasm_rt_err_t zasm_rt_instance_create(zasm_rt_engine_t* engine,
524529
#if defined(__aarch64__) || defined(__arm64__)
525530
{
526531
uint64_t fuel_ptr = 0;
527-
uint64_t trap_ptr = 0;
532+
uint64_t trap_ptr = (uint64_t)(uintptr_t)&inst->trap;
528533
if (inst->policy.fuel != 0) {
529534
fuel_ptr = (uint64_t)(uintptr_t)&inst->fuel_remaining;
530-
trap_ptr = (uint64_t)(uintptr_t)&inst->trap;
531535
}
532536
tr = zxc_arm64_translate(code, code_len,
533537
inst->jit_mem, inst->jit_cap,
@@ -537,10 +541,9 @@ zasm_rt_err_t zasm_rt_instance_create(zasm_rt_engine_t* engine,
537541
#elif defined(__x86_64__) || defined(_M_X64)
538542
{
539543
uint64_t fuel_ptr = 0;
540-
uint64_t trap_ptr = 0;
544+
uint64_t trap_ptr = (uint64_t)(uintptr_t)&inst->trap;
541545
if (inst->policy.fuel != 0) {
542546
fuel_ptr = (uint64_t)(uintptr_t)&inst->fuel_remaining;
543-
trap_ptr = (uint64_t)(uintptr_t)&inst->trap;
544547
}
545548
tr = zxc_x86_64_translate(code, code_len,
546549
inst->jit_mem, inst->jit_cap,
@@ -554,6 +557,17 @@ zasm_rt_err_t zasm_rt_instance_create(zasm_rt_engine_t* engine,
554557
return diag_fail(diag, ZASM_RT_ERR_UNSUPPORTED);
555558
#endif
556559
if (tr.err != ZXC_OK) {
560+
if (diag) {
561+
diag->translate_err = (uint32_t)tr.err;
562+
diag->translate_off = tr.in_off;
563+
diag->translate_opcode = 0;
564+
diag->translate_insn = 0;
565+
if (tr.in_off + 4u <= code_len) {
566+
uint32_t w = u32_le(code + tr.in_off);
567+
diag->translate_insn = w;
568+
diag->translate_opcode = (uint8_t)(w >> 24);
569+
}
570+
}
557571
zasm_rt_instance_destroy(inst);
558572
*out_instance = NULL;
559573
return diag_fail(diag, ZASM_RT_ERR_TRANSLATE_FAIL);

src/zrt/main.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ static void print_version(void) {
3939
fprintf(stdout, "zrt %s\n", ZASM_VERSION);
4040
}
4141

42+
static const char* zxc_err_str_local(uint32_t err) {
43+
switch (err) {
44+
case 0: return "ok";
45+
case 1: return "trunc";
46+
case 2: return "align";
47+
case 3: return "outbuf";
48+
case 4: return "opcode";
49+
case 5: return "unimpl";
50+
default: return "unknown";
51+
}
52+
}
53+
4254
static int read_whole_file(const char *path, uint8_t **out_buf, size_t *out_len) {
4355
if (!path || !out_buf || !out_len) return 0;
4456
*out_buf = NULL;
@@ -106,6 +118,13 @@ static void print_diag(const zasm_rt_diag_t *d) {
106118
fprintf(stderr, "diag: verify: err=%d off=%zu opcode=0x%02x\n",
107119
(int)d->verify_err, d->verify_off, (unsigned)d->verify_opcode);
108120
}
121+
122+
if (d->err == ZASM_RT_ERR_TRANSLATE_FAIL) {
123+
fprintf(stderr, "diag: translate: err=%u(%s) off=%zu opcode=0x%02x insn=0x%08x\n",
124+
(unsigned)d->translate_err, zxc_err_str_local(d->translate_err),
125+
d->translate_off, (unsigned)d->translate_opcode,
126+
(unsigned)d->translate_insn);
127+
}
109128
}
110129

111130
static uint64_t monotonic_ms(void) {
@@ -173,12 +192,33 @@ static int run_guest(const char *path, int safe_mode, int allow_primitives, uint
173192

174193
e = zasm_rt_instance_run(inst, &diag);
175194
if (e != ZASM_RT_OK) {
176-
if (e == ZASM_RT_ERR_EXEC_FAIL && diag.trap == ZASM_RT_TRAP_FUEL) {
177-
fprintf(stderr, "zrt: trap: fuel exhausted\n");
178-
zasm_rt_instance_destroy(inst);
179-
zasm_rt_module_destroy(module);
180-
zasm_rt_engine_destroy(engine);
181-
return 1;
195+
if (e == ZASM_RT_ERR_EXEC_FAIL) {
196+
switch (diag.trap) {
197+
case ZASM_RT_TRAP_FUEL:
198+
fprintf(stderr, "zrt: trap: fuel exhausted\n");
199+
zasm_rt_instance_destroy(inst);
200+
zasm_rt_module_destroy(module);
201+
zasm_rt_engine_destroy(engine);
202+
return 1;
203+
case ZASM_RT_TRAP_OOB:
204+
fprintf(stderr, "zrt: trap: out of bounds memory access\n");
205+
zasm_rt_instance_destroy(inst);
206+
zasm_rt_module_destroy(module);
207+
zasm_rt_engine_destroy(engine);
208+
return 1;
209+
case ZASM_RT_TRAP_DIV0:
210+
fprintf(stderr, "zrt: trap: division by zero\n");
211+
zasm_rt_instance_destroy(inst);
212+
zasm_rt_module_destroy(module);
213+
zasm_rt_engine_destroy(engine);
214+
return 1;
215+
default:
216+
fprintf(stderr, "zrt: trap\n");
217+
zasm_rt_instance_destroy(inst);
218+
zasm_rt_module_destroy(module);
219+
zasm_rt_engine_destroy(engine);
220+
return 1;
221+
}
182222
}
183223
fprintf(stderr, "zrt: error: instance_run: %s\n", zasm_rt_err_str(e));
184224
print_diag(&diag);

0 commit comments

Comments
 (0)