Ruff: reformat tools (part 3/3: perf .. win). Preserve yapf style to the best capacity. LSC doc: https://docs.google.com/document/d/1P6AE9aeKuFkxPAYInYxLFIpDgpiCAT-S_BQkNU0lb3s/edit?tab=t.0 Onboarded using the following command: `~/cr/depot_tools/ruff_chromium format .` NO_IFTTT=reformatting only. BYPASS_RECITATION_REASON=reformatting only. Bug: 40874143 Change-Id: I971d8d3ad1a0dee3998a9eaa25c0617c6a6a6964 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8254624 Commit-Queue: Junji Watanabe <jwata@google.com> Owners-Override: Alex Ovsienko <ovsienko@google.com> SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com> Commit-Queue: Alex Ovsienko <ovsienko@google.com> Auto-Submit: Alex Ovsienko <ovsienko@google.com> Reviewed-by: Junji Watanabe <jwata@google.com> Cr-Commit-Position: refs/heads/main@{#1680337} NOKEYCHECK=True GitOrigin-RevId: 54e9909c3189a77bc8d353662628e4c5d6686290
diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..e6c408d --- /dev/null +++ b/.ruff.toml
@@ -0,0 +1,5 @@ +line-length = 80 +indent-width = 4 + +[format] +quote-style = "preserve"
diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index 557fa7b..0000000 --- a/.style.yapf +++ /dev/null
@@ -1,2 +0,0 @@ -[style] -based_on_style = pep8
diff --git a/google/.ruff.toml b/google/.ruff.toml new file mode 100644 index 0000000..d121cb9 --- /dev/null +++ b/google/.ruff.toml
@@ -0,0 +1,5 @@ +line-length = 80 +indent-width = 2 + +[format] +quote-style = "preserve"
diff --git a/google/.style.yapf b/google/.style.yapf deleted file mode 100644 index b4ebbe2..0000000 --- a/google/.style.yapf +++ /dev/null
@@ -1,6 +0,0 @@ -[style] -based_on_style = pep8 - -# New directories should use a .style.yapf that does not include the following: -column_limit = 80 -indent_width = 2
diff --git a/google/gethash_timer.py b/google/gethash_timer.py index be4c359..773463d 100755 --- a/google/gethash_timer.py +++ b/google/gethash_timer.py
@@ -30,7 +30,8 @@ _GETHASH_HOST = 'safebrowsing.clients.google.com' _GETHASH_REQUEST = ( - '/safebrowsing/gethash?client=googleclient&appver=1.0&pver=2.1') + '/safebrowsing/gethash?client=googleclient&appver=1.0&pver=2.1' +) # Global logging file handle. g_file_handle = None @@ -123,9 +124,9 @@ period = 10 samples = None - options, args = getopt.getopt(sys.argv[1:], - 's:p:o:', - ['samples=', 'period=', 'output=']) + options, args = getopt.getopt( + sys.argv[1:], 's:p:o:', ['samples=', 'period=', 'output='] + ) for option, value in options: if option == '-s' or option == '--samples': samples = int(value)
diff --git a/google/httpd_utils.py b/google/httpd_utils.py index 151b482..102b485 100755 --- a/google/httpd_utils.py +++ b/google/httpd_utils.py
@@ -18,7 +18,10 @@ import google.path_utils import google.platform_utils -class HttpdNotStarted(Exception): pass + +class HttpdNotStarted(Exception): + pass + def UrlIsAlive(url): """Checks to see if we get an http response from |url|. @@ -45,18 +48,21 @@ return False + def ApacheConfigDir(start_dir): """Returns a path to the directory holding the Apache config files.""" - return google.path_utils.FindUpward(start_dir, 'tools', 'python', - 'google', 'httpd_config') + return google.path_utils.FindUpward( + start_dir, 'tools', 'python', 'google', 'httpd_config' + ) def GetCygserverPath(start_dir, apache2=False): """Returns the path to the directory holding cygserver.exe file.""" cygserver_path = None if apache2: - cygserver_path = google.path_utils.FindUpward(start_dir, 'third_party', - 'cygwin', 'usr', 'sbin') + cygserver_path = google.path_utils.FindUpward( + start_dir, 'third_party', 'cygwin', 'usr', 'sbin' + ) return cygserver_path @@ -85,14 +91,16 @@ else: httpd_conf_path = os.path.join(apache_config_dir, 'httpd.conf') mime_types_path = os.path.join(apache_config_dir, 'mime.types') - start_cmd = platform_util.GetStartHttpdCommand(output_dir, - httpd_conf_path, - mime_types_path, - document_root, - apache2=apache2) + start_cmd = platform_util.GetStartHttpdCommand( + output_dir, httpd_conf_path, mime_types_path, document_root, apache2=apache2 + ) stop_cmd = platform_util.GetStopHttpdCommand() - httpd = ApacheHttpd(start_cmd, stop_cmd, [8000], - cygserver_path=GetCygserverPath(script_dir, apache2)) + httpd = ApacheHttpd( + start_cmd, + stop_cmd, + [8000], + cygserver_path=GetCygserverPath(script_dir, apache2), + ) httpd.StartServer() return httpd @@ -111,22 +119,27 @@ """ script_dir = google.path_utils.ScriptDir() platform_util = google.platform_utils.PlatformUtility(script_dir) - httpd = ApacheHttpd('', platform_util.GetStopHttpdCommand(), [], - cygserver_path=GetCygserverPath(script_dir, apache2)) + httpd = ApacheHttpd( + '', + platform_util.GetStopHttpdCommand(), + [], + cygserver_path=GetCygserverPath(script_dir, apache2), + ) httpd.StopServer(force=True) class ApacheHttpd(object): - def __init__(self, start_command, stop_command, port_list, - cygserver_path=None): + def __init__( + self, start_command, stop_command, port_list, cygserver_path=None + ): """Args: - start_command: command list to call to start the httpd - stop_command: command list to call to stop the httpd if one has been - started. May kill all httpd processes running on the machine. - port_list: list of ports expected to respond on the local machine when - the server has been successfully started. - cygserver_path: Path to cygserver.exe. If specified, exe will be started - with server as well as stopped when server is stopped. + start_command: command list to call to start the httpd + stop_command: command list to call to stop the httpd if one has been + started. May kill all httpd processes running on the machine. + port_list: list of ports expected to respond on the local machine when + the server has been successfully started. + cygserver_path: Path to cygserver.exe. If specified, exe will be started + with server as well as stopped when server is stopped. """ self._http_server_proc = None self._start_command = start_command @@ -139,8 +152,9 @@ return if self._cygserver_path: cygserver_exe = os.path.join(self._cygserver_path, "cygserver.exe") - cygbin = google.path_utils.FindUpward(cygserver_exe, 'third_party', - 'cygwin', 'bin') + cygbin = google.path_utils.FindUpward( + cygserver_exe, 'third_party', 'cygwin', 'bin' + ) env = os.environ env['PATH'] += ";" + cygbin subprocess.Popen(cygserver_exe, env=env) @@ -160,16 +174,19 @@ """ if force or self._http_server_proc: logging.info('Stopping http server') - kill_proc = subprocess.Popen(self._stop_command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - logging.info('%s\n%s' % (kill_proc.stdout.read(), - kill_proc.stderr.read())) + kill_proc = subprocess.Popen( + self._stop_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + logging.info( + '%s\n%s' % (kill_proc.stdout.read(), kill_proc.stderr.read()) + ) self._http_server_proc = None if self._cygserver_path: - subprocess.Popen(["taskkill.exe", "/f", "/im", "cygserver.exe"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + subprocess.Popen( + ["taskkill.exe", "/f", "/im", "cygserver.exe"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) def main(): @@ -178,14 +195,20 @@ option_parser = optparse.OptionParser() option_parser.add_option('-k', '--server', help='Server action (start|stop)') option_parser.add_option('-r', '--root', help='Document root (optional)') - option_parser.add_option('-a', '--apache2', action='store_true', - default=False, help='Starts Apache 2 instead of Apache 1.3 (default). ' - 'Ignored on Mac (apache2 is used always)') + option_parser.add_option( + '-a', + '--apache2', + action='store_true', + default=False, + help='Starts Apache 2 instead of Apache 1.3 (default). ' + 'Ignored on Mac (apache2 is used always)', + ) options, args = option_parser.parse_args() if not options.server: - print("Usage: %s -k {start|stop} [-r document_root] [--apache2]" % - sys.argv[0]) + print( + "Usage: %s -k {start|stop} [-r document_root] [--apache2]" % sys.argv[0] + ) return 1 document_root = None
diff --git a/google/logging_utils.py b/google/logging_utils.py index 79e5363..b1eef9c 100644 --- a/google/logging_utils.py +++ b/google/logging_utils.py
@@ -2,25 +2,25 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -''' Utility functions and objects for logging. -''' +'''Utility functions and objects for logging.''' import logging import sys + class StdoutStderrHandler(logging.Handler): - ''' Subclass of logging.Handler which outputs to either stdout or stderr + '''Subclass of logging.Handler which outputs to either stdout or stderr based on a threshold level. ''' def __init__(self, threshold=logging.WARNING, err=sys.stderr, out=sys.stdout): - ''' Args: - threshold: below this logging level messages are sent to stdout, - otherwise they are sent to stderr - err: a stream object that error messages are sent to, defaults to - sys.stderr - out: a stream object that non-error messages are sent to, defaults to - sys.stdout + '''Args: + threshold: below this logging level messages are sent to stdout, + otherwise they are sent to stderr + err: a stream object that error messages are sent to, defaults to + sys.stderr + out: a stream object that non-error messages are sent to, defaults to + sys.stdout ''' logging.Handler.__init__(self) self._err = logging.StreamHandler(err) @@ -59,9 +59,11 @@ FORMAT = "%(asctime)s %(filename)s [%(levelname)s] %(message)s" DATEFMT = "%H:%M:%S" -def config_root(level=logging.INFO, threshold=logging.WARNING, format=FORMAT, - datefmt=DATEFMT): - ''' Configure the root logger to use a StdoutStderrHandler and some default + +def config_root( + level=logging.INFO, threshold=logging.WARNING, format=FORMAT, datefmt=DATEFMT +): + '''Configure the root logger to use a StdoutStderrHandler and some default formatting. Args: level: messages below this level are ignored
diff --git a/google/path_utils.py b/google/path_utils.py index c4012ec..675fb1f 100644 --- a/google/path_utils.py +++ b/google/path_utils.py
@@ -6,18 +6,21 @@ # TODO(pamg): Have the buildbot use these, too. - import errno import os import sys -class PathNotFound(Exception): pass + +class PathNotFound(Exception): + pass + def ScriptDir(): """Get the full path to the directory containing the current script.""" script_filename = os.path.abspath(sys.argv[0]) return os.path.dirname(script_filename) + def FindAncestor(start_dir, ancestor): """Finds an ancestor dir in a path. @@ -35,6 +38,7 @@ path = parent raise PathNotFound("Unable to find ancestor %s in %s" % (ancestor, start_dir)) + def FindUpwardParent(start_dir, *desired_list): """Finds the desired object's parent, searching upward from the start_dir. @@ -51,14 +55,15 @@ last_dir = cur_dir cur_dir = os.path.dirname(cur_dir) if last_dir == cur_dir: - raise PathNotFound('Unable to find %s above %s' % - (desired_path, start_dir)) + raise PathNotFound( + 'Unable to find %s above %s' % (desired_path, start_dir) + ) found_path = os.path.join(cur_dir, desired_path) # Strip the entire original desired path from the end of the one found # and remove a trailing path separator, if present. - found_path = found_path[:len(found_path) - len(desired_path)] + found_path = found_path[: len(found_path) - len(desired_path)] if found_path.endswith(os.sep): - found_path = found_path[:len(found_path) - 1] + found_path = found_path[: len(found_path) - 1] return found_path
diff --git a/google/platform_utils_linux.py b/google/platform_utils_linux.py index 22c03cf..2f56972 100644 --- a/google/platform_utils_linux.py +++ b/google/platform_utils_linux.py
@@ -13,7 +13,7 @@ class PlatformUtility(object): def __init__(self, base_dir): """Args: - base_dir: the base dir for running tests. + base_dir: the base dir for running tests. """ self._base_dir = base_dir self._httpd_cmd_string = None # used for starting/stopping httpd @@ -55,9 +55,14 @@ return "%s://127.0.0.1:%d/%s" % (protocol, port, path) return "file://" + path - def GetStartHttpdCommand(self, output_dir, - httpd_conf_path, mime_types_path, - document_root=None, apache2=False): + def GetStartHttpdCommand( + self, + output_dir, + httpd_conf_path, + mime_types_path, + document_root=None, + apache2=False, + ): """Prepares the config file and output directory to start an httpd server. Returns a list of strings containing the server's command line+args. @@ -77,23 +82,25 @@ """ exe_name = "apache2" - cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', - 'python', 'google', - 'httpd_config', 'httpd2.pem') + cert_file = google.path_utils.FindUpward( + self._base_dir, 'tools', 'python', 'google', 'httpd_config', 'httpd2.pem' + ) ssl_enabled = os.path.exists('/etc/apache2/mods-enabled/ssl.conf') httpd_vars = { - "httpd_executable_path": - os.path.join(self._UnixRoot(), "usr", "sbin", exe_name), + "httpd_executable_path": os.path.join( + self._UnixRoot(), "usr", "sbin", exe_name + ), "httpd_conf_path": httpd_conf_path, "ssl_certificate_file": cert_file, - "document_root" : document_root, + "document_root": document_root, "server_root": os.path.join(self._UnixRoot(), "usr"), "mime_types_path": mime_types_path, "output_dir": output_dir, - "ssl_mutex": "file:"+os.path.join(output_dir, "ssl_mutex"), - "ssl_session_cache": - "shmcb:" + os.path.join(output_dir, "ssl_scache") + "(512000)", + "ssl_mutex": "file:" + os.path.join(output_dir, "ssl_mutex"), + "ssl_session_cache": "shmcb:" + + os.path.join(output_dir, "ssl_scache") + + "(512000)", "user": os.environ.get("USER", "#%d" % os.geteuid()), "lock_file": os.path.join(output_dir, "accept.lock"), } @@ -142,7 +149,7 @@ """ if not self._httpd_cmd_string: - return ["true"] # Haven't been asked for the start cmd yet. Just pass. + return ["true"] # Haven't been asked for the start cmd yet. Just pass. # Add a sleep after the shutdown because sometimes it takes some time for # the port to be available again. return [self._bash, "-c", self._httpd_cmd_string + ' -k stop && sleep 5']
diff --git a/google/platform_utils_mac.py b/google/platform_utils_mac.py index d531635..b98f00e 100644 --- a/google/platform_utils_mac.py +++ b/google/platform_utils_mac.py
@@ -13,7 +13,7 @@ class PlatformUtility(object): def __init__(self, base_dir): """Args: - base_dir: the base dir for running tests. + base_dir: the base dir for running tests. """ self._base_dir = base_dir self._httpd_cmd_string = None # used for starting/stopping httpd @@ -55,9 +55,14 @@ return "%s://127.0.0.1:%d/%s" % (protocol, port, path) return "file://" + path - def GetStartHttpdCommand(self, output_dir, - httpd_conf_path, mime_types_path, - document_root=None, apache2=False): + def GetStartHttpdCommand( + self, + output_dir, + httpd_conf_path, + mime_types_path, + document_root=None, + apache2=False, + ): """Prepares the config file and output directory to start an httpd server. Returns a list of strings containing the server's command line+args. @@ -77,21 +82,22 @@ """ exe_name = "httpd" - cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', - 'python', 'google', - 'httpd_config', 'httpd2.pem') + cert_file = google.path_utils.FindUpward( + self._base_dir, 'tools', 'python', 'google', 'httpd_config', 'httpd2.pem' + ) ssl_enabled = os.path.exists('/etc/apache2/mods-enabled/ssl.conf') httpd_vars = { - "httpd_executable_path": - os.path.join(self._UnixRoot(), "usr", "sbin", exe_name), + "httpd_executable_path": os.path.join( + self._UnixRoot(), "usr", "sbin", exe_name + ), "httpd_conf_path": httpd_conf_path, "ssl_certificate_file": cert_file, - "document_root" : document_root, + "document_root": document_root, "server_root": os.path.join(self._UnixRoot(), "usr"), "mime_types_path": mime_types_path, "output_dir": output_dir, - "ssl_mutex": "file:"+os.path.join(output_dir, "ssl_mutex"), + "ssl_mutex": "file:" + os.path.join(output_dir, "ssl_mutex"), "user": os.environ.get("USER", "#%d" % os.geteuid()), "lock_file": os.path.join(output_dir, "accept.lock"), } @@ -139,7 +145,7 @@ """ if not self._httpd_cmd_string: - return ["true"] # Haven't been asked for the start cmd yet. Just pass. + return ["true"] # Haven't been asked for the start cmd yet. Just pass. # Add a sleep after the shutdown because sometimes it takes some time for # the port to be available again. return [self._bash, "-c", self._httpd_cmd_string + ' -k stop && sleep 5']
diff --git a/google/platform_utils_win.py b/google/platform_utils_win.py index d0dc1c1..9679a4f 100644 --- a/google/platform_utils_win.py +++ b/google/platform_utils_win.py
@@ -14,11 +14,12 @@ # the PlatformUtility class. _cygpath_proc = None + class PlatformUtility(object): def __init__(self, base_dir): """Args: - base_dir: a directory above which third_party/cygwin can be found, - used to locate the cygpath executable for path conversions. + base_dir: a directory above which third_party/cygwin can be found, + used to locate the cygpath executable for path conversions. """ self._cygwin_root = None self._base_dir = base_dir @@ -26,8 +27,9 @@ def _CygwinRoot(self): """Returns the full path to third_party/cygwin/.""" if not self._cygwin_root: - self._cygwin_root = google.path_utils.FindUpward(self._base_dir, - 'third_party', 'cygwin') + self._cygwin_root = google.path_utils.FindUpward( + self._base_dir, 'third_party', 'cygwin' + ) return self._cygwin_root def _PathToExecutable(self, executable): @@ -45,11 +47,16 @@ return os.path.abspath(path) global _cygpath_proc if not _cygpath_proc: - cygpath_command = [self._PathToExecutable("cygpath.exe"), - "-a", "-m", "-f", "-"] - _cygpath_proc = subprocess.Popen(cygpath_command, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) + cygpath_command = [ + self._PathToExecutable("cygpath.exe"), + "-a", + "-m", + "-f", + "-", + ] + _cygpath_proc = subprocess.Popen( + cygpath_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) _cygpath_proc.stdin.write(path + "\n") return _cygpath_proc.stdout.readline().rstrip() @@ -87,9 +94,14 @@ return "%s://127.0.0.1:%s/%s" % (protocol, str(port), path) return "file:///" + self.GetAbsolutePath(path) - def GetStartHttpdCommand(self, output_dir, - httpd_conf_path, mime_types_path, - document_root=None, apache2=False): + def GetStartHttpdCommand( + self, + output_dir, + httpd_conf_path, + mime_types_path, + document_root=None, + apache2=False, + ): """Prepares the config file and output directory to start an httpd server. Returns a list of strings containing the server's command line+args. @@ -112,15 +124,21 @@ cert_file = "" if apache2: exe_name = "httpd2" - cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', - 'python', 'google', - 'httpd_config', 'httpd2.pem') + cert_file = google.path_utils.FindUpward( + self._base_dir, + 'tools', + 'python', + 'google', + 'httpd_config', + 'httpd2.pem', + ) httpd_vars = { "httpd_executable_path": GetCygwinPath( - os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name)), + os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name) + ), "httpd_conf_path": GetCygwinPath(httpd_conf_path), "ssl_certificate_file": GetCygwinPath(cert_file), - "document_root" : document_root, + "document_root": document_root, "server_root": GetCygwinPath(os.path.join(self._CygwinRoot(), "usr")), "mime_types_path": GetCygwinPath(mime_types_path), "output_dir": GetCygwinPath(output_dir), @@ -130,8 +148,9 @@ if not httpd_vars["user"]: # Failed to get the username from the environment; use whoami.exe # instead. - proc = subprocess.Popen(self._PathToExecutable("whoami.exe"), - stdout=subprocess.PIPE) + proc = subprocess.Popen( + self._PathToExecutable("whoami.exe"), stdout=subprocess.PIPE + ) httpd_vars["user"] = proc.stdout.read().strip() if not httpd_vars["user"]: @@ -157,8 +176,11 @@ ' -C \'ServerRoot "%(server_root)s"\'' ) if apache2: - httpd_cmd_string = ('export CYGWIN=server;' + httpd_cmd_string + - ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'') + httpd_cmd_string = ( + 'export CYGWIN=server;' + + httpd_cmd_string + + ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'' + ) if document_root: httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\'' @@ -173,10 +195,12 @@ # killing httpd processes that we didn't start. return ["taskkill.exe", "/f", "/im", "httpd*"] + ########################################################################### # This method is specific to windows, expected to be used only by *_win.py # files. + def GetCygwinPath(path): """Convert a Windows path to a cygwin path. @@ -188,7 +212,9 @@ The path is expected to be an absolute path, on any drive. """ drive_regexp = re.compile(r'([a-z]):[/\\]', re.IGNORECASE) + def LowerDrive(matchobj): return '/cygdrive/%s/' % matchobj.group(1).lower() + path = drive_regexp.sub(LowerDrive, path) return path.replace('\\', '/')
diff --git a/google/process_utils.py b/google/process_utils.py index a3e3dc2..8a7c72d 100644 --- a/google/process_utils.py +++ b/google/process_utils.py
@@ -10,7 +10,9 @@ import subprocess import sys -class CommandNotFound(Exception): pass + +class CommandNotFound(Exception): + pass TASKKILL = os.path.join(os.environ['WINDIR'], 'system32', 'taskkill.exe') @@ -20,6 +22,7 @@ PSKILL = 'pskill.exe' PSKILL_PROCESS_NOT_FOUND_ERR = -1 + def KillAll(executables): """Tries to kill all copies of each process in the processes list. Returns an error if any running processes couldn't be killed. @@ -39,8 +42,10 @@ result = new_error return result -def RunCommandFull(command, verbose=True, collect_output=False, - print_output=True): + +def RunCommandFull( + command, verbose=True, collect_output=False, print_output=True +): """Runs the command list. Prints the given command (which should be a list of one or more strings). @@ -65,8 +70,8 @@ CommandNotFound if the command executable could not be found. """ print( - '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', - end=' ') + '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', end=' ' + ) if verbose: out = subprocess.PIPE @@ -116,6 +121,7 @@ out.close() return (proc.returncode, output) + def RunCommand(command, verbose=True): """Runs the command list, printing its output and returning its exit status. @@ -137,8 +143,10 @@ """ return RunCommandFull(command, verbose)[0] -def RunCommandsInParallel(commands, verbose=True, collect_output=False, - print_output=True): + +def RunCommandsInParallel( + commands, verbose=True, collect_output=False, print_output=True +): """Runs a list of commands in parallel, waits for all commands to terminate and returns their status. If specified, the ouput of commands can be returned and/or printed. @@ -167,8 +175,8 @@ for command in commands: print( - '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', - end=' ') + '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', end=' ' + ) if verbose: out = subprocess.PIPE
diff --git a/llvm_objdump.py b/llvm_objdump.py index a4b668a..e26f7b8 100644 --- a/llvm_objdump.py +++ b/llvm_objdump.py
@@ -8,8 +8,14 @@ import subprocess _CHROME_SRC = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) -_LLVM_OBJDUMP_PATH = os.path.join(_CHROME_SRC, 'third_party', 'llvm-build', - 'Release+Asserts', 'bin', 'llvm-objdump') +_LLVM_OBJDUMP_PATH = os.path.join( + _CHROME_SRC, + 'third_party', + 'llvm-build', + 'Release+Asserts', + 'bin', + 'llvm-objdump', +) # Function lines look like: # 000177b0 <android::IBinder::~IBinder()+0x2c>: @@ -24,114 +30,127 @@ def _StripPC(addr, cpu_arch): - """Strips the Thumb bit from a program counter address when appropriate. + """Strips the Thumb bit from a program counter address when appropriate. - Args: - addr: the program counter address - cpu_arch: Target CPU architecture. + Args: + addr: the program counter address + cpu_arch: Target CPU architecture. - Returns: - The stripped program counter address. - """ - if cpu_arch == "arm": - return addr & ~1 - return addr + Returns: + The stripped program counter address. + """ + if cpu_arch == "arm": + return addr & ~1 + return addr class ObjdumpInformation(object): - def __init__(self, address, library, symbol, offset): - self.address = address - self.library = library - self.symbol = symbol - self.offset = offset + def __init__(self, address, library, symbol, offset): + self.address = address + self.library = library + self.symbol = symbol + self.offset = offset class LLVMObjdumper(object): - def __init__(self): - """Creates an instance of LLVMObjdumper that interacts with llvm-objdump. - """ - self._llvm_objdump_parameters = [ - '--disassemble', - '--demangle', - '--section=.text', - ] + def __init__(self): + """Creates an instance of LLVMObjdumper that interacts with + llvm-objdump. + """ + self._llvm_objdump_parameters = [ + '--disassemble', + '--demangle', + '--section=.text', + ] - def __enter__(self): - return self + def __enter__(self): + return self - def __exit__(self, exc_type, exc_val, exc_tb): - pass + def __exit__(self, exc_type, exc_val, exc_tb): + pass - @staticmethod - def GetSymbolDataFromObjdumpOutput(objdump_out, address, cpu_arch): - stripped_target_address = _StripPC(address, cpu_arch) - for line in objdump_out.split(os.linesep): - components = _FUNC.match(line) - if components: - # This is a new function, so record the current function and its - # address. - current_symbol_addr = int(components.group(1), 16) - current_symbol = components.group(2) + @staticmethod + def GetSymbolDataFromObjdumpOutput(objdump_out, address, cpu_arch): + stripped_target_address = _StripPC(address, cpu_arch) + for line in objdump_out.split(os.linesep): + components = _FUNC.match(line) + if components: + # This is a new function, so record the current function and its + # address. + current_symbol_addr = int(components.group(1), 16) + current_symbol = components.group(2) - # Does it have an optional offset like: "foo(..)+0x2c"? - components = _OFFSET.match(current_symbol) - if components: - current_symbol = components.group(1) - offset = components.group(2) - if offset: - current_symbol_addr -= int(offset, 16) + # Does it have an optional offset like: "foo(..)+0x2c"? + components = _OFFSET.match(current_symbol) + if components: + current_symbol = components.group(1) + offset = components.group(2) + if offset: + current_symbol_addr -= int(offset, 16) - # Is it a disassembly line like: "177b2: b510 push {r4, lr}"? - components = _ASM.match(line) - if components: - addr = components.group(1) - i_addr = int(addr, 16) - if i_addr == stripped_target_address: - return (current_symbol, stripped_target_address - current_symbol_addr) + # Is it a disassembly line like: + # "177b2: b510 push {r4, lr}"? + components = _ASM.match(line) + if components: + addr = components.group(1) + i_addr = int(addr, 16) + if i_addr == stripped_target_address: + return ( + current_symbol, + stripped_target_address - current_symbol_addr, + ) - return (None, None) + return (None, None) - def GetSymbolInformation(self, lib, address, cpu_arch): - """Returns the corresponding function names and line numbers. + def GetSymbolInformation(self, lib, address, cpu_arch): + """Returns the corresponding function names and line numbers. - Args: - lib: library to search for info. - address: address to look for info. - cpu_arch: architecture where the dump was taken + Args: + lib: library to search for info. + address: address to look for info. + cpu_arch: architecture where the dump was taken - Returns: - An ObjdumpInformation object - """ - if not os.path.isfile(_LLVM_OBJDUMP_PATH): - logging.error('Cannot find llvm-objdump. path=%s', _LLVM_OBJDUMP_PATH) - return None + Returns: + An ObjdumpInformation object + """ + if not os.path.isfile(_LLVM_OBJDUMP_PATH): + logging.error( + 'Cannot find llvm-objdump. path=%s', _LLVM_OBJDUMP_PATH + ) + return None - stripped_address = _StripPC(address, cpu_arch) + stripped_address = _StripPC(address, cpu_arch) - full_arguments = [_LLVM_OBJDUMP_PATH] + self._llvm_objdump_parameters - full_arguments.append('--start-address=' + str(stripped_address)) - full_arguments.append('--stop-address=' + str(stripped_address + 8)) - full_arguments.append(lib) + full_arguments = [_LLVM_OBJDUMP_PATH] + self._llvm_objdump_parameters + full_arguments.append('--start-address=' + str(stripped_address)) + full_arguments.append('--stop-address=' + str(stripped_address + 8)) + full_arguments.append(lib) - objdump_process = subprocess.Popen(full_arguments, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - universal_newlines=True) + objdump_process = subprocess.Popen( + full_arguments, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + universal_newlines=True, + ) - stdout, stderr = objdump_process.communicate() - objdump_process_return_code = objdump_process.poll() + stdout, stderr = objdump_process.communicate() + objdump_process_return_code = objdump_process.poll() - if objdump_process_return_code != 0: - logging.error( - 'Invocation of llvm-objdump failed!' + - ' tool-command-line=\'{}\', return-code={}, std-error=\'{}\''.format( - ' '.join(full_arguments), objdump_process_return_code, stderr)) - return None + if objdump_process_return_code != 0: + logging.error( + 'Invocation of llvm-objdump failed!' + + ' tool-command-line=\'{}\', return-code={}, std-error=\'{}\''.format( + ' '.join(full_arguments), + objdump_process_return_code, + stderr, + ) + ) + return None - symbol, offset = LLVMObjdumper.GetSymbolDataFromObjdumpOutput( - stdout, address, cpu_arch) + symbol, offset = LLVMObjdumper.GetSymbolDataFromObjdumpOutput( + stdout, address, cpu_arch + ) - return ObjdumpInformation(address=address, - library=lib, - symbol=symbol, - offset=offset) + return ObjdumpInformation( + address=address, library=lib, symbol=symbol, offset=offset + )
diff --git a/llvm_symbolizer.py b/llvm_symbolizer.py index a36aef1..06f79e1 100644 --- a/llvm_symbolizer.py +++ b/llvm_symbolizer.py
@@ -10,125 +10,137 @@ _CHROME_SRC = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) _LLVM_SYMBOLIZER_PATH = os.path.join( - _CHROME_SRC, 'third_party', 'llvm-build', 'Release+Asserts', 'bin', - 'llvm-symbolizer') + _CHROME_SRC, + 'third_party', + 'llvm-build', + 'Release+Asserts', + 'bin', + 'llvm-symbolizer', +) _UNKNOWN = '<UNKNOWN>' _ELF_MAGIC_HEADER_BYTES = b'\x7f\x45\x4c\x46' + @functools.lru_cache def IsValidLLVMSymbolizerTarget(file_path): - """ Verify the passed file is a valid target for llvm-symbolization + """Verify the passed file is a valid target for llvm-symbolization - Args: - file_path: Path to a file to be checked + Args: + file_path: Path to a file to be checked - Return: - True if the file exists and has the correct ELF header, False otherwise - """ - try: - with open(file_path, 'rb') as f: - header_bytes = f.read(4) - return header_bytes == _ELF_MAGIC_HEADER_BYTES - except IOError: - return False + Return: + True if the file exists and has the correct ELF header, False otherwise + """ + try: + with open(file_path, 'rb') as f: + header_bytes = f.read(4) + return header_bytes == _ELF_MAGIC_HEADER_BYTES + except IOError: + return False class LLVMSymbolizer(object): - def __init__(self): - """Create a LLVMSymbolizer instance that interacts with the llvm symbolizer. + def __init__(self): + """Create a LLVMSymbolizer instance that interacts with the llvm symbolizer. - The purpose of the LLVMSymbolizer is to get function names and line - numbers of an address from the symbols library. - """ - self._llvm_symbolizer_subprocess = None - self._llvm_symbolizer_parameters = [ - '--functions', - '--demangle', - '--inlines', - ] - - # Allow only one thread to call GetSymbolInformation at a time. - self._lock = threading.Lock() - - def Start(self): - """Start the llvm symbolizer subprocess. - - Create a subprocess of the llvm symbolizer executable, which will be used - to retrieve function names etc. - """ - if os.path.isfile(_LLVM_SYMBOLIZER_PATH): - self._llvm_symbolizer_subprocess = subprocess.Popen( - [_LLVM_SYMBOLIZER_PATH] + self._llvm_symbolizer_parameters, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - universal_newlines=True) - else: - logging.error('Cannot find llvm_symbolizer here: %s.' % - _LLVM_SYMBOLIZER_PATH) - self._llvm_symbolizer_subprocess = None - - def Close(self): - """Close the llvm symbolizer subprocess. - - Close the subprocess by closing stdin, stdout and killing the subprocess. - """ - with self._lock: - if self._llvm_symbolizer_subprocess: - self._llvm_symbolizer_subprocess.kill() + The purpose of the LLVMSymbolizer is to get function names and line + numbers of an address from the symbols library. + """ self._llvm_symbolizer_subprocess = None + self._llvm_symbolizer_parameters = [ + '--functions', + '--demangle', + '--inlines', + ] - def __enter__(self): - """Start the llvm symbolizer subprocess.""" - self.Start() - return self + # Allow only one thread to call GetSymbolInformation at a time. + self._lock = threading.Lock() - def __exit__(self, exc_type, exc_val, exc_tb): - """Close the llvm symbolizer subprocess.""" - self.Close() + def Start(self): + """Start the llvm symbolizer subprocess. - def GetSymbolInformation(self, lib, addr): - """Return the corresponding function names and line numbers. - - Args: - lib: library to search for info. - addr: address to look for info. - - Returns: - A triplet of address, module-name and list of symbols - """ - if (self._llvm_symbolizer_subprocess is None): - logging.error('Can\'t run llvm-symbolizer! ' + - 'Subprocess for llvm-symbolizer has not been started!') - return [(_UNKNOWN, lib)] - - if not lib: - logging.error('Can\'t run llvm-symbolizer! No target is given!') - return [(_UNKNOWN, lib)] - - if not IsValidLLVMSymbolizerTarget(lib): - logging.error( - 'Can\'t run llvm-symbolizer! ' + - 'Given binary is not a valid target. path=%s', lib) - return [(_UNKNOWN, lib)] - - proc = self._llvm_symbolizer_subprocess - with self._lock: - proc.stdin.write('%s %s\n' % (lib, hex(addr))) - proc.stdin.flush() - result = [] - # Read until an empty line is observed, which indicates the end of the - # output. Each line with a function name is always followed by one line - # with the corresponding line number. - while True: - line = proc.stdout.readline() - if line != '\n': - line_numbers = proc.stdout.readline() - result.append((line[:-1], line_numbers[:-1])) + Create a subprocess of the llvm symbolizer executable, which will be used + to retrieve function names etc. + """ + if os.path.isfile(_LLVM_SYMBOLIZER_PATH): + self._llvm_symbolizer_subprocess = subprocess.Popen( + [_LLVM_SYMBOLIZER_PATH] + self._llvm_symbolizer_parameters, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + universal_newlines=True, + ) else: - return result + logging.error( + 'Cannot find llvm_symbolizer here: %s.' % _LLVM_SYMBOLIZER_PATH + ) + self._llvm_symbolizer_subprocess = None - @staticmethod - def IsValidTarget(path): - return IsValidLLVMSymbolizerTarget(path) + def Close(self): + """Close the llvm symbolizer subprocess. + + Close the subprocess by closing stdin, stdout and killing the subprocess. + """ + with self._lock: + if self._llvm_symbolizer_subprocess: + self._llvm_symbolizer_subprocess.kill() + self._llvm_symbolizer_subprocess = None + + def __enter__(self): + """Start the llvm symbolizer subprocess.""" + self.Start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Close the llvm symbolizer subprocess.""" + self.Close() + + def GetSymbolInformation(self, lib, addr): + """Return the corresponding function names and line numbers. + + Args: + lib: library to search for info. + addr: address to look for info. + + Returns: + A triplet of address, module-name and list of symbols + """ + if self._llvm_symbolizer_subprocess is None: + logging.error( + 'Can\'t run llvm-symbolizer! ' + + 'Subprocess for llvm-symbolizer has not been started!' + ) + return [(_UNKNOWN, lib)] + + if not lib: + logging.error('Can\'t run llvm-symbolizer! No target is given!') + return [(_UNKNOWN, lib)] + + if not IsValidLLVMSymbolizerTarget(lib): + logging.error( + 'Can\'t run llvm-symbolizer! ' + + 'Given binary is not a valid target. path=%s', + lib, + ) + return [(_UNKNOWN, lib)] + + proc = self._llvm_symbolizer_subprocess + with self._lock: + proc.stdin.write('%s %s\n' % (lib, hex(addr))) + proc.stdin.flush() + result = [] + # Read until an empty line is observed, which indicates the end of the + # output. Each line with a function name is always followed by one line + # with the corresponding line number. + while True: + line = proc.stdout.readline() + if line != '\n': + line_numbers = proc.stdout.readline() + result.append((line[:-1], line_numbers[:-1])) + else: + return result + + @staticmethod + def IsValidTarget(path): + return IsValidLLVMSymbolizerTarget(path)