mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Vendor mozdebug
and stop using distutils
(#30659)
The version of `mozdebug` installable via pip is two years old and Mozilla is slow to release new versions. It also uses `distutils` which doesn't work on newer Python versions. Vendor it and stop using `distutils` there.
This commit is contained in:
parent
4ea042cb14
commit
9d9c5d3ca9
4 changed files with 349 additions and 1 deletions
|
@ -20,6 +20,7 @@ WPT_SERVE_PATH = os.path.join(WPT_PATH, "tests", "tools", "wptserve")
|
|||
|
||||
SEARCH_PATHS = [
|
||||
os.path.join("python", "mach"),
|
||||
os.path.join("third_party", "mozdebug"),
|
||||
]
|
||||
|
||||
# Individual files providing mach commands.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
blessings == 1.7
|
||||
distro == 1.4
|
||||
mozdebug == 0.3
|
||||
mozinfo == 1.2.1
|
||||
mozlog == 7.1.0
|
||||
setuptools == 65.5.1
|
||||
|
|
32
third_party/mozdebug/mozdebug/__init__.py
vendored
Normal file
32
third_party/mozdebug/mozdebug/__init__.py
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
# flake8: noqa
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"""
|
||||
This module contains a set of function to gather information about the
|
||||
debugging capabilities of the platform. It allows to look for a specific
|
||||
debugger or to query the system for a compatible/default debugger.
|
||||
|
||||
The following simple example looks for the default debugger on the
|
||||
current platform and launches a debugger process with the correct
|
||||
debugger-specific arguments:
|
||||
|
||||
::
|
||||
|
||||
import mozdebug
|
||||
|
||||
debugger = mozdebug.get_default_debugger_name()
|
||||
debuggerInfo = mozdebug.get_debugger_info(debugger)
|
||||
|
||||
debuggeePath = "toDebug"
|
||||
|
||||
processArgs = [self.debuggerInfo.path] + self.debuggerInfo.args
|
||||
processArgs.append(debuggeePath)
|
||||
|
||||
run_process(args, ...)
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .mozdebug import *
|
316
third_party/mozdebug/mozdebug/mozdebug.py
vendored
Normal file
316
third_party/mozdebug/mozdebug/mozdebug.py
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import json
|
||||
import os
|
||||
import mozinfo
|
||||
import shutil
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from subprocess import check_output
|
||||
|
||||
__all__ = [
|
||||
"get_debugger_info",
|
||||
"get_default_debugger_name",
|
||||
"DebuggerSearch",
|
||||
"get_default_valgrind_args",
|
||||
"DebuggerInfo",
|
||||
]
|
||||
|
||||
"""
|
||||
Map of debugging programs to information about them, like default arguments
|
||||
and whether or not they are interactive.
|
||||
|
||||
To add support for a new debugger, simply add the relative entry in
|
||||
_DEBUGGER_INFO and optionally update the _DEBUGGER_PRIORITIES.
|
||||
"""
|
||||
_DEBUGGER_INFO = {
|
||||
# gdb requires that you supply the '--args' flag in order to pass arguments
|
||||
# after the executable name to the executable.
|
||||
"gdb": {"interactive": True, "args": ["-q", "--args"]},
|
||||
"cgdb": {"interactive": True, "args": ["-q", "--args"]},
|
||||
"rust-gdb": {"interactive": True, "args": ["-q", "--args"]},
|
||||
"lldb": {"interactive": True, "args": ["--"], "requiresEscapedArgs": True},
|
||||
# Visual Studio Debugger Support.
|
||||
"devenv.exe": {"interactive": True, "args": ["-debugexe"]},
|
||||
# Visual C++ Express Debugger Support.
|
||||
"wdexpress.exe": {"interactive": True, "args": ["-debugexe"]},
|
||||
# Windows Development Kit super-debugger.
|
||||
"windbg.exe": {
|
||||
"interactive": True,
|
||||
},
|
||||
}
|
||||
|
||||
# Maps each OS platform to the preferred debugger programs found in _DEBUGGER_INFO.
|
||||
_DEBUGGER_PRIORITIES = {
|
||||
"win": ["devenv.exe", "wdexpress.exe"],
|
||||
"linux": ["gdb", "cgdb", "lldb"],
|
||||
"mac": ["lldb", "gdb"],
|
||||
"android": ["lldb"],
|
||||
"unknown": ["gdb"],
|
||||
}
|
||||
|
||||
|
||||
DebuggerInfo = namedtuple(
|
||||
"DebuggerInfo", ["path", "interactive", "args", "requiresEscapedArgs"]
|
||||
)
|
||||
|
||||
|
||||
def _windbg_installation_paths():
|
||||
programFilesSuffixes = ["", " (x86)"]
|
||||
programFiles = "C:/Program Files"
|
||||
# Try the most recent versions first.
|
||||
windowsKitsVersions = ["10", "8.1", "8"]
|
||||
|
||||
for suffix in programFilesSuffixes:
|
||||
windowsKitsPrefix = os.path.join(programFiles + suffix, "Windows Kits")
|
||||
for version in windowsKitsVersions:
|
||||
yield os.path.join(
|
||||
windowsKitsPrefix, version, "Debuggers", "x64", "windbg.exe"
|
||||
)
|
||||
|
||||
|
||||
def _vswhere_path():
|
||||
try:
|
||||
import buildconfig
|
||||
|
||||
path = os.path.join(buildconfig.topsrcdir, "build", "win32", "vswhere.exe")
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
except ImportError:
|
||||
pass
|
||||
# Hope it's available on PATH!
|
||||
return "vswhere.exe"
|
||||
|
||||
|
||||
def get_debugger_path(debugger):
|
||||
"""
|
||||
Get the full path of the debugger.
|
||||
|
||||
:param debugger: The name of the debugger.
|
||||
"""
|
||||
|
||||
if mozinfo.os == "mac" and debugger == "lldb":
|
||||
# On newer OSX versions System Integrity Protections prevents us from
|
||||
# setting certain env vars for a process such as DYLD_LIBRARY_PATH if
|
||||
# it's in a protected directory such as /usr/bin. This is the case for
|
||||
# lldb, so we try to find an instance under the Xcode install instead.
|
||||
|
||||
# Attempt to use the xcrun util to find the path.
|
||||
try:
|
||||
path = check_output(
|
||||
["xcrun", "--find", "lldb"], universal_newlines=True
|
||||
).strip()
|
||||
if path:
|
||||
return path
|
||||
except Exception:
|
||||
# Just default to find_executable instead.
|
||||
pass
|
||||
|
||||
if mozinfo.os == "win" and debugger == "devenv.exe":
|
||||
# Attempt to use vswhere to find the path.
|
||||
try:
|
||||
encoding = "mbcs" if sys.platform == "win32" else "utf-8"
|
||||
vswhere = _vswhere_path()
|
||||
vsinfo = check_output([vswhere, "-format", "json", "-latest"])
|
||||
vsinfo = json.loads(vsinfo.decode(encoding, "replace"))
|
||||
return os.path.join(
|
||||
vsinfo[0]["installationPath"], "Common7", "IDE", "devenv.exe"
|
||||
)
|
||||
except Exception:
|
||||
# Just default to find_executable instead.
|
||||
pass
|
||||
|
||||
return shutil.which(debugger)
|
||||
|
||||
|
||||
def get_debugger_info(debugger, debuggerArgs=None, debuggerInteractive=False):
|
||||
"""
|
||||
Get the information about the requested debugger.
|
||||
|
||||
Returns a dictionary containing the |path| of the debugger executable,
|
||||
if it will run in |interactive| mode, its arguments and whether it needs
|
||||
to escape arguments it passes to the debugged program (|requiresEscapedArgs|).
|
||||
If the debugger cannot be found in the system, returns |None|.
|
||||
|
||||
:param debugger: The name of the debugger.
|
||||
:param debuggerArgs: If specified, it's the arguments to pass to the debugger,
|
||||
as a string. Any debugger-specific separator arguments are appended after these
|
||||
arguments.
|
||||
:param debuggerInteractive: If specified, forces the debugger to be interactive.
|
||||
"""
|
||||
|
||||
debuggerPath = None
|
||||
|
||||
if debugger:
|
||||
# Append '.exe' to the debugger on Windows if it's not present,
|
||||
# so things like '--debugger=devenv' work.
|
||||
if os.name == "nt" and not debugger.lower().endswith(".exe"):
|
||||
debugger += ".exe"
|
||||
|
||||
debuggerPath = get_debugger_path(debugger)
|
||||
|
||||
if not debuggerPath:
|
||||
# windbg is not installed with the standard set of tools, and it's
|
||||
# entirely possible that the user hasn't added the install location to
|
||||
# PATH, so we have to be a little more clever than normal to locate it.
|
||||
# Just try to look for it in the standard installed location(s).
|
||||
if debugger == "windbg.exe":
|
||||
for candidate in _windbg_installation_paths():
|
||||
if os.path.exists(candidate):
|
||||
debuggerPath = candidate
|
||||
break
|
||||
else:
|
||||
if os.path.exists(debugger):
|
||||
debuggerPath = debugger
|
||||
|
||||
if not debuggerPath:
|
||||
print("Error: Could not find debugger %s." % debugger)
|
||||
print("Is it installed? Is it in your PATH?")
|
||||
return None
|
||||
|
||||
debuggerName = os.path.basename(debuggerPath).lower()
|
||||
|
||||
def get_debugger_info(type, default):
|
||||
if debuggerName in _DEBUGGER_INFO and type in _DEBUGGER_INFO[debuggerName]:
|
||||
return _DEBUGGER_INFO[debuggerName][type]
|
||||
return default
|
||||
|
||||
# Define a namedtuple to access the debugger information from the outside world.
|
||||
debugger_arguments = []
|
||||
|
||||
if debuggerArgs:
|
||||
# Append the provided debugger arguments at the end of the arguments list.
|
||||
debugger_arguments += debuggerArgs.split()
|
||||
|
||||
debugger_arguments += get_debugger_info("args", [])
|
||||
|
||||
# Override the default debugger interactive mode if needed.
|
||||
debugger_interactive = get_debugger_info("interactive", False)
|
||||
if debuggerInteractive:
|
||||
debugger_interactive = debuggerInteractive
|
||||
|
||||
d = DebuggerInfo(
|
||||
debuggerPath,
|
||||
debugger_interactive,
|
||||
debugger_arguments,
|
||||
get_debugger_info("requiresEscapedArgs", False),
|
||||
)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
# Defines the search policies to use in get_default_debugger_name.
|
||||
|
||||
|
||||
class DebuggerSearch:
|
||||
OnlyFirst = 1
|
||||
KeepLooking = 2
|
||||
|
||||
|
||||
def get_default_debugger_name(search=DebuggerSearch.OnlyFirst):
|
||||
"""
|
||||
Get the debugger name for the default debugger on current platform.
|
||||
|
||||
:param search: If specified, stops looking for the debugger if the
|
||||
default one is not found (|DebuggerSearch.OnlyFirst|) or keeps
|
||||
looking for other compatible debuggers (|DebuggerSearch.KeepLooking|).
|
||||
"""
|
||||
|
||||
mozinfo.find_and_update_from_json()
|
||||
os = mozinfo.info["os"]
|
||||
|
||||
# Find out which debuggers are preferred for use on this platform.
|
||||
debuggerPriorities = _DEBUGGER_PRIORITIES[
|
||||
os if os in _DEBUGGER_PRIORITIES else "unknown"
|
||||
]
|
||||
|
||||
# Finally get the debugger information.
|
||||
for debuggerName in debuggerPriorities:
|
||||
debuggerPath = get_debugger_path(debuggerName)
|
||||
if debuggerPath:
|
||||
return debuggerName
|
||||
elif not search == DebuggerSearch.KeepLooking:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# Defines default values for Valgrind flags.
|
||||
#
|
||||
# --smc-check=all-non-file is required to deal with code generation and
|
||||
# patching by the various JITS. Note that this is only necessary on
|
||||
# x86 and x86_64, but not on ARM. This flag is only necessary for
|
||||
# Valgrind versions prior to 3.11.
|
||||
#
|
||||
# --vex-iropt-register-updates=allregs-at-mem-access is required so that
|
||||
# Valgrind generates correct register values whenever there is a
|
||||
# segfault that is caught and handled. In particular OdinMonkey
|
||||
# requires this. More recent Valgrinds (3.11 and later) provide
|
||||
# --px-default=allregs-at-mem-access and
|
||||
# --px-file-backed=unwindregs-at-mem-access
|
||||
# which provide a significantly cheaper alternative, by restricting the
|
||||
# precise exception behaviour to JIT generated code only.
|
||||
#
|
||||
# --trace-children=yes is required to get Valgrind to follow into
|
||||
# content and other child processes. The resulting output can be
|
||||
# difficult to make sense of, and --child-silent-after-fork=yes
|
||||
# helps by causing Valgrind to be silent for the child in the period
|
||||
# after fork() but before its subsequent exec().
|
||||
#
|
||||
# --trace-children-skip lists processes that we are not interested
|
||||
# in tracing into.
|
||||
#
|
||||
# --leak-check=full requests full stack traces for all leaked blocks
|
||||
# detected at process exit.
|
||||
#
|
||||
# --show-possibly-lost=no requests blocks for which only an interior
|
||||
# pointer was found to be considered not leaked.
|
||||
#
|
||||
#
|
||||
# TODO: pass in the user supplied args for V (--valgrind-args=) and
|
||||
# use this to detect if a different tool has been selected. If so
|
||||
# adjust tool-specific args appropriately.
|
||||
#
|
||||
# TODO: pass in the path to the Valgrind to be used (--valgrind=), and
|
||||
# check what flags it accepts. Possible args that might be beneficial:
|
||||
#
|
||||
# --num-transtab-sectors=24 [reduces re-jitting overheads in long runs]
|
||||
# --px-default=allregs-at-mem-access
|
||||
# --px-file-backed=unwindregs-at-mem-access
|
||||
# [these reduce PX overheads as described above]
|
||||
#
|
||||
|
||||
|
||||
def get_default_valgrind_args():
|
||||
return [
|
||||
"--fair-sched=yes",
|
||||
"--smc-check=all-non-file",
|
||||
"--vex-iropt-register-updates=allregs-at-mem-access",
|
||||
"--trace-children=yes",
|
||||
"--child-silent-after-fork=yes",
|
||||
(
|
||||
"--trace-children-skip="
|
||||
+ "/usr/bin/hg,/bin/rm,*/bin/certutil,*/bin/pk12util,"
|
||||
+ "*/bin/ssltunnel,*/bin/uname,*/bin/which,*/bin/ps,"
|
||||
+ "*/bin/grep,*/bin/java,*/bin/lsb_release"
|
||||
),
|
||||
] + get_default_valgrind_tool_specific_args()
|
||||
|
||||
|
||||
# The default tool is Memcheck. Feeding these arguments to a different
|
||||
# Valgrind tool will cause it to fail at startup, so don't do that!
|
||||
|
||||
|
||||
def get_default_valgrind_tool_specific_args():
|
||||
return [
|
||||
"--partial-loads-ok=yes",
|
||||
"--leak-check=summary",
|
||||
"--show-possibly-lost=no",
|
||||
"--show-mismatched-frees=no",
|
||||
]
|
Loading…
Add table
Add a link
Reference in a new issue