1 /*
2 * Copyright © 2020 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 /*
25 * Decoder for devcoredump traces from drm/msm. In case of a gpu crash/hang,
26 * the coredump should be found in:
27 *
28 * /sys/class/devcoredump/devcd<n>/data
29 *
30 * The crashdump will hang around for 5min, it can be cleared by writing to
31 * the file, ie:
32 *
33 * echo 1 > /sys/class/devcoredump/devcd<n>/data
34 *
35 * (the driver won't log any new crashdumps until the previous one is cleared
36 * or times out after 5min)
37 */
38
39
40 #include "crashdec.h"
41
42 static FILE *in;
43 bool verbose;
44
45 struct rnn *rnn_gmu;
46 struct rnn *rnn_control;
47 struct rnn *rnn_pipe;
48
49 static uint64_t fault_iova;
50 static bool has_fault_iova;
51
52 struct cffdec_options options = {
53 .draw_filter = -1,
54 };
55
56 /*
57 * Helpers to read register values:
58 */
59
60 /* read registers that are 64b on 64b GPUs (ie. a5xx+) */
61 static uint64_t
regval64(const char * name)62 regval64(const char *name)
63 {
64 unsigned reg = regbase(name);
65 assert(reg);
66 uint64_t val = reg_val(reg);
67 if (is_64b())
68 val |= ((uint64_t)reg_val(reg + 1)) << 32;
69 return val;
70 }
71
72 static uint32_t
regval(const char * name)73 regval(const char *name)
74 {
75 unsigned reg = regbase(name);
76 assert(reg);
77 return reg_val(reg);
78 }
79
80 /*
81 * Line reading and string helpers:
82 */
83
84 static char *
replacestr(char * line,const char * find,const char * replace)85 replacestr(char *line, const char *find, const char *replace)
86 {
87 char *tail, *s;
88
89 if (!(s = strstr(line, find)))
90 return line;
91
92 tail = s + strlen(find);
93
94 char *newline;
95 asprintf(&newline, "%.*s%s%s", (int)(s - line), line, replace, tail);
96 free(line);
97
98 return newline;
99 }
100
101 static char *lastline;
102 static char *pushedline;
103
104 static const char *
popline(void)105 popline(void)
106 {
107 char *r = pushedline;
108
109 if (r) {
110 pushedline = NULL;
111 return r;
112 }
113
114 free(lastline);
115
116 size_t n = 0;
117 if (getline(&r, &n, in) < 0)
118 exit(0);
119
120 /* Handle section name typo's from earlier kernels: */
121 r = replacestr(r, "CP_MEMPOOOL", "CP_MEMPOOL");
122 r = replacestr(r, "CP_SEQ_STAT", "CP_SQE_STAT");
123
124 lastline = r;
125 return r;
126 }
127
128 static void
pushline(void)129 pushline(void)
130 {
131 assert(!pushedline);
132 pushedline = lastline;
133 }
134
135 static uint32_t *
popline_ascii85(uint32_t sizedwords)136 popline_ascii85(uint32_t sizedwords)
137 {
138 const char *line = popline();
139
140 /* At this point we exepct the ascii85 data to be indented *some*
141 * amount, and to terminate at the end of the line. So just eat
142 * up the leading whitespace.
143 */
144 assert(*line == ' ');
145 while (*line == ' ')
146 line++;
147
148 uint32_t *buf = calloc(1, 4 * sizedwords);
149 int idx = 0;
150
151 while (*line != '\n') {
152 if (*line == 'z') {
153 buf[idx++] = 0;
154 line++;
155 continue;
156 }
157
158 uint32_t accum = 0;
159 for (int i = 0; (i < 5) && (*line != '\n'); i++) {
160 accum *= 85;
161 accum += *line - '!';
162 line++;
163 }
164
165 buf[idx++] = accum;
166 }
167
168 return buf;
169 }
170
171 static bool
startswith(const char * line,const char * start)172 startswith(const char *line, const char *start)
173 {
174 return strstr(line, start) == line;
175 }
176
177 static void
parseline(const char * line,const char * fmt,...)178 parseline(const char *line, const char *fmt, ...)
179 {
180 int fmtlen = strlen(fmt);
181 int n = 0;
182 int l = 0;
183
184 /* scan fmt string to extract expected # of conversions: */
185 for (int i = 0; i < fmtlen; i++) {
186 if (fmt[i] == '%') {
187 if (i == (l - 1)) { /* prev char was %, ie. we have %% */
188 n--;
189 l = 0;
190 } else {
191 n++;
192 l = i;
193 }
194 }
195 }
196
197 va_list ap;
198 va_start(ap, fmt);
199 if (vsscanf(line, fmt, ap) != n) {
200 fprintf(stderr, "parse error scanning: '%s'\n", fmt);
201 exit(1);
202 }
203 va_end(ap);
204 }
205
206 #define foreach_line_in_section(_line) \
207 for (const char *_line = popline(); _line; _line = popline()) \
208 /* check for start of next section */ \
209 if (_line[0] != ' ') { \
210 pushline(); \
211 break; \
212 } else
213
214 /*
215 * Decode ringbuffer section:
216 */
217
218 static struct {
219 uint64_t iova;
220 uint32_t rptr;
221 uint32_t wptr;
222 uint32_t size;
223 uint32_t *buf;
224 } ringbuffers[5];
225
226 static void
decode_ringbuffer(void)227 decode_ringbuffer(void)
228 {
229 int id = 0;
230
231 foreach_line_in_section (line) {
232 if (startswith(line, " - id:")) {
233 parseline(line, " - id: %d", &id);
234 assert(id < ARRAY_SIZE(ringbuffers));
235 } else if (startswith(line, " iova:")) {
236 parseline(line, " iova: %" PRIx64, &ringbuffers[id].iova);
237 } else if (startswith(line, " rptr:")) {
238 parseline(line, " rptr: %d", &ringbuffers[id].rptr);
239 } else if (startswith(line, " wptr:")) {
240 parseline(line, " wptr: %d", &ringbuffers[id].wptr);
241 } else if (startswith(line, " size:")) {
242 parseline(line, " size: %d", &ringbuffers[id].size);
243 } else if (startswith(line, " data: !!ascii85 |")) {
244 ringbuffers[id].buf = popline_ascii85(ringbuffers[id].size / 4);
245 add_buffer(ringbuffers[id].iova, ringbuffers[id].size,
246 ringbuffers[id].buf);
247 continue;
248 }
249
250 printf("%s", line);
251 }
252 }
253
254 /*
255 * Decode GMU log
256 */
257
258 static void
decode_gmu_log(void)259 decode_gmu_log(void)
260 {
261 uint64_t iova;
262 uint32_t size;
263
264 foreach_line_in_section (line) {
265 if (startswith(line, " iova:")) {
266 parseline(line, " iova: %" PRIx64, &iova);
267 } else if (startswith(line, " size:")) {
268 parseline(line, " size: %u", &size);
269 } else if (startswith(line, " data: !!ascii85 |")) {
270 void *buf = popline_ascii85(size / 4);
271
272 dump_hex_ascii(buf, size, 1);
273
274 free(buf);
275
276 continue;
277 }
278
279 printf("%s", line);
280 }
281 }
282
283 /*
284 * Decode HFI queues
285 */
286
287 static void
decode_gmu_hfi(void)288 decode_gmu_hfi(void)
289 {
290 struct a6xx_hfi_state hfi = {};
291
292 /* Initialize the history buffers with invalid entries (-1): */
293 memset(&hfi.history, 0xff, sizeof(hfi.history));
294
295 foreach_line_in_section (line) {
296 if (startswith(line, " iova:")) {
297 parseline(line, " iova: %" PRIx64, &hfi.iova);
298 } else if (startswith(line, " size:")) {
299 parseline(line, " size: %u", &hfi.size);
300 } else if (startswith(line, " queue-history")) {
301 unsigned qidx, dummy;
302
303 parseline(line, " queue-history[%u]:", &qidx);
304 assert(qidx < ARRAY_SIZE(hfi.history));
305
306 parseline(line, " queue-history[%u]: %d %d %d %d %d %d %d %d", &dummy,
307 &hfi.history[qidx][0], &hfi.history[qidx][1],
308 &hfi.history[qidx][2], &hfi.history[qidx][3],
309 &hfi.history[qidx][4], &hfi.history[qidx][5],
310 &hfi.history[qidx][6], &hfi.history[qidx][7]);
311 } else if (startswith(line, " data: !!ascii85 |")) {
312 hfi.buf = popline_ascii85(hfi.size / 4);
313
314 if (verbose)
315 dump_hex_ascii(hfi.buf, hfi.size, 1);
316
317 dump_gmu_hfi(&hfi);
318
319 free(hfi.buf);
320
321 continue;
322 }
323
324 printf("%s", line);
325 }
326 }
327
328 static bool
valid_header(uint32_t pkt)329 valid_header(uint32_t pkt)
330 {
331 if (options.info->chip >= 5) {
332 return pkt_is_type4(pkt) || pkt_is_type7(pkt);
333 } else {
334 /* TODO maybe we can check validish looking pkt3 opc or pkt0
335 * register offset.. the cmds sent by kernel are usually
336 * fairly limited (other than initialization) which confines
337 * the search space a bit..
338 */
339 return true;
340 }
341 }
342
343 static void
dump_cmdstream(void)344 dump_cmdstream(void)
345 {
346 uint64_t rb_base = regval64("CP_RB_BASE");
347
348 printf("got rb_base=%" PRIx64 "\n", rb_base);
349
350 options.ibs[1].base = regval64("CP_IB1_BASE");
351 if (is_a6xx())
352 options.ibs[1].rem = regval("CP_IB1_REM_SIZE");
353 options.ibs[2].base = regval64("CP_IB2_BASE");
354 if (is_a6xx())
355 options.ibs[2].rem = regval("CP_IB2_REM_SIZE");
356
357 /* Adjust remaining size to account for cmdstream slurped into ROQ
358 * but not yet consumed by SQE
359 *
360 * TODO add support for earlier GPUs once we tease out the needed
361 * registers.. see crashit.c in msmtest for hints.
362 *
363 * TODO it would be nice to be able to extract out register bitfields
364 * by name rather than hard-coding this.
365 */
366 if (is_a6xx()) {
367 uint32_t ib1_rem = regval("CP_ROQ_AVAIL_IB1") >> 16;
368 uint32_t ib2_rem = regval("CP_ROQ_AVAIL_IB2") >> 16;
369 options.ibs[1].rem += ib1_rem ? ib1_rem - 1 : 0;
370 options.ibs[2].rem += ib2_rem ? ib2_rem - 1 : 0;
371 }
372
373 printf("IB1: %" PRIx64 ", %u\n", options.ibs[1].base, options.ibs[1].rem);
374 printf("IB2: %" PRIx64 ", %u\n", options.ibs[2].base, options.ibs[2].rem);
375
376 /* now that we've got the regvals we want, reset register state
377 * so we aren't seeing values from decode_registers();
378 */
379 reset_regs();
380
381 for (int id = 0; id < ARRAY_SIZE(ringbuffers); id++) {
382 if (ringbuffers[id].iova != rb_base)
383 continue;
384 if (!ringbuffers[id].size)
385 continue;
386
387 printf("found ring!\n");
388
389 /* The kernel level ringbuffer (RB) wraps around, which
390 * cffdec doesn't really deal with.. so figure out how
391 * many dwords are unread
392 */
393 unsigned ringszdw = ringbuffers[id].size >> 2; /* in dwords */
394
395 if (verbose) {
396 handle_prefetch(ringbuffers[id].buf, ringszdw);
397 dump_commands(ringbuffers[id].buf, ringszdw, 0);
398 return;
399 }
400
401 /* helper macro to deal with modulo size math: */
402 #define mod_add(b, v) ((ringszdw + (int)(b) + (int)(v)) % ringszdw)
403
404 /* The rptr will (most likely) have moved past the IB to
405 * userspace cmdstream, so back up a bit, and then advance
406 * until we find a valid start of a packet.. this is going
407 * to be less reliable on a4xx and before (pkt0/pkt3),
408 * compared to pkt4/pkt7 with parity bits
409 */
410 const int lookback = 12;
411 unsigned rptr = mod_add(ringbuffers[id].rptr, -lookback);
412
413 for (int idx = 0; idx < lookback; idx++) {
414 if (valid_header(ringbuffers[id].buf[rptr]))
415 break;
416 rptr = mod_add(rptr, 1);
417 }
418
419 unsigned cmdszdw = mod_add(ringbuffers[id].wptr, -rptr);
420
421 printf("got cmdszdw=%d\n", cmdszdw);
422 uint32_t *buf = malloc(cmdszdw * 4);
423
424 for (int idx = 0; idx < cmdszdw; idx++) {
425 int p = mod_add(rptr, idx);
426 buf[idx] = ringbuffers[id].buf[p];
427 }
428
429 handle_prefetch(buf, cmdszdw);
430 dump_commands(buf, cmdszdw, 0);
431 free(buf);
432 }
433 }
434
435 /*
436 * Decode optional 'fault-info' section. We only get this section if
437 * the devcoredump was triggered by an iova fault:
438 */
439
440 static void
decode_fault_info(void)441 decode_fault_info(void)
442 {
443 foreach_line_in_section (line) {
444 if (startswith(line, " - far:")) {
445 parseline(line, " - far: %" PRIx64, &fault_iova);
446 has_fault_iova = true;
447 }
448
449 printf("%s", line);
450 }
451 }
452
453 /*
454 * Decode 'bos' (buffers) section:
455 */
456
457 static void
decode_bos(void)458 decode_bos(void)
459 {
460 uint32_t size = 0;
461 uint64_t iova = 0;
462
463 foreach_line_in_section (line) {
464 if (startswith(line, " - iova:")) {
465 parseline(line, " - iova: %" PRIx64, &iova);
466 continue;
467 } else if (startswith(line, " size:")) {
468 parseline(line, " size: %u", &size);
469
470 /*
471 * This is a bit convoluted, vs just printing the lines as
472 * they come. But we want to have both the iova and size
473 * so we can print the end address of the buffer
474 */
475
476 uint64_t end = iova + size;
477
478 printf(" - iova: 0x%016" PRIx64 "-0x%016" PRIx64, iova, end);
479
480 if (has_fault_iova) {
481 if ((iova <= fault_iova) && (fault_iova < end)) {
482 /* Fault address was within what should be a mapped buffer!! */
483 printf("\t==");
484 } else if ((iova <= fault_iova) && (fault_iova < (end + size))) {
485 /* Fault address was near this mapped buffer */
486 printf("\t>=");
487 }
488 }
489 printf("\n");
490 printf(" size: %u (0x%x)\n", size, size);
491 continue;
492 } else if (startswith(line, " data: !!ascii85 |")) {
493 uint32_t *buf = popline_ascii85(size / 4);
494
495 if (verbose)
496 dump_hex_ascii(buf, size, 1);
497
498 add_buffer(iova, size, buf);
499
500 continue;
501 }
502
503 printf("%s", line);
504 }
505 }
506
507 /*
508 * Decode registers section:
509 */
510
511 void
dump_register(struct regacc * r)512 dump_register(struct regacc *r)
513 {
514 struct rnndecaddrinfo *info = rnn_reginfo(r->rnn, r->regbase);
515 if (info && info->typeinfo) {
516 char *decoded = rnndec_decodeval(r->rnn->vc, info->typeinfo, r->value);
517 printf("%s: %s\n", info->name, decoded);
518 } else if (info) {
519 printf("%s: %08"PRIx64"\n", info->name, r->value);
520 } else {
521 printf("<%04x>: %08"PRIx64"\n", r->regbase, r->value);
522 }
523 rnn_reginfo_free(info);
524 }
525
526 static void
decode_gmu_registers(void)527 decode_gmu_registers(void)
528 {
529 struct regacc r = regacc(rnn_gmu);
530
531 foreach_line_in_section (line) {
532 uint32_t offset, value;
533 parseline(line, " - { offset: %x, value: %x }", &offset, &value);
534
535 if (regacc_push(&r, offset / 4, value)) {
536 printf("\t%08"PRIx64"\t", r.value);
537 dump_register(&r);
538 }
539 }
540 }
541
542 static void
decode_registers(void)543 decode_registers(void)
544 {
545 struct regacc r = regacc(NULL);
546
547 foreach_line_in_section (line) {
548 uint32_t offset, value;
549 parseline(line, " - { offset: %x, value: %x }", &offset, &value);
550
551 reg_set(offset / 4, value);
552 if (regacc_push(&r, offset / 4, value)) {
553 printf("\t%08"PRIx64, r.value);
554 dump_register_val(&r, 0);
555 }
556 }
557 }
558
559 /* similar to registers section, but for banked context regs: */
560 static void
decode_clusters(void)561 decode_clusters(void)
562 {
563 struct regacc r = regacc(NULL);
564
565 foreach_line_in_section (line) {
566 if (startswith(line, " - cluster-name:") ||
567 startswith(line, " - context:")) {
568 printf("%s", line);
569 continue;
570 }
571
572 uint32_t offset, value;
573 parseline(line, " - { offset: %x, value: %x }", &offset, &value);
574
575 if (regacc_push(&r, offset / 4, value)) {
576 printf("\t%08"PRIx64, r.value);
577 dump_register_val(&r, 0);
578 }
579 }
580 }
581
582 /*
583 * Decode indexed-registers.. these aren't like normal registers, but a
584 * sort of FIFO where successive reads pop out associated debug state.
585 */
586
587 static void
dump_cp_sqe_stat(uint32_t * stat)588 dump_cp_sqe_stat(uint32_t *stat)
589 {
590 printf("\t PC: %04x\n", stat[0]);
591 stat++;
592
593 if (is_a6xx() && valid_header(stat[0])) {
594 if (pkt_is_type7(stat[0])) {
595 unsigned opc = cp_type7_opcode(stat[0]);
596 const char *name = pktname(opc);
597 if (name)
598 printf("\tPKT: %s\n", name);
599 } else {
600 /* Not sure if this case can happen: */
601 }
602 }
603
604 for (int i = 0; i < 16; i++) {
605 printf("\t$%02x: %08x\t\t$%02x: %08x\n", i + 1, stat[i], i + 16 + 1,
606 stat[i + 16]);
607 }
608 }
609
610 static void
dump_control_regs(uint32_t * regs)611 dump_control_regs(uint32_t *regs)
612 {
613 if (!rnn_control)
614 return;
615
616 struct regacc r = regacc(rnn_control);
617
618 /* Control regs 0x100-0x17f are a scratch space to be used by the
619 * firmware however it wants, unlike lower regs which involve some
620 * fixed-function units. Therefore only these registers get dumped
621 * directly.
622 */
623 for (uint32_t i = 0; i < 0x80; i++) {
624 if (regacc_push(&r, i + 0x100, regs[i])) {
625 printf("\t%08"PRIx64"\t", r.value);
626 dump_register(&r);
627 }
628 }
629 }
630
631 static void
dump_cp_ucode_dbg(uint32_t * dbg)632 dump_cp_ucode_dbg(uint32_t *dbg)
633 {
634 /* Notes on the data:
635 * There seems to be a section every 4096 DWORD's. The sections aren't
636 * all the same size, so the rest of the 4096 DWORD's are filled with
637 * mirrors of the actual data.
638 */
639
640 for (int section = 0; section < 6; section++, dbg += 0x1000) {
641 switch (section) {
642 case 0:
643 /* Contains scattered data from a630_sqe.fw: */
644 printf("\tSQE instruction cache:\n");
645 dump_hex_ascii(dbg, 4 * 0x400, 1);
646 break;
647 case 1:
648 printf("\tUnknown 1:\n");
649 dump_hex_ascii(dbg, 4 * 0x80, 1);
650 break;
651 case 2:
652 printf("\tUnknown 2:\n");
653 dump_hex_ascii(dbg, 4 * 0x200, 1);
654 break;
655 case 3:
656 printf("\tUnknown 3:\n");
657 dump_hex_ascii(dbg, 4 * 0x80, 1);
658 break;
659 case 4:
660 /* Don't bother printing this normally */
661 if (verbose) {
662 printf("\tSQE packet jumptable contents:\n");
663 dump_hex_ascii(dbg, 4 * 0x80, 1);
664 }
665 break;
666 case 5:
667 printf("\tSQE scratch control regs:\n");
668 dump_control_regs(dbg);
669 break;
670 }
671 }
672 }
673
674 static void
decode_indexed_registers(void)675 decode_indexed_registers(void)
676 {
677 char *name = NULL;
678 uint32_t sizedwords = 0;
679
680 foreach_line_in_section (line) {
681 if (startswith(line, " - regs-name:")) {
682 free(name);
683 parseline(line, " - regs-name: %ms", &name);
684 } else if (startswith(line, " dwords:")) {
685 parseline(line, " dwords: %u", &sizedwords);
686 } else if (startswith(line, " data: !!ascii85 |")) {
687 uint32_t *buf = popline_ascii85(sizedwords);
688
689 /* some of the sections are pretty large, and are (at least
690 * so far) not useful, so skip them if not in verbose mode:
691 */
692 bool dump = verbose || !strcmp(name, "CP_SQE_STAT") ||
693 !strcmp(name, "CP_DRAW_STATE") ||
694 !strcmp(name, "CP_ROQ") || 0;
695
696 if (!strcmp(name, "CP_SQE_STAT"))
697 dump_cp_sqe_stat(buf);
698
699 if (!strcmp(name, "CP_UCODE_DBG_DATA"))
700 dump_cp_ucode_dbg(buf);
701
702 if (!strcmp(name, "CP_MEMPOOL"))
703 dump_cp_mem_pool(buf);
704
705 if (dump)
706 dump_hex_ascii(buf, 4 * sizedwords, 1);
707
708 free(buf);
709
710 continue;
711 }
712
713 printf("%s", line);
714 }
715 }
716
717 /*
718 * Decode shader-blocks:
719 */
720
721 static void
decode_shader_blocks(void)722 decode_shader_blocks(void)
723 {
724 char *type = NULL;
725 uint32_t sizedwords = 0;
726
727 foreach_line_in_section (line) {
728 if (startswith(line, " - type:")) {
729 free(type);
730 parseline(line, " - type: %ms", &type);
731 } else if (startswith(line, " size:")) {
732 parseline(line, " size: %u", &sizedwords);
733 } else if (startswith(line, " data: !!ascii85 |")) {
734 uint32_t *buf = popline_ascii85(sizedwords);
735
736 /* some of the sections are pretty large, and are (at least
737 * so far) not useful, so skip them if not in verbose mode:
738 */
739 bool dump = verbose || !strcmp(type, "A6XX_SP_INST_DATA") ||
740 !strcmp(type, "A6XX_HLSQ_INST_RAM") || 0;
741
742 if (!strcmp(type, "A6XX_SP_INST_DATA") ||
743 !strcmp(type, "A6XX_HLSQ_INST_RAM")) {
744 /* TODO this section actually contains multiple shaders
745 * (or parts of shaders?), so perhaps we should search
746 * for ends of shaders and decode each?
747 */
748 try_disasm_a3xx(buf, sizedwords, 1, stdout, options.info->chip * 100);
749 }
750
751 if (dump)
752 dump_hex_ascii(buf, 4 * sizedwords, 1);
753
754 free(buf);
755
756 continue;
757 }
758
759 printf("%s", line);
760 }
761
762 free(type);
763 }
764
765 /*
766 * Decode debugbus section:
767 */
768
769 static void
decode_debugbus(void)770 decode_debugbus(void)
771 {
772 char *block = NULL;
773 uint32_t sizedwords = 0;
774
775 foreach_line_in_section (line) {
776 if (startswith(line, " - debugbus-block:")) {
777 free(block);
778 parseline(line, " - debugbus-block: %ms", &block);
779 } else if (startswith(line, " count:")) {
780 parseline(line, " count: %u", &sizedwords);
781 } else if (startswith(line, " data: !!ascii85 |")) {
782 uint32_t *buf = popline_ascii85(sizedwords);
783
784 /* some of the sections are pretty large, and are (at least
785 * so far) not useful, so skip them if not in verbose mode:
786 */
787 bool dump = verbose || 0;
788
789 if (dump)
790 dump_hex_ascii(buf, 4 * sizedwords, 1);
791
792 free(buf);
793
794 continue;
795 }
796
797 printf("%s", line);
798 }
799 }
800
801 /*
802 * Main crashdump decode loop:
803 */
804
805 static void
decode(void)806 decode(void)
807 {
808 const char *line;
809
810 while ((line = popline())) {
811 printf("%s", line);
812 if (startswith(line, "revision:")) {
813 unsigned core, major, minor, patchid;
814
815 parseline(line, "revision: %u (%u.%u.%u.%u)", &options.dev_id.gpu_id,
816 &core, &major, &minor, &patchid);
817
818 options.dev_id.chip_id = (core << 24) | (major << 16) | (minor << 8) | patchid;
819 options.info = fd_dev_info_raw(&options.dev_id);
820 if (!options.info) {
821 printf("Unsupported device\n");
822 break;
823 }
824
825 printf("Got chip_id=0x%"PRIx64"\n", options.dev_id.chip_id);
826
827 cffdec_init(&options);
828
829 if (is_a6xx()) {
830 rnn_gmu = rnn_new(!options.color);
831 rnn_load_file(rnn_gmu, "adreno/a6xx_gmu.xml", "A6XX");
832 rnn_control = rnn_new(!options.color);
833 rnn_load_file(rnn_control, "adreno/adreno_control_regs.xml",
834 "A6XX_CONTROL_REG");
835 rnn_pipe = rnn_new(!options.color);
836 rnn_load_file(rnn_pipe, "adreno/adreno_pipe_regs.xml",
837 "A6XX_PIPE_REG");
838 } else if (is_a5xx()) {
839 rnn_control = rnn_new(!options.color);
840 rnn_load_file(rnn_control, "adreno/adreno_control_regs.xml",
841 "A5XX_CONTROL_REG");
842 } else {
843 rnn_control = NULL;
844 }
845 } else if (startswith(line, "fault-info:")) {
846 decode_fault_info();
847 } else if (startswith(line, "bos:")) {
848 decode_bos();
849 } else if (startswith(line, "ringbuffer:")) {
850 decode_ringbuffer();
851 } else if (startswith(line, "gmu-log:")) {
852 decode_gmu_log();
853 } else if (startswith(line, "gmu-hfi:")) {
854 decode_gmu_hfi();
855 } else if (startswith(line, "registers:")) {
856 decode_registers();
857
858 /* after we've recorded buffer contents, and CP register values,
859 * we can take a stab at decoding the cmdstream:
860 */
861 dump_cmdstream();
862 } else if (startswith(line, "registers-gmu:")) {
863 decode_gmu_registers();
864 } else if (startswith(line, "indexed-registers:")) {
865 decode_indexed_registers();
866 } else if (startswith(line, "shader-blocks:")) {
867 decode_shader_blocks();
868 } else if (startswith(line, "clusters:")) {
869 decode_clusters();
870 } else if (startswith(line, "debugbus:")) {
871 decode_debugbus();
872 }
873 }
874 }
875
876 /*
877 * Usage and argument parsing:
878 */
879
880 static void
usage(void)881 usage(void)
882 {
883 /* clang-format off */
884 fprintf(stderr, "Usage:\n\n"
885 "\tcrashdec [-achmsv] [-f FILE]\n\n"
886 "Options:\n"
887 "\t-a, --allregs - show all registers (including ones not written since\n"
888 "\t previous draw) at each draw\n"
889 "\t-c, --color - use colors\n"
890 "\t-f, --file=FILE - read input from specified file (rather than stdin)\n"
891 "\t-h, --help - this usage message\n"
892 "\t-m, --markers - try to decode CP_NOP string markers\n"
893 "\t-s, --summary - don't show individual register writes, but just show\n"
894 "\t register values on draws\n"
895 "\t-v, --verbose - dump more verbose output, including contents of\n"
896 "\t less interesting buffers\n"
897 "\n"
898 );
899 /* clang-format on */
900 exit(2);
901 }
902
903 /* clang-format off */
904 static const struct option opts[] = {
905 { .name = "allregs", .has_arg = 0, NULL, 'a' },
906 { .name = "color", .has_arg = 0, NULL, 'c' },
907 { .name = "file", .has_arg = 1, NULL, 'f' },
908 { .name = "help", .has_arg = 0, NULL, 'h' },
909 { .name = "markers", .has_arg = 0, NULL, 'm' },
910 { .name = "summary", .has_arg = 0, NULL, 's' },
911 { .name = "verbose", .has_arg = 0, NULL, 'v' },
912 {}
913 };
914 /* clang-format on */
915
916 static bool interactive;
917
918 static void
cleanup(void)919 cleanup(void)
920 {
921 fflush(stdout);
922
923 if (interactive) {
924 pager_close();
925 }
926 }
927
928 int
main(int argc,char ** argv)929 main(int argc, char **argv)
930 {
931 int c;
932
933 interactive = isatty(STDOUT_FILENO);
934 options.color = interactive;
935
936 /* default to read from stdin: */
937 in = stdin;
938
939 while ((c = getopt_long(argc, argv, "acf:hmsv", opts, NULL)) != -1) {
940 switch (c) {
941 case 'a':
942 options.allregs = true;
943 break;
944 case 'c':
945 options.color = true;
946 break;
947 case 'f':
948 in = fopen(optarg, "r");
949 break;
950 case 'm':
951 options.decode_markers = true;
952 break;
953 case 's':
954 options.summary = true;
955 break;
956 case 'v':
957 verbose = true;
958 break;
959 case 'h':
960 default:
961 usage();
962 }
963 }
964
965 disasm_a3xx_set_debug(PRINT_RAW);
966
967 if (interactive) {
968 pager_open();
969 }
970
971 atexit(cleanup);
972
973 decode();
974 cleanup();
975 }
976