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