dis.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
  15. #include <stdio.h> // Need fileno
  16. #include <unistd.h>
  17. #endif
  18. #include <cstdio>
  19. #include <cstring>
  20. #include <string>
  21. #include <vector>
  22. #include "spirv-tools/libspirv.h"
  23. #include "tools/io.h"
  24. #include "tools/util/flags.h"
  25. static const std::string kHelpText = R"(%s - Disassemble a SPIR-V binary module
  26. Usage: %s [options] [<filename>]
  27. The SPIR-V binary is read from <filename>. If no file is specified,
  28. or if the filename is "-", then the binary is read from standard input.
  29. A text-based hex stream is also accepted as binary input, which should either
  30. consist of 32-bit words or 8-bit bytes. The 0x or x prefix is optional, but
  31. should be consistently present in the stream.
  32. Options:
  33. -h, --help Print this help.
  34. --version Display disassembler version information.
  35. -o <filename> Set the output filename.
  36. Output goes to standard output if this option is
  37. not specified, or if the filename is "-".
  38. --color Force color output. The default when printing to a terminal.
  39. Overrides a previous --no-color option.
  40. --no-color Don't print in color. Overrides a previous --color option.
  41. The default when output goes to something other than a
  42. terminal (e.g. a file, a pipe, or a shell redirection).
  43. --no-indent Don't indent instructions.
  44. --no-header Don't output the header as leading comments.
  45. --raw-id Show raw Id values instead of friendly names.
  46. --nested-indent Indentation is adjusted to indicate nesting in structured
  47. control flow.
  48. --reorder-blocks Reorder blocks to match the structured control flow of SPIR-V.
  49. With this option, the order of instructions will no longer
  50. match the input binary, but the result will be more readable.
  51. --offsets Show byte offsets for each instruction.
  52. --comment Add comments to make reading easier
  53. )";
  54. // clang-format off
  55. FLAG_SHORT_bool (h, /* default_value= */ false, /* required= */ false);
  56. FLAG_SHORT_string(o, /* default_value= */ "-", /* required= */ false);
  57. FLAG_LONG_bool (help, /* default_value= */ false, /* required= */false);
  58. FLAG_LONG_bool (version, /* default_value= */ false, /* required= */ false);
  59. FLAG_LONG_bool (color, /* default_value= */ false, /* required= */ false);
  60. FLAG_LONG_bool (no_color, /* default_value= */ false, /* required= */ false);
  61. FLAG_LONG_bool (no_indent, /* default_value= */ false, /* required= */ false);
  62. FLAG_LONG_bool (no_header, /* default_value= */ false, /* required= */ false);
  63. FLAG_LONG_bool (raw_id, /* default_value= */ false, /* required= */ false);
  64. FLAG_LONG_bool (nested_indent, /* default_value= */ false, /* required= */ false);
  65. FLAG_LONG_bool (reorder_blocks, /* default_value= */ false, /* required= */ false);
  66. FLAG_LONG_bool (offsets, /* default_value= */ false, /* required= */ false);
  67. FLAG_LONG_bool (comment, /* default_value= */ false, /* required= */ false);
  68. // clang-format on
  69. static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
  70. int main(int, const char** argv) {
  71. if (!flags::Parse(argv)) {
  72. return 1;
  73. }
  74. if (flags::h.value() || flags::help.value()) {
  75. printf(kHelpText.c_str(), argv[0], argv[0]);
  76. return 0;
  77. }
  78. if (flags::version.value()) {
  79. printf("%s\n", spvSoftwareVersionDetailsString());
  80. printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment));
  81. return 0;
  82. }
  83. if (flags::positional_arguments.size() > 1) {
  84. fprintf(stderr, "error: more than one input file specified.\n");
  85. return 1;
  86. }
  87. const std::string inFile = flags::positional_arguments.size() == 0
  88. ? "-"
  89. : flags::positional_arguments[0];
  90. const std::string outFile = flags::o.value();
  91. bool color_is_possible =
  92. #if SPIRV_COLOR_TERMINAL
  93. true;
  94. #else
  95. false;
  96. #endif
  97. uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;
  98. if (!flags::no_indent.value()) options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
  99. if (flags::offsets.value())
  100. options |= SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET;
  101. if (flags::no_header.value()) options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER;
  102. if (!flags::raw_id.value())
  103. options |= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
  104. if (flags::nested_indent.value())
  105. options |= SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT;
  106. if (flags::reorder_blocks.value())
  107. options |= SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS;
  108. if (flags::comment.value()) options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT;
  109. if (flags::o.value() == "-") {
  110. // Print to standard output.
  111. options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
  112. if (color_is_possible && !flags::no_color.value()) {
  113. bool output_is_tty = true;
  114. #if defined(_POSIX_VERSION)
  115. output_is_tty = isatty(fileno(stdout));
  116. #endif
  117. if (output_is_tty || flags::color.value()) {
  118. options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
  119. }
  120. }
  121. }
  122. // Read the input binary.
  123. std::vector<uint32_t> contents;
  124. if (!ReadBinaryFile(inFile.c_str(), &contents)) return 1;
  125. // If printing to standard output, then spvBinaryToText should
  126. // do the printing. In particular, colour printing on Windows is
  127. // controlled by modifying console objects synchronously while
  128. // outputting to the stream rather than by injecting escape codes
  129. // into the output stream.
  130. // If the printing option is off, then save the text in memory, so
  131. // it can be emitted later in this function.
  132. const bool print_to_stdout = SPV_BINARY_TO_TEXT_OPTION_PRINT & options;
  133. spv_text text = nullptr;
  134. spv_text* textOrNull = print_to_stdout ? nullptr : &text;
  135. spv_diagnostic diagnostic = nullptr;
  136. spv_context context = spvContextCreate(kDefaultEnvironment);
  137. spv_result_t error =
  138. spvBinaryToText(context, contents.data(), contents.size(), options,
  139. textOrNull, &diagnostic);
  140. spvContextDestroy(context);
  141. if (error) {
  142. spvDiagnosticPrint(diagnostic);
  143. spvDiagnosticDestroy(diagnostic);
  144. return error;
  145. }
  146. if (!print_to_stdout) {
  147. if (!WriteFile<char>(outFile.c_str(), "w", text->str, text->length)) {
  148. spvTextDestroy(text);
  149. return 1;
  150. }
  151. }
  152. spvTextDestroy(text);
  153. return 0;
  154. }