• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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