mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
e23d238e85
Commands now require a `setup` function, where the will register the command instance manually
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# This file is distributed under the MIT License. See LICENSE.md for details.
|
|
#
|
|
|
|
import os
|
|
import shutil
|
|
import sys
|
|
|
|
import pefile
|
|
import requests
|
|
|
|
from revng.cli.commands_registry import Command, CommandsRegistry, Options
|
|
from revng.cli.support import log_error
|
|
|
|
microsoft_symbol_server_url = "http://msdl.microsoft.com/download/symbols/"
|
|
|
|
|
|
class DownloadPDBCommand(Command):
|
|
def __init__(self):
|
|
super().__init__(("model", "download-pdb"), "Download missing PDBs for CRTs.")
|
|
|
|
def register_arguments(self, parser):
|
|
parser.add_argument("input", help="The input file.")
|
|
parser.add_argument("output", help="The output file.", nargs="?", default="/dev/stdout")
|
|
parser.add_argument(
|
|
"urls",
|
|
help="List of URLs where to try finding the PDB files.",
|
|
nargs="*",
|
|
default=[microsoft_symbol_server_url],
|
|
)
|
|
|
|
def log(self, message):
|
|
if self.verbose:
|
|
sys.stderr.write(message + "\n")
|
|
|
|
def download_pdb_file(self, url, local_filename):
|
|
with requests.get(url, stream=True) as r, open(local_filename, "wb") as f:
|
|
if r.status_code == 200:
|
|
shutil.copyfileobj(r.raw, f)
|
|
self.log("Downloaded.")
|
|
return True
|
|
else:
|
|
self.log("URL was not found.")
|
|
return False
|
|
|
|
return False
|
|
|
|
def run(self, options: Options):
|
|
args = options.parsed_args
|
|
self.verbose = args.verbose
|
|
|
|
if not os.path.exists(args.input):
|
|
log_error("Could not find " + args.input)
|
|
return 1
|
|
|
|
# Parse the file.
|
|
try:
|
|
pe = pefile.PE(args.input)
|
|
except Exception as exception:
|
|
log_error("Unable to parse the input file.")
|
|
log_error(str(exception))
|
|
return 1
|
|
|
|
for e in pe.DIRECTORY_ENTRY_DEBUG:
|
|
if not isinstance(e.entry, pefile.Structure):
|
|
continue
|
|
|
|
pdb_file_name = e.entry.PdbFileName.decode("utf-8")
|
|
pdb_file_name = pdb_file_name.replace("\x00", "")
|
|
# A hash for the PDB file.
|
|
pdb_id = (
|
|
str(hex(e.entry.Signature_Data1)[2:])
|
|
+ str(hex(e.entry.Signature_Data2)[2:])
|
|
+ str(hex(e.entry.Signature_Data3)[2:])
|
|
+ e.entry.Signature_Data4.hex()
|
|
+ str(hex(e.entry.Age)[2:])
|
|
)
|
|
self.log("PDBID: " + pdb_id)
|
|
|
|
for symbol_server_url in args.urls:
|
|
pdb_url = symbol_server_url + pdb_file_name + "/" + pdb_id + "/" + pdb_file_name
|
|
self.log("URL: " + pdb_url)
|
|
|
|
if self.download_pdb_file(pdb_url, args.output) is True:
|
|
return 0
|
|
break
|
|
|
|
return 0
|
|
|
|
|
|
def setup(commands_registry: CommandsRegistry):
|
|
commands_registry.register_command(DownloadPDBCommand())
|