decompile_tokens.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (c) 2015-2016, 2018, 2020, 2022-2024
  4. # by Rocky Bernstein <rb@dustyfeet.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. """
  20. Command-line interface to first phase of decompliation -
  21. taking a disassembly and "tokenizing" this to make it easier for
  22. parsing.
  23. """
  24. import getopt
  25. import os
  26. import sys
  27. from decompyle3.disas import disassemble_file
  28. from decompyle3.version import __version__
  29. program = "decompile-tokens"
  30. __doc__ = """
  31. Usage:
  32. {0} [OPTIONS]... FILE
  33. {0} [--help | -h | -V | --version]
  34. Disassemble/Tokenize FILE with in the way that is done to assist
  35. decompyle3 in parsing the instruction stream. For example instructions
  36. with variable-length arguments like CALL_FUNCTION and BUILD_LIST have
  37. argument counts appended to the instruction name, and COME_FROM pseudo
  38. instructions are inserted into the instruction stream. Bit flag
  39. values encoded in an operand are expanding, EXTENDED_ARG value are
  40. folded into the following instruction operand.
  41. Like the parser, you may find this more high-level and or helpful.
  42. However if you want a true disassembler see the Standard built-in
  43. Python library module "dis", or pydisasm from the cross-version
  44. Python bytecode package "xdis".
  45. Examples:
  46. {0} foo.pyc
  47. {0} foo.py # same thing as above but find the file
  48. {0} foo.pyc bar.pyc # disassemble foo.pyc and bar.pyc
  49. See also `pydisasm' from the `xdis' package.
  50. Options:
  51. -V | --version show version and stop
  52. -h | --help show this message
  53. """.format(
  54. program
  55. )
  56. PATTERNS = ("*.pyc", "*.pyo")
  57. def main():
  58. usage_short = f"""usage: {program} FILE...
  59. Type -h for for full help."""
  60. if len(sys.argv) == 1:
  61. print("No file(s) given", file=sys.stderr)
  62. print(usage_short, file=sys.stderr)
  63. sys.exit(1)
  64. try:
  65. opts, files = getopt.getopt(
  66. sys.argv[1:], "hVU", ["help", "version", "decompyle3"]
  67. )
  68. except getopt.GetoptError as e:
  69. print(f"{os.path.basename(sys.argv[0])}: {e}", file=sys.stderr)
  70. sys.exit(-1)
  71. for opt, val in opts:
  72. if opt in ("-h", "--help"):
  73. print(__doc__)
  74. sys.exit(1)
  75. elif opt in ("-V", "--version"):
  76. print(f"{program} {__version__}")
  77. sys.exit(0)
  78. else:
  79. print(opt)
  80. print(usage_short, file=sys.stderr)
  81. sys.exit(1)
  82. for file in files:
  83. if os.path.exists(files[0]):
  84. disassemble_file(file, sys.stdout)
  85. else:
  86. print(f"Can't read {files[0]} - skipping", file=sys.stderr)
  87. pass
  88. pass
  89. return
  90. if __name__ == "__main__":
  91. main()