mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 928397 - Enable xpcshell-test debugging on Windows platforms and default debugger detection. r=ted.mielczarek
This commit is contained in:
parent
09e9640c25
commit
3a4ff18bd7
@ -23,8 +23,6 @@ __all__ = [
|
||||
"dumpLeakLog",
|
||||
"isURL",
|
||||
"processLeakLog",
|
||||
"getDebuggerInfo",
|
||||
"DEBUGGER_INFO",
|
||||
"replaceBackSlashes",
|
||||
'KeyValueParseError',
|
||||
'parseKeyValue',
|
||||
@ -48,54 +46,6 @@ def setAutomationLog(alt_logger):
|
||||
global log
|
||||
log = alt_logger
|
||||
|
||||
# Map of debugging programs to information about them, like default arguments
|
||||
# and whether or not they are interactive.
|
||||
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"
|
||||
},
|
||||
|
||||
"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"
|
||||
},
|
||||
|
||||
# valgrind doesn't explain much about leaks unless you set the
|
||||
# '--leak-check=full' flag. But there are a lot of objects that are
|
||||
# semi-deliberately leaked, so we set '--show-possibly-lost=no' to avoid
|
||||
# uninteresting output from those objects. We set '--smc-check==all-non-file'
|
||||
# and '--vex-iropt-register-updates=allregs-at-mem-access' so that valgrind
|
||||
# deals properly with JIT'd JavaScript code.
|
||||
"valgrind": {
|
||||
"interactive": False,
|
||||
"args": " ".join(["--leak-check=full",
|
||||
"--show-possibly-lost=no",
|
||||
"--smc-check=all-non-file",
|
||||
"--vex-iropt-register-updates=allregs-at-mem-access"])
|
||||
}
|
||||
}
|
||||
|
||||
class ZipFileReader(object):
|
||||
"""
|
||||
Class to read zip files in Python 2.5 and later. Limited to only what we
|
||||
@ -224,58 +174,6 @@ def addCommonOptions(parser, defaults={}):
|
||||
help = "prevents the test harness from redirecting "
|
||||
"stdout and stderr for interactive debuggers")
|
||||
|
||||
def getFullPath(directory, path):
|
||||
"Get an absolute path relative to 'directory'."
|
||||
return os.path.normpath(os.path.join(directory, os.path.expanduser(path)))
|
||||
|
||||
def searchPath(directory, path):
|
||||
"Go one step beyond getFullPath and try the various folders in PATH"
|
||||
# Try looking in the current working directory first.
|
||||
newpath = getFullPath(directory, path)
|
||||
if os.path.isfile(newpath):
|
||||
return newpath
|
||||
|
||||
# At this point we have to fail if a directory was given (to prevent cases
|
||||
# like './gdb' from matching '/usr/bin/./gdb').
|
||||
if not os.path.dirname(path):
|
||||
for dir in os.environ['PATH'].split(os.pathsep):
|
||||
newpath = os.path.join(dir, path)
|
||||
if os.path.isfile(newpath):
|
||||
return newpath
|
||||
return None
|
||||
|
||||
def getDebuggerInfo(directory, debugger, debuggerArgs, debuggerInteractive = False):
|
||||
|
||||
debuggerInfo = None
|
||||
|
||||
if debugger:
|
||||
debuggerPath = searchPath(directory, debugger)
|
||||
if not debuggerPath:
|
||||
print "Error: Path %s doesn't exist." % debugger
|
||||
sys.exit(1)
|
||||
|
||||
debuggerName = os.path.basename(debuggerPath).lower()
|
||||
|
||||
def getDebuggerInfo(type, default):
|
||||
if debuggerName in DEBUGGER_INFO and type in DEBUGGER_INFO[debuggerName]:
|
||||
return DEBUGGER_INFO[debuggerName][type]
|
||||
return default
|
||||
|
||||
debuggerInfo = {
|
||||
"path": debuggerPath,
|
||||
"interactive" : getDebuggerInfo("interactive", False),
|
||||
"args": getDebuggerInfo("args", "").split(),
|
||||
"requiresEscapedArgs": getDebuggerInfo("requiresEscapedArgs", False)
|
||||
}
|
||||
|
||||
if debuggerArgs:
|
||||
debuggerInfo["args"] = debuggerArgs.split()
|
||||
if debuggerInteractive:
|
||||
debuggerInfo["interactive"] = debuggerInteractive
|
||||
|
||||
return debuggerInfo
|
||||
|
||||
|
||||
def dumpLeakLog(leakLogFile, filter = False):
|
||||
"""Process the leak log, without parsing it.
|
||||
|
||||
|
@ -23,10 +23,10 @@ sys.path.insert(0, SCRIPT_DIRECTORY)
|
||||
from automation import Automation
|
||||
from automationutils import (
|
||||
addCommonOptions,
|
||||
getDebuggerInfo,
|
||||
isURL,
|
||||
processLeakLog
|
||||
)
|
||||
import mozdebug
|
||||
import mozprofile
|
||||
|
||||
def categoriesToRegex(categoryList):
|
||||
@ -320,7 +320,7 @@ class RefTest(object):
|
||||
return int(any(t.retcode != 0 for t in threads))
|
||||
|
||||
def runSerialTests(self, testPath, options, cmdlineArgs = None):
|
||||
debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
|
||||
debuggerInfo = mozdebug.get_debugger_info(options.debugger, options.debuggerArgs,
|
||||
options.debuggerInteractive);
|
||||
|
||||
profileDir = None
|
||||
|
@ -824,7 +824,7 @@ class DebugProgram(MachCommandBase):
|
||||
@CommandArgument('+debugger', default=None, type=str,
|
||||
help='Name of debugger to launch')
|
||||
@CommandArgument('+debugparams', default=None, metavar='params', type=str,
|
||||
help='Command-line arguments to pass to GDB or LLDB itself; split as the Bourne shell would.')
|
||||
help='Command-line arguments to pass to the debugger itself; split as the Bourne shell would.')
|
||||
# Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever
|
||||
# segfaults induced by the slow-script-detecting logic for Ion/Odin JITted
|
||||
# code. If we don't pass this, the user will need to periodically type
|
||||
@ -833,26 +833,7 @@ class DebugProgram(MachCommandBase):
|
||||
@CommandArgument('+slowscript', action='store_true',
|
||||
help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
|
||||
def debug(self, params, remote, background, debugger, debugparams, slowscript):
|
||||
import which
|
||||
if debugger:
|
||||
try:
|
||||
debugger = which.which(debugger)
|
||||
except Exception as e:
|
||||
print("You don't have %s in your PATH" % (debugger))
|
||||
print(e)
|
||||
return 1
|
||||
else:
|
||||
try:
|
||||
debugger = which.which('gdb')
|
||||
except Exception:
|
||||
try:
|
||||
debugger = which.which('lldb')
|
||||
except Exception as e:
|
||||
print("You don't have gdb or lldb in your PATH")
|
||||
print(e)
|
||||
return 1
|
||||
args = [debugger]
|
||||
extra_env = { 'MOZ_CRASHREPORTER_DISABLE' : '1' }
|
||||
# Parameters come from the CLI. We need to convert them before their use.
|
||||
if debugparams:
|
||||
import pymake.process
|
||||
argv, badchar = pymake.process.clinetoargv(debugparams, os.getcwd())
|
||||
@ -860,7 +841,22 @@ class DebugProgram(MachCommandBase):
|
||||
print("The +debugparams you passed require a real shell to parse them.")
|
||||
print("(We can't handle the %r character.)" % (badchar,))
|
||||
return 1
|
||||
args.extend(argv)
|
||||
debugparams = argv;
|
||||
|
||||
import mozdebug
|
||||
|
||||
if not debugger:
|
||||
# No debugger name was provided. Look for the default ones on current OS.
|
||||
debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
||||
|
||||
self.debuggerInfo = mozdebug.get_debugger_info(debugger, debugparams)
|
||||
|
||||
# We could not find the information about the desired debugger.
|
||||
if not self.debuggerInfo:
|
||||
print("Could not find a suitable debugger in your PATH.")
|
||||
return 1
|
||||
|
||||
extra_env = { 'MOZ_CRASHREPORTER_DISABLE' : '1' }
|
||||
|
||||
binpath = None
|
||||
|
||||
@ -872,17 +868,8 @@ class DebugProgram(MachCommandBase):
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
# args added to separate the debugger and process arguments.
|
||||
args_separator = {
|
||||
'gdb': '--args',
|
||||
'ddd': '--args',
|
||||
'cgdb': '--args',
|
||||
'lldb': '--'
|
||||
}
|
||||
|
||||
debugger_name = os.path.basename(debugger)
|
||||
if debugger_name in args_separator:
|
||||
args.append(args_separator[debugger_name])
|
||||
# Build the list of arguments to pass to run_process
|
||||
args = [self.debuggerInfo.path] + self.debuggerInfo.args
|
||||
args.append(binpath)
|
||||
|
||||
if not remote:
|
||||
|
@ -16,6 +16,7 @@ import ctypes
|
||||
import glob
|
||||
import json
|
||||
import mozcrash
|
||||
import mozdebug
|
||||
import mozinfo
|
||||
import mozprocess
|
||||
import mozrunner
|
||||
@ -34,7 +35,6 @@ import bisection
|
||||
|
||||
from automationutils import (
|
||||
environment,
|
||||
getDebuggerInfo,
|
||||
isURL,
|
||||
KeyValueParseError,
|
||||
parseKeyValue,
|
||||
@ -390,7 +390,7 @@ class WebSocketServer(object):
|
||||
script = os.path.join(self._scriptdir, scriptPath)
|
||||
|
||||
cmd = [sys.executable, script]
|
||||
if self.debuggerInfo and self.debuggerInfo['interactive']:
|
||||
if self.debuggerInfo and self.debuggerInfo.interactive:
|
||||
cmd += ['--interactive']
|
||||
cmd += ['-p', str(self.port), '-w', self._scriptdir, '-l', \
|
||||
os.path.join(self._scriptdir, "websock.log"), \
|
||||
@ -1377,8 +1377,8 @@ class Mochitest(MochitestUtilsMixin):
|
||||
interactive = False
|
||||
debug_args = None
|
||||
if debuggerInfo:
|
||||
interactive = debuggerInfo['interactive']
|
||||
debug_args = [debuggerInfo['path']] + debuggerInfo['args']
|
||||
interactive = debuggerInfo.interactive
|
||||
debug_args = [debuggerInfo.path] + debuggerInfo.args
|
||||
|
||||
# fix default timeout
|
||||
if timeout == -1:
|
||||
@ -1407,7 +1407,7 @@ class Mochitest(MochitestUtilsMixin):
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=916512
|
||||
args.append('-foreground')
|
||||
if testUrl:
|
||||
if debuggerInfo and debuggerInfo['requiresEscapedArgs']:
|
||||
if debuggerInfo and debuggerInfo.requiresEscapedArgs:
|
||||
testUrl = testUrl.replace("&", "\\&")
|
||||
args.append(testUrl)
|
||||
|
||||
@ -1694,10 +1694,10 @@ class Mochitest(MochitestUtilsMixin):
|
||||
# 'args': arguments to the debugger (list)
|
||||
# TODO: use mozrunner.local.debugger_arguments:
|
||||
# https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/local.py#L42
|
||||
debuggerInfo = getDebuggerInfo(self.oldcwd,
|
||||
options.debugger,
|
||||
options.debuggerArgs,
|
||||
options.debuggerInteractive)
|
||||
|
||||
debuggerInfo = mozdebug.get_debugger_info(options.debugger,
|
||||
options.debuggerArgs,
|
||||
options.debuggerInteractive)
|
||||
|
||||
if options.useTestMediaDevices:
|
||||
devices = findTestMediaDevices(self.log)
|
||||
|
@ -146,15 +146,9 @@ class XPCShellRunner(MozbuildObject):
|
||||
(manifest and len(manifest.test_paths())==1) or
|
||||
verbose)
|
||||
|
||||
# We need to attach the '.exe' extension on Windows for the debugger to
|
||||
# work properly.
|
||||
xpcsExecutable = 'xpcshell'
|
||||
if os.name == 'nt':
|
||||
xpcsExecutable += '.exe'
|
||||
|
||||
args = {
|
||||
'manifest': manifest,
|
||||
'xpcshell': os.path.join(self.bindir, xpcsExecutable),
|
||||
'xpcshell': self.get_binary_path('xpcshell'),
|
||||
'mozInfo': os.path.join(self.topobjdir, 'mozinfo.json'),
|
||||
'symbolsPath': os.path.join(self.distdir, 'crashreporter-symbols'),
|
||||
'interactive': interactive,
|
||||
|
@ -7,6 +7,7 @@
|
||||
import copy
|
||||
import json
|
||||
import math
|
||||
import mozdebug
|
||||
import os
|
||||
import os.path
|
||||
import random
|
||||
@ -397,7 +398,7 @@ class XPCShellTestThread(Thread):
|
||||
self.xpcsCmd.extend(['-f', os.path.join(self.testharnessdir, 'head.js')])
|
||||
|
||||
if self.debuggerInfo:
|
||||
self.xpcsCmd = [self.debuggerInfo["path"]] + self.debuggerInfo["args"] + self.xpcsCmd
|
||||
self.xpcsCmd = [self.debuggerInfo.path] + self.debuggerInfo.args + self.xpcsCmd
|
||||
|
||||
# Automation doesn't specify a pluginsPath and xpcshell defaults to
|
||||
# $APPDIR/plugins. We do the same here so we can carry on with
|
||||
@ -757,7 +758,6 @@ class XPCShellTestThread(Thread):
|
||||
class XPCShellTests(object):
|
||||
|
||||
log = getGlobalLog()
|
||||
oldcwd = os.getcwd()
|
||||
|
||||
def __init__(self, log=None):
|
||||
""" Init logging and node status """
|
||||
@ -904,7 +904,7 @@ class XPCShellTests(object):
|
||||
pStdout = None
|
||||
pStderr = None
|
||||
else:
|
||||
if (self.debuggerInfo and self.debuggerInfo["interactive"]):
|
||||
if (self.debuggerInfo and self.debuggerInfo.interactive):
|
||||
pStdout = None
|
||||
pStderr = None
|
||||
else:
|
||||
@ -1190,8 +1190,11 @@ class XPCShellTests(object):
|
||||
be printed always
|
||||
|logfiles|, if set to False, indicates not to save output to log files.
|
||||
Non-interactive only option.
|
||||
|debuggerInfo|, if set, specifies the debugger and debugger arguments
|
||||
that will be used to launch xpcshell.
|
||||
|debugger|, if set, specifies the name of the debugger that will be used
|
||||
to launch xpcshell.
|
||||
|debuggerArgs|, if set, specifies arguments to use with the debugger.
|
||||
|debuggerInteractive|, if set, allows the debugger to be run in interactive
|
||||
mode.
|
||||
|profileName|, if set, specifies the name of the application for the profile
|
||||
directory if running only a subset of tests.
|
||||
|mozInfo|, if set, specifies specifies build configuration information, either as a filename containing JSON, or a dict.
|
||||
@ -1247,6 +1250,16 @@ class XPCShellTests(object):
|
||||
if not testingModulesDir.endswith(os.path.sep):
|
||||
testingModulesDir += os.path.sep
|
||||
|
||||
self.debuggerInfo = None
|
||||
|
||||
if debugger:
|
||||
# We need a list of arguments, not a string, to feed into
|
||||
# the debugger
|
||||
if debuggerArgs:
|
||||
debuggerArgs = debuggerArgs.split();
|
||||
|
||||
self.debuggerInfo = mozdebug.get_debugger_info(debugger, debuggerArgs, debuggerInteractive)
|
||||
|
||||
self.xpcshell = xpcshell
|
||||
self.xrePath = xrePath
|
||||
self.appPath = appPath
|
||||
@ -1261,7 +1274,6 @@ class XPCShellTests(object):
|
||||
self.on_message = on_message
|
||||
self.totalChunks = totalChunks
|
||||
self.thisChunk = thisChunk
|
||||
self.debuggerInfo = getDebuggerInfo(self.oldcwd, debugger, debuggerArgs, debuggerInteractive)
|
||||
self.profileName = profileName or "xpcshell"
|
||||
self.mozInfo = mozInfo
|
||||
self.testingModulesDir = testingModulesDir
|
||||
@ -1362,7 +1374,7 @@ class XPCShellTests(object):
|
||||
self.sequential = True
|
||||
|
||||
# If we have an interactive debugger, disable SIGINT entirely.
|
||||
if self.debuggerInfo["interactive"]:
|
||||
if self.debuggerInfo.interactive:
|
||||
signal.signal(signal.SIGINT, lambda signum, frame: None)
|
||||
|
||||
# create a queue of all tests that will run
|
||||
|
Loading…
Reference in New Issue
Block a user