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