1/*
2 * Copyright © 2018 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 <string.h>
27#include <getopt.h>
28
29#include "compiler/brw_eu.h"
30#include "dev/gen_device_info.h"
31
32/* Return size of file in bytes pointed by fp */
33static size_t
34i965_disasm_get_file_size(FILE *fp)
35{
36   size_t size;
37
38   fseek(fp, 0L, SEEK_END);
39   size = ftell(fp);
40   fseek(fp, 0L, SEEK_SET);
41
42   return size;
43}
44
45static void *
46i965_disasm_read_binary(FILE *fp, size_t *end)
47{
48   size_t size;
49   void *assembly;
50
51   *end = i965_disasm_get_file_size(fp);
52   if (!*end)
53      return NULL;
54
55   assembly = malloc(*end + 1);
56   if (assembly == NULL)
57      return NULL;
58
59   size = fread(assembly, *end, 1, fp);
60   fclose(fp);
61   if (!size) {
62      free(assembly);
63      return NULL;
64   }
65   return assembly;
66}
67
68static struct gen_device_info *
69i965_disasm_init(uint16_t pci_id)
70{
71   struct gen_device_info *devinfo;
72
73   devinfo = malloc(sizeof *devinfo);
74   if (devinfo == NULL)
75      return NULL;
76
77   if (!gen_get_device_info(pci_id, devinfo)) {
78      fprintf(stderr, "can't find device information: pci_id=0x%x\n",
79              pci_id);
80      exit(EXIT_FAILURE);
81   }
82
83   /* initialize compaction table in order to handle compacted instructions */
84   brw_init_compaction_tables(devinfo);
85
86   return devinfo;
87}
88
89static void
90print_help(const char *progname, FILE *file)
91{
92   fprintf(file,
93           "Usage: %s [OPTION]...\n"
94           "Disassemble i965 instructions from binary file.\n\n"
95           "      --help             display this help and exit\n"
96           "      --binary-path=PATH read binary file from binary file PATH\n"
97           "      --gen=platform     disassemble instructions for given \n"
98           "                         platform (3 letter platform name)\n",
99           progname);
100}
101
102int main(int argc, char *argv[])
103{
104   FILE *fp = NULL;
105   void *assembly = NULL;
106   char *binary_path = NULL;
107   size_t start = 0, end = 0;
108   uint16_t pci_id = 0;
109   int c, i;
110   struct gen_device_info *devinfo;
111
112   bool help = false;
113   const struct option i965_disasm_opts[] = {
114      { "help",          no_argument,       (int *) &help,      true },
115      { "binary-path",   required_argument, NULL,               'b' },
116      { "gen",           required_argument, NULL,               'g'},
117      { NULL,            0,                 NULL,                0 }
118   };
119
120   i = 0;
121   while ((c = getopt_long(argc, argv, "", i965_disasm_opts, &i)) != -1) {
122      switch (c) {
123      case 'g': {
124         const int id = gen_device_name_to_pci_device_id(optarg);
125         if (id < 0) {
126            fprintf(stderr, "can't parse gen: '%s', expected 3 letter "
127                            "platform name\n", optarg);
128            /* Clean up binary path if given pci id is wrong */
129            if (binary_path) {
130               free(binary_path);
131               fclose(fp);
132            }
133            exit(EXIT_FAILURE);
134         } else {
135            pci_id = id;
136         }
137         break;
138      }
139      case 'b':
140         binary_path = strdup(optarg);
141         fp = fopen(binary_path, "rb");
142         if (!fp) {
143            fprintf(stderr, "Unable to read input binary file : %s\n",
144                    binary_path);
145            /* free binary_path if path is wrong */
146            free(binary_path);
147            exit(EXIT_FAILURE);
148         }
149         break;
150      default:
151         /* Clean up binary path if given option is wrong */
152         if (binary_path) {
153            free(binary_path);
154            fclose(fp);
155         }
156         break;
157      }
158   }
159
160   if (help || !binary_path || !pci_id) {
161      print_help(argv[0], stderr);
162      exit(0);
163   }
164
165   devinfo = i965_disasm_init(pci_id);
166   if (!devinfo) {
167      fprintf(stderr, "Unable to allocate memory for "
168                      "gen_device_info struct instance.\n");
169      exit(EXIT_FAILURE);
170   }
171
172   assembly = i965_disasm_read_binary(fp, &end);
173   if (!assembly) {
174      if (end)
175        fprintf(stderr, "Unable to allocate buffer to read binary file\n");
176      else
177        fprintf(stderr, "Input file is empty\n");
178
179      exit(EXIT_FAILURE);
180   }
181
182   /* Disassemble i965 instructions from buffer assembly */
183   brw_disassemble(devinfo, assembly, start, end, stdout);
184
185   free(binary_path);
186   free(assembly);
187   free(devinfo);
188
189   return EXIT_SUCCESS;
190}
191