aubinator: Drop unused print_dword_headers flag.
[mesa.git] / src / intel / tools / aubinator.c
1 /*
2 * Copyright © 2016 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 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <getopt.h>
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <errno.h>
34 #include <inttypes.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <sys/mman.h>
39
40 #include "util/macros.h"
41
42 #include "decoder.h"
43 #include "intel_aub.h"
44 #include "gen_disasm.h"
45
46 /* Below is the only command missing from intel_aub.h in libdrm
47 * So, reuse intel_aub.h from libdrm and #define the
48 * AUB_MI_BATCH_BUFFER_END as below
49 */
50 #define AUB_MI_BATCH_BUFFER_END (0x0500 << 16)
51
52 #define CSI "\e["
53 #define BLUE_HEADER CSI "0;44m"
54 #define GREEN_HEADER CSI "1;42m"
55 #define NORMAL CSI "0m"
56
57 /* options */
58
59 static bool option_full_decode = true;
60 static bool option_print_offsets = true;
61 static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;
62
63 /* state */
64
65 uint16_t pci_id = 0;
66 char *input_file = NULL, *xml_path = NULL;
67 struct gen_spec *spec;
68 struct gen_disasm *disasm;
69
70 uint64_t gtt_size, gtt_end;
71 void *gtt;
72 uint64_t general_state_base;
73 uint64_t surface_state_base;
74 uint64_t dynamic_state_base;
75 uint64_t instruction_base;
76 uint64_t instruction_bound;
77
78 FILE *outfile;
79
80 static inline uint32_t
81 field(uint32_t value, int start, int end)
82 {
83 uint32_t mask;
84
85 mask = ~0U >> (31 - end + start);
86
87 return (value >> start) & mask;
88 }
89
90 struct brw_instruction;
91
92 static inline int
93 valid_offset(uint32_t offset)
94 {
95 return offset < gtt_end;
96 }
97
98 static void
99 print_dword_val(struct gen_field_iterator *iter, uint64_t offset,
100 int *dword_num)
101 {
102 struct gen_field *f;
103
104 f = iter->group->fields[iter->i - 1];
105 const int dword = f->start / 32;
106
107 if (*dword_num != dword) {
108 fprintf(outfile, "0x%08"PRIx64": 0x%08x : Dword %d\n",
109 offset + 4 * dword, iter->p[dword], dword);
110 *dword_num = dword;
111 }
112 }
113
114 static char *
115 print_iterator_values(struct gen_field_iterator *iter, int *idx)
116 {
117 char *token = NULL;
118 if (strstr(iter->value, "struct") == NULL) {
119 fprintf(outfile, " %s: %s\n", iter->name, iter->value);
120 } else {
121 token = strtok(iter->value, " ");
122 if (token != NULL) {
123 token = strtok(NULL, " ");
124 *idx = atoi(strtok(NULL, ">"));
125 } else {
126 token = NULL;
127 }
128 fprintf(outfile, " %s:<struct %s>\n", iter->name, token);
129 }
130 return token;
131 }
132
133 static void
134 decode_group(struct gen_spec *spec, struct gen_group *strct,
135 const uint32_t *p, int starting_dword)
136 {
137 struct gen_field_iterator iter;
138 char *token = NULL;
139 int idx = 0, dword_num = 0;
140 uint64_t offset = 0;
141
142 if (option_print_offsets)
143 offset = (void *) p - gtt;
144 else
145 offset = 0;
146
147 gen_field_iterator_init(&iter, strct, p,
148 option_color == COLOR_ALWAYS);
149 while (gen_field_iterator_next(&iter)) {
150 idx = 0;
151 print_dword_val(&iter, offset, &dword_num);
152 if (dword_num >= starting_dword)
153 token = print_iterator_values(&iter, &idx);
154 if (token != NULL) {
155 fprintf(outfile, "0x%08"PRIx64": 0x%08x : Dword %d\n",
156 offset + 4 * idx, p[idx], idx);
157 struct gen_group *struct_val = gen_spec_find_struct(spec, token);
158 decode_group(spec, struct_val, &p[idx], 0);
159 token = NULL;
160 }
161 }
162 }
163
164 static void
165 decode_structure(struct gen_spec *spec, struct gen_group *strct,
166 const uint32_t *p)
167 {
168 decode_group(spec, strct, p, 0);
169 }
170
171 static void
172 dump_binding_table(struct gen_spec *spec, uint32_t offset)
173 {
174 uint32_t *pointers, i;
175 uint64_t start;
176 struct gen_group *surface_state;
177
178 surface_state = gen_spec_find_struct(spec, "RENDER_SURFACE_STATE");
179 if (surface_state == NULL) {
180 fprintf(outfile, "did not find RENDER_SURFACE_STATE info\n");
181 return;
182 }
183
184 start = surface_state_base + offset;
185 pointers = gtt + start;
186 for (i = 0; i < 16; i++) {
187 if (pointers[i] == 0)
188 continue;
189 start = pointers[i] + surface_state_base;
190 if (!valid_offset(start)) {
191 fprintf(outfile, "pointer %u: %08x <not valid>\n",
192 i, pointers[i]);
193 continue;
194 } else {
195 fprintf(outfile, "pointer %u: %08x\n", i, pointers[i]);
196 }
197
198 decode_structure(spec, surface_state, gtt + start);
199 }
200 }
201
202 static void
203 handle_3dstate_index_buffer(struct gen_spec *spec, uint32_t *p)
204 {
205 void *start;
206 uint32_t length, i, type, size;
207
208 start = gtt + p[2];
209 type = (p[1] >> 8) & 3;
210 size = 1 << type;
211 length = p[4] / size;
212 if (length > 10)
213 length = 10;
214
215 fprintf(outfile, "\t");
216
217 for (i = 0; i < length; i++) {
218 switch (type) {
219 case 0:
220 fprintf(outfile, "%3d ", ((uint8_t *)start)[i]);
221 break;
222 case 1:
223 fprintf(outfile, "%3d ", ((uint16_t *)start)[i]);
224 break;
225 case 2:
226 fprintf(outfile, "%3d ", ((uint32_t *)start)[i]);
227 break;
228 }
229 }
230 if (length < p[4] / size)
231 fprintf(outfile, "...\n");
232 else
233 fprintf(outfile, "\n");
234 }
235
236 static inline uint64_t
237 get_address(struct gen_spec *spec, uint32_t *p)
238 {
239 /* Addresses are always guaranteed to be page-aligned and sometimes
240 * hardware packets have extra stuff stuffed in the bottom 12 bits.
241 */
242 uint64_t addr = p[0] & ~0xfffu;
243
244 if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) {
245 /* On Broadwell and above, we have 48-bit addresses which consume two
246 * dwords. Some packets require that these get stored in a "canonical
247 * form" which means that bit 47 is sign-extended through the upper
248 * bits. In order to correctly handle those aub dumps, we need to mask
249 * off the top 16 bits.
250 */
251 addr |= ((uint64_t)p[1] & 0xffff) << 32;
252 }
253
254 return addr;
255 }
256
257 static inline uint64_t
258 get_offset(uint32_t *p, uint32_t start, uint32_t end)
259 {
260 assert(start <= end);
261 assert(end < 64);
262
263 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
264
265 uint64_t offset = p[0];
266 if (end >= 32)
267 offset |= (uint64_t) p[1] << 32;
268
269 return offset & mask;
270 }
271
272 static void
273 handle_state_base_address(struct gen_spec *spec, uint32_t *p)
274 {
275 if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) {
276 if (p[1] & 1)
277 general_state_base = get_address(spec, &p[1]);
278 if (p[4] & 1)
279 surface_state_base = get_address(spec, &p[4]);
280 if (p[6] & 1)
281 dynamic_state_base = get_address(spec, &p[6]);
282 if (p[10] & 1)
283 instruction_base = get_address(spec, &p[10]);
284 if (p[15] & 1)
285 instruction_bound = p[15] & 0xfff;
286 } else {
287 if (p[2] & 1)
288 surface_state_base = get_address(spec, &p[2]);
289 if (p[3] & 1)
290 dynamic_state_base = get_address(spec, &p[3]);
291 if (p[5] & 1)
292 instruction_base = get_address(spec, &p[5]);
293 if (p[9] & 1)
294 instruction_bound = get_address(spec, &p[9]);
295 }
296 }
297
298 static void
299 dump_samplers(struct gen_spec *spec, uint32_t offset)
300 {
301 uint32_t i;
302 uint64_t start;
303 struct gen_group *sampler_state;
304
305 sampler_state = gen_spec_find_struct(spec, "SAMPLER_STATE");
306
307 start = dynamic_state_base + offset;
308 for (i = 0; i < 4; i++) {
309 fprintf(outfile, "sampler state %d\n", i);
310 decode_structure(spec, sampler_state, gtt + start + i * 16);
311 }
312 }
313
314 static void
315 handle_media_interface_descriptor_load(struct gen_spec *spec, uint32_t *p)
316 {
317 int i, length = p[2] / 32;
318 struct gen_group *descriptor_structure;
319 uint32_t *descriptors;
320 uint64_t start;
321 struct brw_instruction *insns;
322
323 descriptor_structure =
324 gen_spec_find_struct(spec, "INTERFACE_DESCRIPTOR_DATA");
325 if (descriptor_structure == NULL) {
326 fprintf(outfile, "did not find INTERFACE_DESCRIPTOR_DATA info\n");
327 return;
328 }
329
330 start = dynamic_state_base + p[3];
331 descriptors = gtt + start;
332 for (i = 0; i < length; i++, descriptors += 8) {
333 fprintf(outfile, "descriptor %u: %08x\n", i, *descriptors);
334 decode_structure(spec, descriptor_structure, descriptors);
335
336 start = instruction_base + descriptors[0];
337 if (!valid_offset(start)) {
338 fprintf(outfile, "kernel: %08"PRIx64" <not valid>\n", start);
339 continue;
340 } else {
341 fprintf(outfile, "kernel: %08"PRIx64"\n", start);
342 }
343
344 insns = (struct brw_instruction *) (gtt + start);
345 gen_disasm_disassemble(disasm, insns, 0, stdout);
346
347 dump_samplers(spec, descriptors[3] & ~0x1f);
348 dump_binding_table(spec, descriptors[4] & ~0x1f);
349 }
350 }
351
352 /* Heuristic to determine whether a uint32_t is probably actually a float
353 * (http://stackoverflow.com/a/2953466)
354 */
355
356 static bool
357 probably_float(uint32_t bits)
358 {
359 int exp = ((bits & 0x7f800000U) >> 23) - 127;
360 uint32_t mant = bits & 0x007fffff;
361
362 /* +- 0.0 */
363 if (exp == -127 && mant == 0)
364 return true;
365
366 /* +- 1 billionth to 1 billion */
367 if (-30 <= exp && exp <= 30)
368 return true;
369
370 /* some value with only a few binary digits */
371 if ((mant & 0x0000ffff) == 0)
372 return true;
373
374 return false;
375 }
376
377 static void
378 handle_3dstate_vertex_buffers(struct gen_spec *spec, uint32_t *p)
379 {
380 uint32_t *end, *s, *dw, *dwend;
381 uint64_t offset;
382 int n, i, count, stride;
383
384 end = (p[0] & 0xff) + p + 2;
385 for (s = &p[1], n = 0; s < end; s += 4, n++) {
386 if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
387 offset = *(uint64_t *) &s[1];
388 dwend = gtt + offset + s[3];
389 } else {
390 offset = s[1];
391 dwend = gtt + s[2] + 1;
392 }
393
394 stride = field(s[0], 0, 11);
395 count = 0;
396 fprintf(outfile, "vertex buffer %d, size %d\n", n, s[3]);
397 for (dw = gtt + offset, i = 0; dw < dwend && i < 256; dw++) {
398 if (count == 0 && count % (8 * 4) == 0)
399 fprintf(outfile, " ");
400
401 if (probably_float(*dw))
402 fprintf(outfile, " %8.2f", *(float *) dw);
403 else
404 fprintf(outfile, " 0x%08x", *dw);
405
406 i++;
407 count += 4;
408
409 if (count == stride) {
410 fprintf(outfile, "\n");
411 count = 0;
412 } else if (count % (8 * 4) == 0) {
413 fprintf(outfile, "\n");
414 } else {
415 fprintf(outfile, " ");
416 }
417 }
418 if (count > 0 && count % (8 * 4) != 0)
419 fprintf(outfile, "\n");
420 }
421 }
422
423 static void
424 handle_3dstate_vs(struct gen_spec *spec, uint32_t *p)
425 {
426 uint64_t start;
427 struct brw_instruction *insns;
428 int vs_enable;
429
430 if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
431 start = get_offset(&p[1], 6, 63);
432 vs_enable = p[7] & 1;
433 } else {
434 start = get_offset(&p[1], 6, 31);
435 vs_enable = p[5] & 1;
436 }
437
438 if (vs_enable) {
439 fprintf(outfile, "instruction_base %08"PRIx64", start %08"PRIx64"\n",
440 instruction_base, start);
441
442 insns = (struct brw_instruction *) (gtt + instruction_base + start);
443 gen_disasm_disassemble(disasm, insns, 0, stdout);
444 }
445 }
446
447 static void
448 handle_3dstate_hs(struct gen_spec *spec, uint32_t *p)
449 {
450 uint64_t start;
451 struct brw_instruction *insns;
452 int hs_enable;
453
454 if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
455 start = get_offset(&p[3], 6, 63);
456 } else {
457 start = get_offset(&p[3], 6, 31);
458 }
459
460 hs_enable = p[2] & 0x80000000;
461
462 if (hs_enable) {
463 fprintf(outfile, "instruction_base %08"PRIx64", start %08"PRIx64"\n",
464 instruction_base, start);
465
466 insns = (struct brw_instruction *) (gtt + instruction_base + start);
467 gen_disasm_disassemble(disasm, insns, 0, stdout);
468 }
469 }
470
471 static void
472 handle_3dstate_constant(struct gen_spec *spec, uint32_t *p)
473 {
474 int i, j, length;
475 uint32_t *dw;
476 float *f;
477
478 for (i = 0; i < 4; i++) {
479 length = (p[1 + i / 2] >> (i & 1) * 16) & 0xffff;
480 f = (float *) (gtt + p[3 + i * 2] + dynamic_state_base);
481 dw = (uint32_t *) f;
482 for (j = 0; j < length * 8; j++) {
483 if (probably_float(dw[j]))
484 fprintf(outfile, " %04.3f", f[j]);
485 else
486 fprintf(outfile, " 0x%08x", dw[j]);
487
488 if ((j & 7) == 7)
489 fprintf(outfile, "\n");
490 }
491 }
492 }
493
494 static void
495 handle_3dstate_ps(struct gen_spec *spec, uint32_t *p)
496 {
497 uint32_t mask = ~((1 << 6) - 1);
498 uint64_t start;
499 struct brw_instruction *insns;
500 static const char unused[] = "unused";
501 static const char *pixel_type[3] = {"8 pixel", "16 pixel", "32 pixel"};
502 const char *k0, *k1, *k2;
503 uint32_t k_mask, k1_offset, k2_offset;
504
505 if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
506 k_mask = p[6] & 7;
507 k1_offset = 8;
508 k2_offset = 10;
509 } else {
510 k_mask = p[4] & 7;
511 k1_offset = 6;
512 k2_offset = 7;
513 }
514
515 #define DISPATCH_8 1
516 #define DISPATCH_16 2
517 #define DISPATCH_32 4
518
519 switch (k_mask) {
520 case DISPATCH_8:
521 k0 = pixel_type[0];
522 k1 = unused;
523 k2 = unused;
524 break;
525 case DISPATCH_16:
526 k0 = pixel_type[1];
527 k1 = unused;
528 k2 = unused;
529 break;
530 case DISPATCH_8 | DISPATCH_16:
531 k0 = pixel_type[0];
532 k1 = unused;
533 k2 = pixel_type[1];
534 break;
535 case DISPATCH_32:
536 k0 = pixel_type[2];
537 k1 = unused;
538 k2 = unused;
539 break;
540 case DISPATCH_16 | DISPATCH_32:
541 k0 = unused;
542 k1 = pixel_type[2];
543 k2 = pixel_type[1];
544 break;
545 case DISPATCH_8 | DISPATCH_16 | DISPATCH_32:
546 k0 = pixel_type[0];
547 k1 = pixel_type[2];
548 k2 = pixel_type[1];
549 break;
550 default:
551 k0 = unused;
552 k1 = unused;
553 k2 = unused;
554 break;
555 }
556
557 start = instruction_base + (p[1] & mask);
558 fprintf(outfile, " Kernel[0] %s\n", k0);
559 if (k0 != unused) {
560 insns = (struct brw_instruction *) (gtt + start);
561 gen_disasm_disassemble(disasm, insns, 0, stdout);
562 }
563
564 start = instruction_base + (p[k1_offset] & mask);
565 fprintf(outfile, " Kernel[1] %s\n", k1);
566 if (k1 != unused) {
567 insns = (struct brw_instruction *) (gtt + start);
568 gen_disasm_disassemble(disasm, insns, 0, stdout);
569 }
570
571 start = instruction_base + (p[k2_offset] & mask);
572 fprintf(outfile, " Kernel[2] %s\n", k2);
573 if (k2 != unused) {
574 insns = (struct brw_instruction *) (gtt + start);
575 gen_disasm_disassemble(disasm, insns, 0, stdout);
576 }
577 }
578
579 static void
580 handle_3dstate_binding_table_pointers(struct gen_spec *spec, uint32_t *p)
581 {
582 dump_binding_table(spec, p[1]);
583 }
584
585 static void
586 handle_3dstate_sampler_state_pointers(struct gen_spec *spec, uint32_t *p)
587 {
588 dump_samplers(spec, p[1]);
589 }
590
591 static void
592 handle_3dstate_viewport_state_pointers_cc(struct gen_spec *spec, uint32_t *p)
593 {
594 uint64_t start;
595 struct gen_group *cc_viewport;
596
597 cc_viewport = gen_spec_find_struct(spec, "CC_VIEWPORT");
598
599 start = dynamic_state_base + (p[1] & ~0x1fu);
600 for (uint32_t i = 0; i < 4; i++) {
601 fprintf(outfile, "viewport %d\n", i);
602 decode_structure(spec, cc_viewport, gtt + start + i * 8);
603 }
604 }
605
606 static void
607 handle_3dstate_viewport_state_pointers_sf_clip(struct gen_spec *spec,
608 uint32_t *p)
609 {
610 uint64_t start;
611 struct gen_group *sf_clip_viewport;
612
613 sf_clip_viewport = gen_spec_find_struct(spec, "SF_CLIP_VIEWPORT");
614
615 start = dynamic_state_base + (p[1] & ~0x3fu);
616 for (uint32_t i = 0; i < 4; i++) {
617 fprintf(outfile, "viewport %d\n", i);
618 decode_structure(spec, sf_clip_viewport, gtt + start + i * 64);
619 }
620 }
621
622 static void
623 handle_3dstate_blend_state_pointers(struct gen_spec *spec, uint32_t *p)
624 {
625 uint64_t start;
626 struct gen_group *blend_state;
627
628 blend_state = gen_spec_find_struct(spec, "BLEND_STATE");
629
630 start = dynamic_state_base + (p[1] & ~0x3fu);
631 decode_structure(spec, blend_state, gtt + start);
632 }
633
634 static void
635 handle_3dstate_cc_state_pointers(struct gen_spec *spec, uint32_t *p)
636 {
637 uint64_t start;
638 struct gen_group *cc_state;
639
640 cc_state = gen_spec_find_struct(spec, "COLOR_CALC_STATE");
641
642 start = dynamic_state_base + (p[1] & ~0x3fu);
643 decode_structure(spec, cc_state, gtt + start);
644 }
645
646 static void
647 handle_3dstate_scissor_state_pointers(struct gen_spec *spec, uint32_t *p)
648 {
649 uint64_t start;
650 struct gen_group *scissor_rect;
651
652 scissor_rect = gen_spec_find_struct(spec, "SCISSOR_RECT");
653
654 start = dynamic_state_base + (p[1] & ~0x1fu);
655 decode_structure(spec, scissor_rect, gtt + start);
656 }
657
658 static void
659 handle_load_register_imm(struct gen_spec *spec, uint32_t *p)
660 {
661 struct gen_group *reg = gen_spec_find_register(spec, p[1]);
662
663 if (reg != NULL) {
664 fprintf(outfile, "register %s (0x%x): 0x%x\n",
665 reg->name, reg->register_offset, p[2]);
666 decode_structure(spec, reg, &p[2]);
667 }
668 }
669
670 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
671
672 #define STATE_BASE_ADDRESS 0x61010000
673
674 #define MEDIA_INTERFACE_DESCRIPTOR_LOAD 0x70020000
675
676 #define _3DSTATE_INDEX_BUFFER 0x780a0000
677 #define _3DSTATE_VERTEX_BUFFERS 0x78080000
678
679 #define _3DSTATE_VS 0x78100000
680 #define _3DSTATE_GS 0x78110000
681 #define _3DSTATE_HS 0x781b0000
682 #define _3DSTATE_DS 0x781d0000
683
684 #define _3DSTATE_CONSTANT_VS 0x78150000
685 #define _3DSTATE_CONSTANT_GS 0x78160000
686 #define _3DSTATE_CONSTANT_PS 0x78170000
687 #define _3DSTATE_CONSTANT_HS 0x78190000
688 #define _3DSTATE_CONSTANT_DS 0x781A0000
689
690 #define _3DSTATE_PS 0x78200000
691
692 #define _3DSTATE_BINDING_TABLE_POINTERS_VS 0x78260000
693 #define _3DSTATE_BINDING_TABLE_POINTERS_HS 0x78270000
694 #define _3DSTATE_BINDING_TABLE_POINTERS_DS 0x78280000
695 #define _3DSTATE_BINDING_TABLE_POINTERS_GS 0x78290000
696 #define _3DSTATE_BINDING_TABLE_POINTERS_PS 0x782a0000
697
698 #define _3DSTATE_SAMPLER_STATE_POINTERS_VS 0x782b0000
699 #define _3DSTATE_SAMPLER_STATE_POINTERS_GS 0x782e0000
700 #define _3DSTATE_SAMPLER_STATE_POINTERS_PS 0x782f0000
701
702 #define _3DSTATE_VIEWPORT_STATE_POINTERS_CC 0x78230000
703 #define _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP 0x78210000
704 #define _3DSTATE_BLEND_STATE_POINTERS 0x78240000
705 #define _3DSTATE_CC_STATE_POINTERS 0x780e0000
706 #define _3DSTATE_SCISSOR_STATE_POINTERS 0x780f0000
707
708 #define _MI_LOAD_REGISTER_IMM 0x11000000
709
710 struct custom_handler {
711 uint32_t opcode;
712 void (*handle)(struct gen_spec *spec, uint32_t *p);
713 } custom_handlers[] = {
714 { STATE_BASE_ADDRESS, handle_state_base_address },
715 { MEDIA_INTERFACE_DESCRIPTOR_LOAD, handle_media_interface_descriptor_load },
716 { _3DSTATE_VERTEX_BUFFERS, handle_3dstate_vertex_buffers },
717 { _3DSTATE_INDEX_BUFFER, handle_3dstate_index_buffer },
718 { _3DSTATE_VS, handle_3dstate_vs },
719 { _3DSTATE_GS, handle_3dstate_vs },
720 { _3DSTATE_DS, handle_3dstate_vs },
721 { _3DSTATE_HS, handle_3dstate_hs },
722 { _3DSTATE_CONSTANT_VS, handle_3dstate_constant },
723 { _3DSTATE_CONSTANT_GS, handle_3dstate_constant },
724 { _3DSTATE_CONSTANT_PS, handle_3dstate_constant },
725 { _3DSTATE_CONSTANT_HS, handle_3dstate_constant },
726 { _3DSTATE_CONSTANT_DS, handle_3dstate_constant },
727 { _3DSTATE_PS, handle_3dstate_ps },
728
729 { _3DSTATE_BINDING_TABLE_POINTERS_VS, handle_3dstate_binding_table_pointers },
730 { _3DSTATE_BINDING_TABLE_POINTERS_HS, handle_3dstate_binding_table_pointers },
731 { _3DSTATE_BINDING_TABLE_POINTERS_DS, handle_3dstate_binding_table_pointers },
732 { _3DSTATE_BINDING_TABLE_POINTERS_GS, handle_3dstate_binding_table_pointers },
733 { _3DSTATE_BINDING_TABLE_POINTERS_PS, handle_3dstate_binding_table_pointers },
734
735 { _3DSTATE_SAMPLER_STATE_POINTERS_VS, handle_3dstate_sampler_state_pointers },
736 { _3DSTATE_SAMPLER_STATE_POINTERS_GS, handle_3dstate_sampler_state_pointers },
737 { _3DSTATE_SAMPLER_STATE_POINTERS_PS, handle_3dstate_sampler_state_pointers },
738
739 { _3DSTATE_VIEWPORT_STATE_POINTERS_CC, handle_3dstate_viewport_state_pointers_cc },
740 { _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP, handle_3dstate_viewport_state_pointers_sf_clip },
741 { _3DSTATE_BLEND_STATE_POINTERS, handle_3dstate_blend_state_pointers },
742 { _3DSTATE_CC_STATE_POINTERS, handle_3dstate_cc_state_pointers },
743 { _3DSTATE_SCISSOR_STATE_POINTERS, handle_3dstate_scissor_state_pointers },
744 { _MI_LOAD_REGISTER_IMM, handle_load_register_imm }
745 };
746
747 static void
748 parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine)
749 {
750 uint32_t *p, *end = cmds + size / 4;
751 unsigned int length, i;
752 struct gen_group *inst;
753
754 for (p = cmds; p < end; p += length) {
755 inst = gen_spec_find_instruction(spec, p);
756 if (inst == NULL) {
757 fprintf(outfile, "unknown instruction %08x\n", p[0]);
758 length = (p[0] & 0xff) + 2;
759 continue;
760 }
761 length = gen_group_get_length(inst, p);
762
763 const char *color, *reset_color = NORMAL;
764 uint64_t offset;
765
766 if (option_full_decode) {
767 if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_START ||
768 (p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_END)
769 color = GREEN_HEADER;
770 else
771 color = BLUE_HEADER;
772 } else
773 color = NORMAL;
774
775 if (option_color == COLOR_NEVER) {
776 color = "";
777 reset_color = "";
778 }
779
780 if (option_print_offsets)
781 offset = (void *) p - gtt;
782 else
783 offset = 0;
784
785 fprintf(outfile, "%s0x%08"PRIx64": 0x%08x: %-80s%s\n",
786 color, offset, p[0],
787 gen_group_get_name(inst), reset_color);
788
789 if (option_full_decode) {
790 decode_group(spec, inst, p, 1);
791
792 for (i = 0; i < ARRAY_LENGTH(custom_handlers); i++) {
793 if (gen_group_get_opcode(inst) == custom_handlers[i].opcode)
794 custom_handlers[i].handle(spec, p);
795 }
796 }
797
798 if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_START) {
799 uint64_t start = get_address(spec, &p[1]);
800
801 if (p[0] & (1 << 22)) {
802 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" set acts
803 * like a subroutine call. Commands that come afterwards get
804 * processed once the 2nd level batch buffer returns with
805 * MI_BATCH_BUFFER_END.
806 */
807 parse_commands(spec, gtt + start, gtt_end - start, engine);
808 } else {
809 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" unset acts
810 * like a goto. Nothing after it will ever get processed. In
811 * order to prevent the recursion from growing, we just reset the
812 * loop and continue;
813 */
814 p = gtt + start;
815 /* We don't know where secondaries end so use the GTT end */
816 end = gtt + gtt_end;
817 length = 0;
818 continue;
819 }
820 } else if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_END) {
821 break;
822 }
823 }
824 }
825
826 #define GEN_ENGINE_RENDER 1
827 #define GEN_ENGINE_BLITTER 2
828
829 static void
830 handle_trace_block(uint32_t *p)
831 {
832 int operation = p[1] & AUB_TRACE_OPERATION_MASK;
833 int type = p[1] & AUB_TRACE_TYPE_MASK;
834 int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK;
835 uint64_t offset = p[3];
836 uint32_t size = p[4];
837 int header_length = p[0] & 0xffff;
838 uint32_t *data = p + header_length + 2;
839 int engine = GEN_ENGINE_RENDER;
840
841 if (gen_spec_get_gen(spec) >= gen_make_gen(8,0))
842 offset += (uint64_t) p[5] << 32;
843
844 switch (operation) {
845 case AUB_TRACE_OP_DATA_WRITE:
846 if (address_space != AUB_TRACE_MEMTYPE_GTT)
847 break;
848 if (gtt_size < offset + size) {
849 fprintf(stderr, "overflow gtt space: %s\n", strerror(errno));
850 exit(EXIT_FAILURE);
851 }
852 memcpy((char *) gtt + offset, data, size);
853 if (gtt_end < offset + size)
854 gtt_end = offset + size;
855 break;
856 case AUB_TRACE_OP_COMMAND_WRITE:
857 switch (type) {
858 case AUB_TRACE_TYPE_RING_PRB0:
859 engine = GEN_ENGINE_RENDER;
860 break;
861 case AUB_TRACE_TYPE_RING_PRB2:
862 engine = GEN_ENGINE_BLITTER;
863 break;
864 default:
865 fprintf(outfile, "command write to unknown ring %d\n", type);
866 break;
867 }
868
869 parse_commands(spec, data, size, engine);
870 gtt_end = 0;
871 break;
872 }
873 }
874
875 static void
876 handle_trace_header(uint32_t *p)
877 {
878 /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in
879 * the AUB header comment. If the user hasn't specified a hardware
880 * generation, try to use the one from the AUB file.
881 */
882 uint32_t *end = p + (p[0] & 0xffff) + 2;
883 int aub_pci_id = 0;
884 if (end > &p[12] && p[12] > 0)
885 sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id);
886
887 if (pci_id == 0)
888 pci_id = aub_pci_id;
889
890 struct gen_device_info devinfo;
891 if (!gen_get_device_info(pci_id, &devinfo)) {
892 fprintf(stderr, "can't find device information: pci_id=0x%x\n", pci_id);
893 exit(EXIT_FAILURE);
894 }
895
896 if (xml_path == NULL)
897 spec = gen_spec_load(&devinfo);
898 else
899 spec = gen_spec_load_from_path(&devinfo, xml_path);
900 disasm = gen_disasm_create(pci_id);
901
902 if (spec == NULL || disasm == NULL)
903 exit(EXIT_FAILURE);
904
905 fprintf(outfile, "%sAubinator: Intel AUB file decoder.%-80s%s\n",
906 GREEN_HEADER, "", NORMAL);
907
908 if (input_file)
909 fprintf(outfile, "File name: %s\n", input_file);
910
911 if (aub_pci_id)
912 fprintf(outfile, "PCI ID: 0x%x\n", aub_pci_id);
913
914 char app_name[33];
915 strncpy(app_name, (char *)&p[2], 32);
916 app_name[32] = 0;
917 fprintf(outfile, "Application name: %s\n", app_name);
918
919 fprintf(outfile, "Decoding as: %s\n", gen_get_device_name(pci_id));
920
921 /* Throw in a new line before the first batch */
922 fprintf(outfile, "\n");
923 }
924
925 struct aub_file {
926 FILE *stream;
927
928 uint32_t *map, *end, *cursor;
929 uint32_t *mem_end;
930 };
931
932 static struct aub_file *
933 aub_file_open(const char *filename)
934 {
935 struct aub_file *file;
936 struct stat sb;
937 int fd;
938
939 file = calloc(1, sizeof *file);
940 fd = open(filename, O_RDONLY);
941 if (fd == -1) {
942 fprintf(stderr, "open %s failed: %s\n", filename, strerror(errno));
943 exit(EXIT_FAILURE);
944 }
945
946 if (fstat(fd, &sb) == -1) {
947 fprintf(stderr, "stat failed: %s\n", strerror(errno));
948 exit(EXIT_FAILURE);
949 }
950
951 file->map = mmap(NULL, sb.st_size,
952 PROT_READ, MAP_SHARED, fd, 0);
953 if (file->map == MAP_FAILED) {
954 fprintf(stderr, "mmap failed: %s\n", strerror(errno));
955 exit(EXIT_FAILURE);
956 }
957
958 file->cursor = file->map;
959 file->end = file->map + sb.st_size / 4;
960
961 return file;
962 }
963
964 static struct aub_file *
965 aub_file_stdin(void)
966 {
967 struct aub_file *file;
968
969 file = calloc(1, sizeof *file);
970 file->stream = stdin;
971
972 return file;
973 }
974
975 #define TYPE(dw) (((dw) >> 29) & 7)
976 #define OPCODE(dw) (((dw) >> 23) & 0x3f)
977 #define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
978
979 #define MAKE_HEADER(type, opcode, subopcode) \
980 (((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
981
982 #define TYPE_AUB 0x7
983
984 /* Classic AUB opcodes */
985 #define OPCODE_AUB 0x01
986 #define SUBOPCODE_HEADER 0x05
987 #define SUBOPCODE_BLOCK 0x41
988 #define SUBOPCODE_BMP 0x1e
989
990 /* Newer version AUB opcode */
991 #define OPCODE_NEW_AUB 0x2e
992 #define SUBOPCODE_VERSION 0x00
993 #define SUBOPCODE_REG_WRITE 0x03
994 #define SUBOPCODE_MEM_POLL 0x05
995 #define SUBOPCODE_MEM_WRITE 0x06
996
997 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
998
999 struct {
1000 const char *name;
1001 uint32_t gen;
1002 } device_map[] = {
1003 { "bwr", MAKE_GEN(4, 0) },
1004 { "cln", MAKE_GEN(4, 0) },
1005 { "blc", MAKE_GEN(4, 0) },
1006 { "ctg", MAKE_GEN(4, 0) },
1007 { "el", MAKE_GEN(4, 0) },
1008 { "il", MAKE_GEN(4, 0) },
1009 { "sbr", MAKE_GEN(6, 0) },
1010 { "ivb", MAKE_GEN(7, 0) },
1011 { "lrb2", MAKE_GEN(0, 0) },
1012 { "hsw", MAKE_GEN(7, 5) },
1013 { "vlv", MAKE_GEN(7, 0) },
1014 { "bdw", MAKE_GEN(8, 0) },
1015 { "skl", MAKE_GEN(9, 0) },
1016 { "chv", MAKE_GEN(8, 0) },
1017 { "bxt", MAKE_GEN(9, 0) }
1018 };
1019
1020 enum {
1021 AUB_ITEM_DECODE_OK,
1022 AUB_ITEM_DECODE_FAILED,
1023 AUB_ITEM_DECODE_NEED_MORE_DATA,
1024 };
1025
1026 static int
1027 aub_file_decode_batch(struct aub_file *file)
1028 {
1029 uint32_t *p, h, device, data_type, *new_cursor;
1030 int header_length, bias;
1031
1032 if (file->end - file->cursor < 1)
1033 return AUB_ITEM_DECODE_NEED_MORE_DATA;
1034
1035 p = file->cursor;
1036 h = *p;
1037 header_length = h & 0xffff;
1038
1039 switch (OPCODE(h)) {
1040 case OPCODE_AUB:
1041 bias = 2;
1042 break;
1043 case OPCODE_NEW_AUB:
1044 bias = 1;
1045 break;
1046 default:
1047 fprintf(outfile, "unknown opcode %d at %td/%td\n",
1048 OPCODE(h), file->cursor - file->map,
1049 file->end - file->map);
1050 return AUB_ITEM_DECODE_FAILED;
1051 }
1052
1053 new_cursor = p + header_length + bias;
1054 if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) {
1055 if (file->end - file->cursor < 4)
1056 return AUB_ITEM_DECODE_NEED_MORE_DATA;
1057 new_cursor += p[4] / 4;
1058 }
1059
1060 if (new_cursor > file->end)
1061 return AUB_ITEM_DECODE_NEED_MORE_DATA;
1062
1063 switch (h & 0xffff0000) {
1064 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER):
1065 handle_trace_header(p);
1066 break;
1067 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK):
1068 handle_trace_block(p);
1069 break;
1070 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP):
1071 break;
1072 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION):
1073 fprintf(outfile, "version block: dw1 %08x\n", p[1]);
1074 device = (p[1] >> 8) & 0xff;
1075 fprintf(outfile, " device %s\n", device_map[device].name);
1076 break;
1077 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE):
1078 fprintf(outfile, "register write block: (dwords %d)\n", h & 0xffff);
1079 fprintf(outfile, " reg 0x%x, data 0x%x\n", p[1], p[5]);
1080 break;
1081 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE):
1082 fprintf(outfile, "memory write block (dwords %d):\n", h & 0xffff);
1083 fprintf(outfile, " address 0x%"PRIx64"\n", *(uint64_t *) &p[1]);
1084 data_type = (p[3] >> 20) & 0xff;
1085 if (data_type != 0)
1086 fprintf(outfile, " data type 0x%x\n", data_type);
1087 fprintf(outfile, " address space 0x%x\n", (p[3] >> 28) & 0xf);
1088 break;
1089 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL):
1090 fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff);
1091 break;
1092 default:
1093 fprintf(outfile, "unknown block type=0x%x, opcode=0x%x, "
1094 "subopcode=0x%x (%08x)\n", TYPE(h), OPCODE(h), SUBOPCODE(h), h);
1095 break;
1096 }
1097 file->cursor = new_cursor;
1098
1099 return AUB_ITEM_DECODE_OK;
1100 }
1101
1102 static int
1103 aub_file_more_stuff(struct aub_file *file)
1104 {
1105 return file->cursor < file->end || (file->stream && !feof(file->stream));
1106 }
1107
1108 #define AUB_READ_BUFFER_SIZE (4096)
1109 #define MAX(a, b) ((a) < (b) ? (b) : (a))
1110
1111 static void
1112 aub_file_data_grow(struct aub_file *file)
1113 {
1114 size_t old_size = (file->mem_end - file->map) * 4;
1115 size_t new_size = MAX(old_size * 2, AUB_READ_BUFFER_SIZE);
1116 uint32_t *new_start = realloc(file->map, new_size);
1117
1118 file->cursor = new_start + (file->cursor - file->map);
1119 file->end = new_start + (file->end - file->map);
1120 file->map = new_start;
1121 file->mem_end = file->map + (new_size / 4);
1122 }
1123
1124 static bool
1125 aub_file_data_load(struct aub_file *file)
1126 {
1127 size_t r;
1128
1129 if (file->stream == NULL)
1130 return false;
1131
1132 /* First remove any consumed data */
1133 if (file->cursor > file->map) {
1134 memmove(file->map, file->cursor,
1135 (file->end - file->cursor) * 4);
1136 file->end -= file->cursor - file->map;
1137 file->cursor = file->map;
1138 }
1139
1140 /* Then load some new data in */
1141 if ((file->mem_end - file->end) < (AUB_READ_BUFFER_SIZE / 4))
1142 aub_file_data_grow(file);
1143
1144 r = fread(file->end, 1, (file->mem_end - file->end) * 4, file->stream);
1145 file->end += r / 4;
1146
1147 return r != 0;
1148 }
1149
1150 static void
1151 setup_pager(void)
1152 {
1153 int fds[2];
1154 pid_t pid;
1155
1156 if (!isatty(1))
1157 return;
1158
1159 if (pipe(fds) == -1)
1160 return;
1161
1162 pid = fork();
1163 if (pid == -1)
1164 return;
1165
1166 if (pid == 0) {
1167 close(fds[1]);
1168 dup2(fds[0], 0);
1169 execlp("less", "less", "-FRSi", NULL);
1170 }
1171
1172 close(fds[0]);
1173 dup2(fds[1], 1);
1174 close(fds[1]);
1175 }
1176
1177 static void
1178 print_help(const char *progname, FILE *file)
1179 {
1180 fprintf(file,
1181 "Usage: %s [OPTION]... [FILE]\n"
1182 "Decode aub file contents from either FILE or the standard input.\n\n"
1183 "A valid --gen option must be provided.\n\n"
1184 " --help display this help and exit\n"
1185 " --gen=platform decode for given platform (ivb, byt, hsw, bdw, chv, skl, kbl or bxt)\n"
1186 " --headers decode only command headers\n"
1187 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
1188 " if omitted), 'always', or 'never'\n"
1189 " --no-pager don't launch pager\n"
1190 " --no-offsets don't print instruction offsets\n"
1191 " --xml=DIR load hardware xml description from directory DIR\n",
1192 progname);
1193 }
1194
1195 int main(int argc, char *argv[])
1196 {
1197 struct aub_file *file;
1198 int c, i;
1199 bool help = false, pager = true;
1200 const struct {
1201 const char *name;
1202 int pci_id;
1203 } gens[] = {
1204 { "ivb", 0x0166 }, /* Intel(R) Ivybridge Mobile GT2 */
1205 { "hsw", 0x0416 }, /* Intel(R) Haswell Mobile GT2 */
1206 { "byt", 0x0155 }, /* Intel(R) Bay Trail */
1207 { "bdw", 0x1616 }, /* Intel(R) HD Graphics 5500 (Broadwell GT2) */
1208 { "chv", 0x22B3 }, /* Intel(R) HD Graphics (Cherryview) */
1209 { "skl", 0x1912 }, /* Intel(R) HD Graphics 530 (Skylake GT2) */
1210 { "kbl", 0x591D }, /* Intel(R) Kabylake GT2 */
1211 { "bxt", 0x0A84 } /* Intel(R) HD Graphics (Broxton) */
1212 };
1213 const struct option aubinator_opts[] = {
1214 { "help", no_argument, (int *) &help, true },
1215 { "no-pager", no_argument, (int *) &pager, false },
1216 { "no-offsets", no_argument, (int *) &option_print_offsets, false },
1217 { "gen", required_argument, NULL, 'g' },
1218 { "headers", no_argument, (int *) &option_full_decode, false },
1219 { "color", required_argument, NULL, 'c' },
1220 { "xml", required_argument, NULL, 'x' },
1221 { NULL, 0, NULL, 0 }
1222 };
1223
1224 outfile = stdout;
1225
1226 i = 0;
1227 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
1228 switch (c) {
1229 case 'g':
1230 for (i = 0; i < ARRAY_SIZE(gens); i++) {
1231 if (!strcmp(optarg, gens[i].name)) {
1232 pci_id = gens[i].pci_id;
1233 break;
1234 }
1235 }
1236 if (i == ARRAY_SIZE(gens)) {
1237 fprintf(stderr, "can't parse gen: '%s', expected ivb, byt, hsw, "
1238 "bdw, chv, skl, kbl or bxt\n", optarg);
1239 exit(EXIT_FAILURE);
1240 }
1241 break;
1242 case 'c':
1243 if (optarg == NULL || strcmp(optarg, "always") == 0)
1244 option_color = COLOR_ALWAYS;
1245 else if (strcmp(optarg, "never") == 0)
1246 option_color = COLOR_NEVER;
1247 else if (strcmp(optarg, "auto") == 0)
1248 option_color = COLOR_AUTO;
1249 else {
1250 fprintf(stderr, "invalid value for --color: %s", optarg);
1251 exit(EXIT_FAILURE);
1252 }
1253 break;
1254 case 'x':
1255 xml_path = strdup(optarg);
1256 break;
1257 default:
1258 break;
1259 }
1260 }
1261
1262 if (help || argc == 1) {
1263 print_help(argv[0], stderr);
1264 exit(0);
1265 }
1266
1267 if (optind < argc)
1268 input_file = argv[optind];
1269
1270 /* Do this before we redirect stdout to pager. */
1271 if (option_color == COLOR_AUTO)
1272 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
1273
1274 if (isatty(1) && pager)
1275 setup_pager();
1276
1277 if (input_file == NULL)
1278 file = aub_file_stdin();
1279 else
1280 file = aub_file_open(input_file);
1281
1282 /* mmap a terabyte for our gtt space. */
1283 gtt_size = 1ull << 40;
1284 gtt = mmap(NULL, gtt_size, PROT_READ | PROT_WRITE,
1285 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
1286 if (gtt == MAP_FAILED) {
1287 fprintf(stderr, "failed to alloc gtt space: %s\n", strerror(errno));
1288 exit(EXIT_FAILURE);
1289 }
1290
1291 while (aub_file_more_stuff(file)) {
1292 switch (aub_file_decode_batch(file)) {
1293 case AUB_ITEM_DECODE_OK:
1294 break;
1295 case AUB_ITEM_DECODE_NEED_MORE_DATA:
1296 if (!file->stream) {
1297 file->cursor = file->end;
1298 break;
1299 }
1300 if (aub_file_more_stuff(file) && !aub_file_data_load(file)) {
1301 fprintf(stderr, "failed to load data from stdin\n");
1302 exit(EXIT_FAILURE);
1303 }
1304 break;
1305 default:
1306 fprintf(stderr, "failed to parse aubdump data\n");
1307 exit(EXIT_FAILURE);
1308 }
1309 }
1310
1311
1312 fflush(stdout);
1313 /* close the stdout which is opened to write the output */
1314 close(1);
1315 free(xml_path);
1316
1317 wait(NULL);
1318
1319 return EXIT_SUCCESS;
1320 }