File: dis.cpp

package info (click to toggle)
spirv-tools 2025.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 28,588 kB
  • sloc: cpp: 470,407; javascript: 5,893; python: 3,326; ansic: 488; sh: 450; ruby: 88; makefile: 18; lisp: 9
file content (193 lines) | stat: -rw-r--r-- 7,074 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <stdio.h>  // Need fileno
#include <unistd.h>
#endif

#include <cstdio>
#include <cstring>
#include <string>
#include <vector>

#include "spirv-tools/libspirv.h"
#include "tools/io.h"
#include "tools/util/flags.h"

static const std::string kHelpText = R"(%s - Disassemble a SPIR-V binary module

Usage: %s [options] [<filename>]

The SPIR-V binary is read from <filename>. If no file is specified,
or if the filename is "-", then the binary is read from standard input.

A text-based hex stream is also accepted as binary input, which should either
consist of 32-bit words or 8-bit bytes.  The 0x or x prefix is optional, but
should be consistently present in the stream.

Options:

  -h, --help        Print this help.
  --version         Display disassembler version information.

  -o <filename>     Set the output filename.
                    Output goes to standard output if this option is
                    not specified, or if the filename is "-".

  --color           Force color output.  The default when printing to a terminal.
                    Overrides a previous --no-color option.
  --no-color        Don't print in color.  Overrides a previous --color option.
                    The default when output goes to something other than a
                    terminal (e.g. a file, a pipe, or a shell redirection).

  --no-indent       Don't indent instructions.

  --no-header       Don't output the header as leading comments.

  --raw-id          Show raw Id values instead of friendly names.

  --nested-indent   Indentation is adjusted to indicate nesting in structured
                    control flow.

  --reorder-blocks  Reorder blocks to match the structured control flow of SPIR-V.
                    With this option, the order of instructions will no longer
                    match the input binary, but the result will be more readable.

  --offsets         Show byte offsets for each instruction.

  --comment         Add comments to make reading easier
)";

// clang-format off
FLAG_SHORT_bool  (h,              /* default_value= */ false, /* required= */ false);
FLAG_SHORT_string(o,              /* default_value= */ "-",   /* required= */ false);
FLAG_LONG_bool   (help,           /* default_value= */ false, /* required= */false);
FLAG_LONG_bool   (version,        /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (color,          /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (no_color,       /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (no_indent,      /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (no_header,      /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (raw_id,         /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (nested_indent,  /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (reorder_blocks, /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (offsets,        /* default_value= */ false, /* required= */ false);
FLAG_LONG_bool   (comment,        /* default_value= */ false, /* required= */ false);
// clang-format on

static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;

int main(int, const char** argv) {
  if (!flags::Parse(argv)) {
    return 1;
  }

  if (flags::h.value() || flags::help.value()) {
    printf(kHelpText.c_str(), argv[0], argv[0]);
    return 0;
  }

  if (flags::version.value()) {
    printf("%s\n", spvSoftwareVersionDetailsString());
    printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment));
    return 0;
  }

  if (flags::positional_arguments.size() > 1) {
    fprintf(stderr, "error: more than one input file specified.\n");
    return 1;
  }

  const std::string inFile = flags::positional_arguments.size() == 0
                                 ? "-"
                                 : flags::positional_arguments[0];
  const std::string outFile = flags::o.value();

  bool color_is_possible =
#if SPIRV_COLOR_TERMINAL
      true;
#else
      false;
#endif

  uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;

  if (!flags::no_indent.value()) options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;

  if (flags::offsets.value())
    options |= SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET;

  if (flags::no_header.value()) options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER;

  if (!flags::raw_id.value())
    options |= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;

  if (flags::nested_indent.value())
    options |= SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT;

  if (flags::reorder_blocks.value())
    options |= SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS;

  if (flags::comment.value()) options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT;

  if (flags::o.value() == "-") {
    // Print to standard output.
    options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
    if (color_is_possible && !flags::no_color.value()) {
      bool output_is_tty = true;
#if defined(_POSIX_VERSION)
      output_is_tty = isatty(fileno(stdout));
#endif
      if (output_is_tty || flags::color.value()) {
        options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
      }
    }
  }

  // Read the input binary.
  std::vector<uint32_t> contents;
  if (!ReadBinaryFile(inFile.c_str(), &contents)) return 1;

  // If printing to standard output, then spvBinaryToText should
  // do the printing.  In particular, colour printing on Windows is
  // controlled by modifying console objects synchronously while
  // outputting to the stream rather than by injecting escape codes
  // into the output stream.
  // If the printing option is off, then save the text in memory, so
  // it can be emitted later in this function.
  const bool print_to_stdout = SPV_BINARY_TO_TEXT_OPTION_PRINT & options;
  spv_text text = nullptr;
  spv_text* textOrNull = print_to_stdout ? nullptr : &text;
  spv_diagnostic diagnostic = nullptr;
  spv_context context = spvContextCreate(kDefaultEnvironment);
  spv_result_t error =
      spvBinaryToText(context, contents.data(), contents.size(), options,
                      textOrNull, &diagnostic);
  spvContextDestroy(context);
  if (error) {
    spvDiagnosticPrint(diagnostic);
    spvDiagnosticDestroy(diagnostic);
    return error;
  }

  if (!print_to_stdout) {
    if (!WriteFile<char>(outFile.c_str(), "w", text->str, text->length)) {
      spvTextDestroy(text);
      return 1;
    }
  }
  spvTextDestroy(text);

  return 0;
}