1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2018 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include <stdio.h>
25b8e80941Smrg#include <stdlib.h>
26b8e80941Smrg#include <string.h>
27b8e80941Smrg#include <getopt.h>
28b8e80941Smrg
29b8e80941Smrg#include "compiler/brw_eu.h"
30b8e80941Smrg#include "dev/gen_device_info.h"
31b8e80941Smrg
32b8e80941Smrg/* Return size of file in bytes pointed by fp */
33b8e80941Smrgstatic size_t
34b8e80941Smrgi965_disasm_get_file_size(FILE *fp)
35b8e80941Smrg{
36b8e80941Smrg   size_t size;
37b8e80941Smrg
38b8e80941Smrg   fseek(fp, 0L, SEEK_END);
39b8e80941Smrg   size = ftell(fp);
40b8e80941Smrg   fseek(fp, 0L, SEEK_SET);
41b8e80941Smrg
42b8e80941Smrg   return size;
43b8e80941Smrg}
44b8e80941Smrg
45b8e80941Smrgstatic void *
46b8e80941Smrgi965_disasm_read_binary(FILE *fp, size_t *end)
47b8e80941Smrg{
48b8e80941Smrg   size_t size;
49b8e80941Smrg   void *assembly;
50b8e80941Smrg
51b8e80941Smrg   *end = i965_disasm_get_file_size(fp);
52b8e80941Smrg   if (!*end)
53b8e80941Smrg      return NULL;
54b8e80941Smrg
55b8e80941Smrg   assembly = malloc(*end + 1);
56b8e80941Smrg   if (assembly == NULL)
57b8e80941Smrg      return NULL;
58b8e80941Smrg
59b8e80941Smrg   size = fread(assembly, *end, 1, fp);
60b8e80941Smrg   fclose(fp);
61b8e80941Smrg   if (!size) {
62b8e80941Smrg      free(assembly);
63b8e80941Smrg      return NULL;
64b8e80941Smrg   }
65b8e80941Smrg   return assembly;
66b8e80941Smrg}
67b8e80941Smrg
68b8e80941Smrgstatic struct gen_device_info *
69b8e80941Smrgi965_disasm_init(uint16_t pci_id)
70b8e80941Smrg{
71b8e80941Smrg   struct gen_device_info *devinfo;
72b8e80941Smrg
73b8e80941Smrg   devinfo = malloc(sizeof *devinfo);
74b8e80941Smrg   if (devinfo == NULL)
75b8e80941Smrg      return NULL;
76b8e80941Smrg
77b8e80941Smrg   if (!gen_get_device_info(pci_id, devinfo)) {
78b8e80941Smrg      fprintf(stderr, "can't find device information: pci_id=0x%x\n",
79b8e80941Smrg              pci_id);
80b8e80941Smrg      exit(EXIT_FAILURE);
81b8e80941Smrg   }
82b8e80941Smrg
83b8e80941Smrg   /* initialize compaction table in order to handle compacted instructions */
84b8e80941Smrg   brw_init_compaction_tables(devinfo);
85b8e80941Smrg
86b8e80941Smrg   return devinfo;
87b8e80941Smrg}
88b8e80941Smrg
89b8e80941Smrgstatic void
90b8e80941Smrgprint_help(const char *progname, FILE *file)
91b8e80941Smrg{
92b8e80941Smrg   fprintf(file,
93b8e80941Smrg           "Usage: %s [OPTION]...\n"
94b8e80941Smrg           "Disassemble i965 instructions from binary file.\n\n"
95b8e80941Smrg           "      --help             display this help and exit\n"
96b8e80941Smrg           "      --binary-path=PATH read binary file from binary file PATH\n"
97b8e80941Smrg           "      --gen=platform     disassemble instructions for given \n"
98b8e80941Smrg           "                         platform (3 letter platform name)\n",
99b8e80941Smrg           progname);
100b8e80941Smrg}
101b8e80941Smrg
102b8e80941Smrgint main(int argc, char *argv[])
103b8e80941Smrg{
104b8e80941Smrg   FILE *fp = NULL;
105b8e80941Smrg   void *assembly = NULL;
106b8e80941Smrg   char *binary_path = NULL;
107b8e80941Smrg   size_t start = 0, end = 0;
108b8e80941Smrg   uint16_t pci_id = 0;
109b8e80941Smrg   int c, i;
110b8e80941Smrg   struct gen_device_info *devinfo;
111b8e80941Smrg
112b8e80941Smrg   bool help = false;
113b8e80941Smrg   const struct option i965_disasm_opts[] = {
114b8e80941Smrg      { "help",          no_argument,       (int *) &help,      true },
115b8e80941Smrg      { "binary-path",   required_argument, NULL,               'b' },
116b8e80941Smrg      { "gen",           required_argument, NULL,               'g'},
117b8e80941Smrg      { NULL,            0,                 NULL,                0 }
118b8e80941Smrg   };
119b8e80941Smrg
120b8e80941Smrg   i = 0;
121b8e80941Smrg   while ((c = getopt_long(argc, argv, "", i965_disasm_opts, &i)) != -1) {
122b8e80941Smrg      switch (c) {
123b8e80941Smrg      case 'g': {
124b8e80941Smrg         const int id = gen_device_name_to_pci_device_id(optarg);
125b8e80941Smrg         if (id < 0) {
126b8e80941Smrg            fprintf(stderr, "can't parse gen: '%s', expected 3 letter "
127b8e80941Smrg                            "platform name\n", optarg);
128b8e80941Smrg            /* Clean up binary path if given pci id is wrong */
129b8e80941Smrg            if (binary_path) {
130b8e80941Smrg               free(binary_path);
131b8e80941Smrg               fclose(fp);
132b8e80941Smrg            }
133b8e80941Smrg            exit(EXIT_FAILURE);
134b8e80941Smrg         } else {
135b8e80941Smrg            pci_id = id;
136b8e80941Smrg         }
137b8e80941Smrg         break;
138b8e80941Smrg      }
139b8e80941Smrg      case 'b':
140b8e80941Smrg         binary_path = strdup(optarg);
141b8e80941Smrg         fp = fopen(binary_path, "rb");
142b8e80941Smrg         if (!fp) {
143b8e80941Smrg            fprintf(stderr, "Unable to read input binary file : %s\n",
144b8e80941Smrg                    binary_path);
145b8e80941Smrg            /* free binary_path if path is wrong */
146b8e80941Smrg            free(binary_path);
147b8e80941Smrg            exit(EXIT_FAILURE);
148b8e80941Smrg         }
149b8e80941Smrg         break;
150b8e80941Smrg      default:
151b8e80941Smrg         /* Clean up binary path if given option is wrong */
152b8e80941Smrg         if (binary_path) {
153b8e80941Smrg            free(binary_path);
154b8e80941Smrg            fclose(fp);
155b8e80941Smrg         }
156b8e80941Smrg         break;
157b8e80941Smrg      }
158b8e80941Smrg   }
159b8e80941Smrg
160b8e80941Smrg   if (help || !binary_path || !pci_id) {
161b8e80941Smrg      print_help(argv[0], stderr);
162b8e80941Smrg      exit(0);
163b8e80941Smrg   }
164b8e80941Smrg
165b8e80941Smrg   devinfo = i965_disasm_init(pci_id);
166b8e80941Smrg   if (!devinfo) {
167b8e80941Smrg      fprintf(stderr, "Unable to allocate memory for "
168b8e80941Smrg                      "gen_device_info struct instance.\n");
169b8e80941Smrg      exit(EXIT_FAILURE);
170b8e80941Smrg   }
171b8e80941Smrg
172b8e80941Smrg   assembly = i965_disasm_read_binary(fp, &end);
173b8e80941Smrg   if (!assembly) {
174b8e80941Smrg      if (end)
175b8e80941Smrg        fprintf(stderr, "Unable to allocate buffer to read binary file\n");
176b8e80941Smrg      else
177b8e80941Smrg        fprintf(stderr, "Input file is empty\n");
178b8e80941Smrg
179b8e80941Smrg      exit(EXIT_FAILURE);
180b8e80941Smrg   }
181b8e80941Smrg
182b8e80941Smrg   /* Disassemble i965 instructions from buffer assembly */
183b8e80941Smrg   brw_disassemble(devinfo, assembly, start, end, stdout);
184b8e80941Smrg
185b8e80941Smrg   free(binary_path);
186b8e80941Smrg   free(assembly);
187b8e80941Smrg   free(devinfo);
188b8e80941Smrg
189b8e80941Smrg   return EXIT_SUCCESS;
190b8e80941Smrg}
191