tree-wide: replace MAYBE_UNUSED with ASSERTED
[mesa.git] / src / intel / tools / aubinator_error_decode.c
1 /*
2 * Copyright © 2007-2017 Intel Corporation
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <err.h>
37 #include <assert.h>
38 #include <getopt.h>
39 #include <zlib.h>
40
41 #include "common/gen_decoder.h"
42 #include "util/macros.h"
43
44 #define CSI "\e["
45 #define BLUE_HEADER CSI "0;44m"
46 #define GREEN_HEADER CSI "1;42m"
47 #define NORMAL CSI "0m"
48
49 #define MIN(a, b) ((a) < (b) ? (a) : (b))
50
51 /* options */
52
53 static bool option_full_decode = true;
54 static bool option_print_all_bb = false;
55 static bool option_print_offsets = true;
56 static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;
57 static char *xml_path = NULL;
58
59 static uint32_t
60 print_head(unsigned int reg)
61 {
62 printf(" head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21);
63 return reg & (0x7ffff<<2);
64 }
65
66 static void
67 print_register(struct gen_spec *spec, const char *name, uint32_t reg)
68 {
69 struct gen_group *reg_spec =
70 name ? gen_spec_find_register_by_name(spec, name) : NULL;
71
72 if (reg_spec) {
73 gen_print_group(stdout, reg_spec, 0, &reg, 0,
74 option_color == COLOR_ALWAYS);
75 }
76 }
77
78 struct ring_register_mapping {
79 enum drm_i915_gem_engine_class ring_class;
80 unsigned ring_instance;
81 const char *register_name;
82 };
83
84 static const struct ring_register_mapping acthd_registers[] = {
85 { I915_ENGINE_CLASS_COPY, 0, "BCS_ACTHD_UDW" },
86 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_ACTHD_UDW" },
87 { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_ACTHD_UDW" },
88 { I915_ENGINE_CLASS_RENDER, 0, "ACTHD_UDW" },
89 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_ACTHD_UDW" },
90 };
91
92 static const struct ring_register_mapping ctl_registers[] = {
93 { I915_ENGINE_CLASS_COPY, 0, "BCS_RING_BUFFER_CTL" },
94 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_RING_BUFFER_CTL" },
95 { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_RING_BUFFER_CTL" },
96 { I915_ENGINE_CLASS_RENDER, 0, "RCS_RING_BUFFER_CTL" },
97 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_RING_BUFFER_CTL" },
98 };
99
100 static const struct ring_register_mapping fault_registers[] = {
101 { I915_ENGINE_CLASS_COPY, 0, "BCS_FAULT_REG" },
102 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_FAULT_REG" },
103 { I915_ENGINE_CLASS_RENDER, 0, "RCS_FAULT_REG" },
104 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_FAULT_REG" },
105 };
106
107 static int ring_name_to_class(const char *ring_name,
108 enum drm_i915_gem_engine_class *class)
109 {
110 static const char *class_names[] = {
111 [I915_ENGINE_CLASS_RENDER] = "rcs",
112 [I915_ENGINE_CLASS_COPY] = "bcs",
113 [I915_ENGINE_CLASS_VIDEO] = "vcs",
114 [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "vecs",
115 };
116 for (size_t i = 0; i < ARRAY_SIZE(class_names); i++) {
117 if (strncmp(ring_name, class_names[i], strlen(class_names[i])))
118 continue;
119
120 *class = i;
121 return atoi(ring_name + strlen(class_names[i]));
122 }
123
124 static const struct {
125 const char *name;
126 unsigned int class;
127 int instance;
128 } legacy_names[] = {
129 { "render", I915_ENGINE_CLASS_RENDER, 0 },
130 { "blt", I915_ENGINE_CLASS_COPY, 0 },
131 { "bsd", I915_ENGINE_CLASS_VIDEO, 0 },
132 { "bsd2", I915_ENGINE_CLASS_VIDEO, 1 },
133 { "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE, 0 },
134 };
135 for (size_t i = 0; i < ARRAY_SIZE(legacy_names); i++) {
136 if (strcmp(ring_name, legacy_names[i].name))
137 continue;
138
139 *class = legacy_names[i].class;
140 return legacy_names[i].instance;
141 }
142
143 return -1;
144 }
145
146 static const char *
147 register_name_from_ring(const struct ring_register_mapping *mapping,
148 unsigned nb_mapping,
149 const char *ring_name)
150 {
151 enum drm_i915_gem_engine_class class;
152 int instance;
153
154 instance = ring_name_to_class(ring_name, &class);
155 if (instance < 0)
156 return NULL;
157
158 for (unsigned i = 0; i < nb_mapping; i++) {
159 if (mapping[i].ring_class == class &&
160 mapping[i].ring_instance == instance)
161 return mapping[i].register_name;
162 }
163 return NULL;
164 }
165
166 static const char *
167 instdone_register_for_ring(const struct gen_device_info *devinfo,
168 const char *ring_name)
169 {
170 enum drm_i915_gem_engine_class class;
171 int instance;
172
173 instance = ring_name_to_class(ring_name, &class);
174 if (instance < 0)
175 return NULL;
176
177 switch (class) {
178 case I915_ENGINE_CLASS_RENDER:
179 if (devinfo->gen == 6)
180 return "INSTDONE_2";
181 else
182 return "INSTDONE_1";
183
184 case I915_ENGINE_CLASS_COPY:
185 return "BCS_INSTDONE";
186
187 case I915_ENGINE_CLASS_VIDEO:
188 switch (instance) {
189 case 0:
190 return "VCS_INSTDONE";
191 case 1:
192 return "VCS2_INSTDONE";
193 default:
194 return NULL;
195 }
196
197 case I915_ENGINE_CLASS_VIDEO_ENHANCE:
198 return "VECS_INSTDONE";
199
200 default:
201 return NULL;
202 }
203
204 return NULL;
205 }
206
207 static void
208 print_pgtbl_err(unsigned int reg, struct gen_device_info *devinfo)
209 {
210 if (reg & (1 << 26))
211 printf(" Invalid Sampler Cache GTT entry\n");
212 if (reg & (1 << 24))
213 printf(" Invalid Render Cache GTT entry\n");
214 if (reg & (1 << 23))
215 printf(" Invalid Instruction/State Cache GTT entry\n");
216 if (reg & (1 << 22))
217 printf(" There is no ROC, this cannot occur!\n");
218 if (reg & (1 << 21))
219 printf(" Invalid GTT entry during Vertex Fetch\n");
220 if (reg & (1 << 20))
221 printf(" Invalid GTT entry during Command Fetch\n");
222 if (reg & (1 << 19))
223 printf(" Invalid GTT entry during CS\n");
224 if (reg & (1 << 18))
225 printf(" Invalid GTT entry during Cursor Fetch\n");
226 if (reg & (1 << 17))
227 printf(" Invalid GTT entry during Overlay Fetch\n");
228 if (reg & (1 << 8))
229 printf(" Invalid GTT entry during Display B Fetch\n");
230 if (reg & (1 << 4))
231 printf(" Invalid GTT entry during Display A Fetch\n");
232 if (reg & (1 << 1))
233 printf(" Valid PTE references illegal memory\n");
234 if (reg & (1 << 0))
235 printf(" Invalid GTT entry during fetch for host\n");
236 }
237
238 static void
239 print_snb_fence(struct gen_device_info *devinfo, uint64_t fence)
240 {
241 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
242 fence & 1 ? "" : "in",
243 fence & (1<<1) ? 'y' : 'x',
244 (int)(((fence>>32)&0xfff)+1)*128,
245 (uint32_t)fence & 0xfffff000,
246 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
247 }
248
249 static void
250 print_i965_fence(struct gen_device_info *devinfo, uint64_t fence)
251 {
252 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
253 fence & 1 ? "" : "in",
254 fence & (1<<1) ? 'y' : 'x',
255 (int)(((fence>>2)&0x1ff)+1)*128,
256 (uint32_t)fence & 0xfffff000,
257 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
258 }
259
260 static void
261 print_fence(struct gen_device_info *devinfo, uint64_t fence)
262 {
263 if (devinfo->gen == 6 || devinfo->gen == 7) {
264 return print_snb_fence(devinfo, fence);
265 } else if (devinfo->gen == 4 || devinfo->gen == 5) {
266 return print_i965_fence(devinfo, fence);
267 }
268 }
269
270 static void
271 print_fault_data(struct gen_device_info *devinfo, uint32_t data1, uint32_t data0)
272 {
273 uint64_t address;
274
275 if (devinfo->gen < 8)
276 return;
277
278 address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;
279 printf(" Address 0x%016" PRIx64 " %s\n", address,
280 data1 & (1 << 4) ? "GGTT" : "PPGTT");
281 }
282
283 #define CSI "\e["
284 #define NORMAL CSI "0m"
285
286 struct section {
287 uint64_t gtt_offset;
288 char *ring_name;
289 const char *buffer_name;
290 uint32_t *data;
291 int dword_count;
292 };
293
294 #define MAX_SECTIONS 256
295 static unsigned num_sections;
296 static struct section sections[MAX_SECTIONS];
297
298 static int zlib_inflate(uint32_t **ptr, int len)
299 {
300 struct z_stream_s zstream;
301 void *out;
302 const uint32_t out_size = 128*4096; /* approximate obj size */
303
304 memset(&zstream, 0, sizeof(zstream));
305
306 zstream.next_in = (unsigned char *)*ptr;
307 zstream.avail_in = 4*len;
308
309 if (inflateInit(&zstream) != Z_OK)
310 return 0;
311
312 out = malloc(out_size);
313 zstream.next_out = out;
314 zstream.avail_out = out_size;
315
316 do {
317 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
318 case Z_STREAM_END:
319 goto end;
320 case Z_OK:
321 break;
322 default:
323 inflateEnd(&zstream);
324 return 0;
325 }
326
327 if (zstream.avail_out)
328 break;
329
330 out = realloc(out, 2*zstream.total_out);
331 if (out == NULL) {
332 inflateEnd(&zstream);
333 return 0;
334 }
335
336 zstream.next_out = (unsigned char *)out + zstream.total_out;
337 zstream.avail_out = zstream.total_out;
338 } while (1);
339 end:
340 inflateEnd(&zstream);
341 free(*ptr);
342 *ptr = out;
343 return zstream.total_out / 4;
344 }
345
346 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
347 {
348 int len = 0, size = 1024;
349
350 *out = realloc(*out, sizeof(uint32_t)*size);
351 if (*out == NULL)
352 return 0;
353
354 while (*in >= '!' && *in <= 'z') {
355 uint32_t v = 0;
356
357 if (len == size) {
358 size *= 2;
359 *out = realloc(*out, sizeof(uint32_t)*size);
360 if (*out == NULL)
361 return 0;
362 }
363
364 if (*in == 'z') {
365 in++;
366 } else {
367 v += in[0] - 33; v *= 85;
368 v += in[1] - 33; v *= 85;
369 v += in[2] - 33; v *= 85;
370 v += in[3] - 33; v *= 85;
371 v += in[4] - 33;
372 in += 5;
373 }
374 (*out)[len++] = v;
375 }
376
377 if (!inflate)
378 return len;
379
380 return zlib_inflate(out, len);
381 }
382
383 static struct gen_batch_decode_bo
384 get_gen_batch_bo(void *user_data, bool ppgtt, uint64_t address)
385 {
386 for (int s = 0; s < num_sections; s++) {
387 if (sections[s].gtt_offset <= address &&
388 address < sections[s].gtt_offset + sections[s].dword_count * 4) {
389 return (struct gen_batch_decode_bo) {
390 .addr = sections[s].gtt_offset,
391 .map = sections[s].data,
392 .size = sections[s].dword_count * 4,
393 };
394 }
395 }
396
397 return (struct gen_batch_decode_bo) { .map = NULL };
398 }
399
400 static void
401 read_data_file(FILE *file)
402 {
403 struct gen_spec *spec = NULL;
404 long long unsigned fence;
405 int matched;
406 char *line = NULL;
407 size_t line_size;
408 uint32_t offset, value;
409 char *ring_name = NULL;
410 struct gen_device_info devinfo;
411
412 while (getline(&line, &line_size, file) > 0) {
413 char *new_ring_name = NULL;
414 char *dashes;
415
416 if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {
417 free(ring_name);
418 ring_name = new_ring_name;
419 }
420
421 if (line[0] == ':' || line[0] == '~') {
422 uint32_t *data = NULL;
423 int dword_count = ascii85_decode(line+1, &data, line[0] == ':');
424 if (dword_count == 0) {
425 fprintf(stderr, "ASCII85 decode failed.\n");
426 exit(EXIT_FAILURE);
427 }
428 assert(num_sections < MAX_SECTIONS);
429 sections[num_sections].data = data;
430 sections[num_sections].dword_count = dword_count;
431 num_sections++;
432 continue;
433 }
434
435 dashes = strstr(line, "---");
436 if (dashes) {
437 const struct {
438 const char *match;
439 const char *name;
440 } buffers[] = {
441 { "ringbuffer", "ring buffer" },
442 { "gtt_offset", "batch buffer" },
443 { "hw context", "HW Context" },
444 { "hw status", "HW status" },
445 { "wa context", "WA context" },
446 { "wa batchbuffer", "WA batch" },
447 { "NULL context", "Kernel context" },
448 { "user", "user" },
449 { "semaphores", "semaphores", },
450 { "guc log buffer", "GuC log", },
451 { NULL, "unknown" },
452 }, *b;
453
454 free(ring_name);
455 ring_name = malloc(dashes - line);
456 strncpy(ring_name, line, dashes - line);
457 ring_name[dashes - line - 1] = '\0';
458
459 dashes += 4;
460 for (b = buffers; b->match; b++) {
461 if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)
462 break;
463 }
464
465 assert(num_sections < MAX_SECTIONS);
466 sections[num_sections].buffer_name = b->name;
467 sections[num_sections].ring_name = strdup(ring_name);
468
469 uint32_t hi, lo;
470 dashes = strchr(dashes, '=');
471 if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo))
472 sections[num_sections].gtt_offset = ((uint64_t) hi) << 32 | lo;
473
474 continue;
475 }
476
477 matched = sscanf(line, "%08x : %08x", &offset, &value);
478 if (matched != 2) {
479 uint32_t reg, reg2;
480
481 /* display reg section is after the ringbuffers, don't mix them */
482 printf("%s", line);
483
484 matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
485 if (matched == 0)
486 matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
487 if (matched == 0) {
488 const char *pci_id_start = strstr(line, "PCI ID");
489 if (pci_id_start)
490 matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
491 }
492 if (matched == 1) {
493 if (!gen_get_device_info(reg, &devinfo)) {
494 printf("Unable to identify devid=%x\n", reg);
495 exit(EXIT_FAILURE);
496 }
497
498 printf("Detected GEN%i chipset\n", devinfo.gen);
499
500 if (xml_path == NULL)
501 spec = gen_spec_load(&devinfo);
502 else
503 spec = gen_spec_load_from_path(&devinfo, xml_path);
504 }
505
506 matched = sscanf(line, " CTL: 0x%08x\n", &reg);
507 if (matched == 1) {
508 print_register(spec,
509 register_name_from_ring(ctl_registers,
510 ARRAY_SIZE(ctl_registers),
511 ring_name), reg);
512 }
513
514 matched = sscanf(line, " HEAD: 0x%08x\n", &reg);
515 if (matched == 1)
516 print_head(reg);
517
518 matched = sscanf(line, " ACTHD: 0x%08x\n", &reg);
519 if (matched == 1) {
520 print_register(spec,
521 register_name_from_ring(acthd_registers,
522 ARRAY_SIZE(acthd_registers),
523 ring_name), reg);
524 }
525
526 matched = sscanf(line, " PGTBL_ER: 0x%08x\n", &reg);
527 if (matched == 1 && reg)
528 print_pgtbl_err(reg, &devinfo);
529
530 matched = sscanf(line, " ERROR: 0x%08x\n", &reg);
531 if (matched == 1 && reg) {
532 print_register(spec, "GFX_ARB_ERROR_RPT", reg);
533 }
534
535 matched = sscanf(line, " INSTDONE: 0x%08x\n", &reg);
536 if (matched == 1) {
537 const char *reg_name =
538 instdone_register_for_ring(&devinfo, ring_name);
539 if (reg_name)
540 print_register(spec, reg_name, reg);
541 }
542
543 matched = sscanf(line, " SC_INSTDONE: 0x%08x\n", &reg);
544 if (matched == 1)
545 print_register(spec, "SC_INSTDONE", reg);
546
547 matched = sscanf(line, " SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", &reg);
548 if (matched == 1)
549 print_register(spec, "SAMPLER_INSTDONE", reg);
550
551 matched = sscanf(line, " ROW_INSTDONE[%*d][%*d]: 0x%08x\n", &reg);
552 if (matched == 1)
553 print_register(spec, "ROW_INSTDONE", reg);
554
555 matched = sscanf(line, " INSTDONE1: 0x%08x\n", &reg);
556 if (matched == 1)
557 print_register(spec, "INSTDONE_1", reg);
558
559 matched = sscanf(line, " fence[%i] = %Lx\n", &reg, &fence);
560 if (matched == 2)
561 print_fence(&devinfo, fence);
562
563 matched = sscanf(line, " FAULT_REG: 0x%08x\n", &reg);
564 if (matched == 1 && reg) {
565 const char *reg_name =
566 register_name_from_ring(fault_registers,
567 ARRAY_SIZE(fault_registers),
568 ring_name);
569 if (reg_name == NULL)
570 reg_name = "FAULT_REG";
571 print_register(spec, reg_name, reg);
572 }
573
574 matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
575 if (matched == 2)
576 print_fault_data(&devinfo, reg, reg2);
577
578 continue;
579 }
580 }
581
582 free(line);
583 free(ring_name);
584
585 enum gen_batch_decode_flags batch_flags = 0;
586 if (option_color == COLOR_ALWAYS)
587 batch_flags |= GEN_BATCH_DECODE_IN_COLOR;
588 if (option_full_decode)
589 batch_flags |= GEN_BATCH_DECODE_FULL;
590 if (option_print_offsets)
591 batch_flags |= GEN_BATCH_DECODE_OFFSETS;
592 batch_flags |= GEN_BATCH_DECODE_FLOATS;
593
594 struct gen_batch_decode_ctx batch_ctx;
595 gen_batch_decode_ctx_init(&batch_ctx, &devinfo, stdout, batch_flags,
596 xml_path, get_gen_batch_bo, NULL, NULL);
597
598
599 for (int s = 0; s < num_sections; s++) {
600 enum drm_i915_gem_engine_class class;
601 ring_name_to_class(sections[s].ring_name, &class);
602
603 printf("--- %s (%s) at 0x%08x %08x\n",
604 sections[s].buffer_name, sections[s].ring_name,
605 (unsigned) (sections[s].gtt_offset >> 32),
606 (unsigned) sections[s].gtt_offset);
607
608 if (option_print_all_bb ||
609 strcmp(sections[s].buffer_name, "batch buffer") == 0 ||
610 strcmp(sections[s].buffer_name, "ring buffer") == 0 ||
611 strcmp(sections[s].buffer_name, "HW Context") == 0) {
612 batch_ctx.engine = class;
613 gen_print_batch(&batch_ctx, sections[s].data,
614 sections[s].dword_count * 4,
615 sections[s].gtt_offset, false);
616 }
617 }
618
619 gen_batch_decode_ctx_finish(&batch_ctx);
620
621 for (int s = 0; s < num_sections; s++) {
622 free(sections[s].ring_name);
623 free(sections[s].data);
624 }
625 }
626
627 static void
628 setup_pager(void)
629 {
630 int fds[2];
631 pid_t pid;
632
633 if (!isatty(1))
634 return;
635
636 if (pipe(fds) == -1)
637 return;
638
639 pid = fork();
640 if (pid == -1)
641 return;
642
643 if (pid == 0) {
644 close(fds[1]);
645 dup2(fds[0], 0);
646 execlp("less", "less", "-FRSi", NULL);
647 }
648
649 close(fds[0]);
650 dup2(fds[1], 1);
651 close(fds[1]);
652 }
653
654 static void
655 print_help(const char *progname, FILE *file)
656 {
657 fprintf(file,
658 "Usage: %s [OPTION]... [FILE]\n"
659 "Parse an Intel GPU i915_error_state.\n"
660 "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
661 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"
662 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
663 " --help display this help and exit\n"
664 " --headers decode only command headers\n"
665 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
666 " if omitted), 'always', or 'never'\n"
667 " --no-pager don't launch pager\n"
668 " --no-offsets don't print instruction offsets\n"
669 " --xml=DIR load hardware xml description from directory DIR\n"
670 " --all-bb print out all batchbuffers\n",
671 progname);
672 }
673
674 int
675 main(int argc, char *argv[])
676 {
677 FILE *file;
678 const char *path;
679 struct stat st;
680 int c, i, error;
681 bool help = false, pager = true;
682 const struct option aubinator_opts[] = {
683 { "help", no_argument, (int *) &help, true },
684 { "no-pager", no_argument, (int *) &pager, false },
685 { "no-offsets", no_argument, (int *) &option_print_offsets, false },
686 { "headers", no_argument, (int *) &option_full_decode, false },
687 { "color", required_argument, NULL, 'c' },
688 { "xml", required_argument, NULL, 'x' },
689 { "all-bb", no_argument, (int *) &option_print_all_bb, true },
690 { NULL, 0, NULL, 0 }
691 };
692
693 i = 0;
694 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
695 switch (c) {
696 case 'c':
697 if (optarg == NULL || strcmp(optarg, "always") == 0)
698 option_color = COLOR_ALWAYS;
699 else if (strcmp(optarg, "never") == 0)
700 option_color = COLOR_NEVER;
701 else if (strcmp(optarg, "auto") == 0)
702 option_color = COLOR_AUTO;
703 else {
704 fprintf(stderr, "invalid value for --color: %s", optarg);
705 exit(EXIT_FAILURE);
706 }
707 break;
708 case 'x':
709 xml_path = strdup(optarg);
710 break;
711 default:
712 break;
713 }
714 }
715
716 if (help || argc == 1) {
717 print_help(argv[0], stderr);
718 exit(EXIT_SUCCESS);
719 }
720
721 if (optind >= argc) {
722 if (isatty(0)) {
723 path = "/sys/class/drm/card0/error";
724 error = stat(path, &st);
725 if (error != 0) {
726 path = "/debug/dri";
727 error = stat(path, &st);
728 }
729 if (error != 0) {
730 path = "/sys/kernel/debug/dri";
731 error = stat(path, &st);
732 }
733 if (error != 0) {
734 errx(1,
735 "Couldn't find i915 debugfs directory.\n\n"
736 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
737 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
738 }
739 } else {
740 read_data_file(stdin);
741 exit(EXIT_SUCCESS);
742 }
743 } else {
744 path = argv[optind];
745 error = stat(path, &st);
746 if (error != 0) {
747 fprintf(stderr, "Error opening %s: %s\n",
748 path, strerror(errno));
749 exit(EXIT_FAILURE);
750 }
751 }
752
753 if (option_color == COLOR_AUTO)
754 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
755
756 if (isatty(1) && pager)
757 setup_pager();
758
759 if (S_ISDIR(st.st_mode)) {
760 ASSERTED int ret;
761 char *filename;
762
763 ret = asprintf(&filename, "%s/i915_error_state", path);
764 assert(ret > 0);
765 file = fopen(filename, "r");
766 if (!file) {
767 int minor;
768 free(filename);
769 for (minor = 0; minor < 64; minor++) {
770 ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
771 assert(ret > 0);
772
773 file = fopen(filename, "r");
774 if (file)
775 break;
776
777 free(filename);
778 }
779 }
780 if (!file) {
781 fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
782 path);
783 return EXIT_FAILURE;
784 }
785 } else {
786 file = fopen(path, "r");
787 if (!file) {
788 fprintf(stderr, "Failed to open %s: %s\n",
789 path, strerror(errno));
790 return EXIT_FAILURE;
791 }
792 }
793
794 read_data_file(file);
795 fclose(file);
796
797 /* close the stdout which is opened to write the output */
798 fflush(stdout);
799 close(1);
800 wait(NULL);
801
802 if (xml_path)
803 free(xml_path);
804
805 return EXIT_SUCCESS;
806 }
807
808 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/