diff --git a/cffdump/crashdec.c b/cffdump/crashdec.c index 1fef6871..a50b17f4 100644 --- a/cffdump/crashdec.c +++ b/cffdump/crashdec.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,34 @@ parseline(const char *line, const char *fmt, ...) break; \ } else +/* + * Provide our own disasm assert() handler, so that we can recover + * after attempting to disassemble things that might not be valid + * instructions: + */ + +static bool jmp_env_valid; +static jmp_buf jmp_env; + +void +ir3_assert_handler(const char *expr, const char *file, int line, + const char *func) +{ + printf("%s:%u: %s: Assertion `%s' failed.\n", file, line, func, expr); + if (jmp_env_valid) + longjmp(jmp_env, 1); + abort(); +} + +#define TRY(x) do { \ + assert(!jmp_env_valid); \ + if (setjmp(jmp_env) == 0) { \ + jmp_env_valid = true; \ + x; \ + } \ + jmp_env_valid = false; \ + } while (0) + /* * Decode ringbuffer section: */ @@ -299,6 +328,8 @@ dump_cmdstream(void) for (int id = 0; id < ARRAY_SIZE(ringbuffers); id++) { if (ringbuffers[id].iova != rb_base) continue; + if (!ringbuffers[id].size) + continue; printf("found ring!\n"); @@ -877,7 +908,7 @@ decode_shader_blocks(void) * (or parts of shaders?), so perhaps we should search * for ends of shaders and decode each? */ - disasm_a3xx(buf, sizedwords, 1, stdout, options.gpu_id); + TRY(disasm_a3xx(buf, sizedwords, 1, stdout, options.gpu_id)); } if (dump) diff --git a/cffdump/disasm-a3xx.c b/cffdump/disasm-a3xx.c index 249563bb..9645dc5f 100644 --- a/cffdump/disasm-a3xx.c +++ b/cffdump/disasm-a3xx.c @@ -174,7 +174,7 @@ static void regmask_set(regmask_t *regmask, unsigned num, bool full, unsigned va { unsigned i = num / 8; unsigned j = num % 8; - assert(num < MAX_REG); + ir3_assert(num < MAX_REG); if (full) { regmask->full[i] = (regmask->full[i] & ~(1 << j)) | (val << j); } else { @@ -186,7 +186,7 @@ static unsigned regmask_get(regmask_t *regmask, unsigned num, bool full) { unsigned i = num / 8; unsigned j = num % 8; - assert(num < MAX_REG); + ir3_assert(num < MAX_REG); if (full) { return (regmask->full[i] >> j) & 0x1; } else { @@ -1614,7 +1614,7 @@ int disasm_a3xx_stat(uint32_t *dwords, int sizedwords, int level, FILE *out, int nop_count = 0; bool has_end = false; -// assert((sizedwords % 2) == 0); +// ir3_assert((sizedwords % 2) == 0); memset(&ctx, 0, sizeof(ctx)); ctx.out = out; diff --git a/cffdump/instr-a3xx.h b/cffdump/instr-a3xx.h index b372bd14..218bdc3e 100644 --- a/cffdump/instr-a3xx.h +++ b/cffdump/instr-a3xx.h @@ -30,6 +30,23 @@ #include #include +void ir3_assert_handler(const char *expr, const char *file, int line, + const char *func) __attribute__((weak)) __attribute__ ((__noreturn__)); + +/* A wrapper for assert() that allows overriding handling of a failed + * assert. This is needed for tools like crashdec which can want to + * attempt to disassemble memory that might not actually be valid + * instructions. + */ +#define ir3_assert(expr) do { \ + if (!(expr)) { \ + if (ir3_assert_handler) { \ + ir3_assert_handler(#expr, __FILE__, __LINE__, __func__); \ + } \ + assert(expr); \ + } \ + } while (0) + /* size of largest OPC field of all the instruction categories: */ #define NOPC_BITS 6 @@ -251,7 +268,7 @@ static inline uint32_t type_size(type_t type) case TYPE_S8: return 8; default: - assert(0); /* invalid type */ + ir3_assert(0); /* invalid type */ return 0; } } @@ -958,8 +975,8 @@ static inline bool is_cat6_legacy(instr_t *instr, unsigned gpu_id) * in all cases. So we can use this to detect new encoding: */ if ((cat6->pad3 & 0x8) && (cat6->pad5 & 0x2)) { - assert(gpu_id >= 600); - assert(instr->cat6.opc == 0); + ir3_assert(gpu_id >= 600); + ir3_assert(instr->cat6.opc == 0); return false; }