From 74e77ce6a4b2968c7079ceaace8b39772b14a511 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 15 Oct 2025 08:33:51 -0700 Subject: [PATCH] freedreno/crashdec: Log IBs to snapshot Signed-off-by: Rob Clark Part-of: --- src/freedreno/decode/crashdec.c | 60 +++++++++++++++++++++++++++++++-- src/freedreno/decode/snapshot.h | 41 ++++++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/freedreno/decode/crashdec.c b/src/freedreno/decode/crashdec.c index 444c98a656d..7841aa5447d 100644 --- a/src/freedreno/decode/crashdec.c +++ b/src/freedreno/decode/crashdec.c @@ -422,6 +422,52 @@ valid_header(uint32_t pkt) } } +/** + * Simplified version of the parsing loop in dump_commands(), which simply + * looks for "IB" type packets and logs the target cmdstream buffers. + */ +static void +parse_ibs(uint32_t *dwords, uint32_t sizedwords) +{ + int dwords_left = sizedwords; + uint32_t count = 0; /* dword count including packet header */ + uint32_t val; + + while (dwords_left > 0) { + if (pkt_is_regwrite(dwords[0], &val, &count)) { + /* ignore */ + } else if (pkt_is_opcode(dwords[0], &val, &count)) { + const char *name = pktname(val); + if (!strcmp(name, "CP_INDIRECT_BUFFER")) { + uint64_t ibaddr; + uint32_t ibsize; + + parse_cp_indirect(&dwords[1], count - 1, &ibaddr, &ibsize); + + /* map gpuaddr back to hostptr: */ + void *ptr = hostptr(ibaddr); + snapshot_ib(ibaddr, ptr, ibsize); + } + // TODO CP_SET_DRAW_STATE and others? + } else if (pkt_is_type2(dwords[0])) { + /* no-op */ + count = 1; + } else { + printf("bad type! %08x\n", dwords[0]); + /* for 5xx+ we can do a passable job of looking for start of next valid + * packet: */ + if (options.info->chip >= 5) { + count = find_next_packet(dwords, dwords_left); + } else { + return; + } + } + + dwords += count; + dwords_left -= count; + } +} + static void dump_cmdstream(void) { @@ -522,7 +568,13 @@ dump_cmdstream(void) options.ibs[0].size = cmdszdw; handle_prefetch(buf, cmdszdw); - dump_commands(buf, cmdszdw, 0); + + if (snapshot) { + parse_ibs(buf, cmdszdw); + } else { + dump_commands(buf, cmdszdw, 0); + } + free(buf); } } @@ -1136,11 +1188,12 @@ decode(void) static void decode_finalize(void) { + snapshot_linux.ptbase = ptbase; + /* Dump cmdstream at the end after we know we've decoded all sections that might * contain reg vals needed for locating the cmdstream: */ - if (!snapshot) - dump_cmdstream(); + dump_cmdstream(); /* If we are exporting snapshot, finalize it now: */ do_snapshot(); @@ -1249,6 +1302,7 @@ main(int argc, char **argv) if (snapshot) { freopen("/dev/null", "w", stdout); + verbose = false; } else if (interactive) { pager_open(); } diff --git a/src/freedreno/decode/snapshot.h b/src/freedreno/decode/snapshot.h index 7e6f09a6e03..d093fd9235e 100644 --- a/src/freedreno/decode/snapshot.h +++ b/src/freedreno/decode/snapshot.h @@ -327,6 +327,7 @@ struct snapshot_gmu_version { */ static FILE *snapshot; +static uint64_t ptbase = 0x43210000; /* We don't always have a real ttbr0, so fake it */ static inline void snapshot_write(void *data, size_t sz) @@ -556,6 +557,36 @@ snapshot_gpu_object(uint64_t gpuaddr, uint32_t size, uint32_t *buf) snapshot_write(buf, size); } +static struct { + struct snapshot_ib_v2 ib; + uint32_t *dwords; +} ibs[512]; +static unsigned nibs; + +static inline void +snapshot_ib(uint64_t gpuaddr, uint32_t *dwords, uint32_t sizedwords) +{ + int idx; + + if (!snapshot || !dwords) + return; + + for (idx = 0; idx < nibs; idx++) { + if (ibs[idx].ib.gpuaddr == gpuaddr) { + ibs[idx].ib.size = MAX2(ibs[idx].ib.size, sizedwords); + return; + } + } + + assert(idx < ARRAY_SIZE(ibs)); + ibs[idx].ib.gpuaddr = gpuaddr; + ibs[idx].ib.size = sizedwords; + ibs[idx].ib.ptbase = ptbase; + ibs[idx].dwords = dwords; + + nibs++; +} + static inline void do_snapshot(void) { @@ -582,6 +613,16 @@ do_snapshot(void) snapshot_write(buf, snapshot_rb[i].rbsize * 4); } + for (unsigned i = 0; i < nibs; i++) { + snapshot_write_sect_header( + SNAPSHOT_SECTION_IB_V2, + sizeof(ibs[i].ib) + (4 * ibs[i].ib.size) + ); + snapshot_write(&ibs[i].ib, sizeof(ibs[i].ib)); + snapshot_write(ibs[i].dwords, ibs[i].ib.size * 4); + + } + snapshot_write_sect_header(SNAPSHOT_SECTION_END, 0); }