mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 14:08:56 +00:00
validate: launcher: Add support for lldb
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7452>
This commit is contained in:
parent
1b5a093b96
commit
0d24821167
3 changed files with 93 additions and 15 deletions
|
@ -79,6 +79,63 @@ EXITING_SIGNALS.update({(v, k) for k, v in EXITING_SIGNALS.items()})
|
||||||
|
|
||||||
|
|
||||||
CI_ARTIFACTS_URL = os.environ.get('CI_ARTIFACTS_URL')
|
CI_ARTIFACTS_URL = os.environ.get('CI_ARTIFACTS_URL')
|
||||||
|
DEBUGGER = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_debugger():
|
||||||
|
global DEBUGGER
|
||||||
|
if DEBUGGER is not None:
|
||||||
|
return DEBUGGER
|
||||||
|
|
||||||
|
gdb = shutil.which('gdb')
|
||||||
|
if gdb:
|
||||||
|
DEBUGGER = GDBDebugger(gdb)
|
||||||
|
else:
|
||||||
|
lldb = shutil.which('lldb')
|
||||||
|
DEBUGGER = LLDBDebugger(lldb)
|
||||||
|
|
||||||
|
return DEBUGGER
|
||||||
|
|
||||||
|
|
||||||
|
class Debugger:
|
||||||
|
def __init__(self, executable):
|
||||||
|
self.executable = executable
|
||||||
|
|
||||||
|
def get_args(self, args, non_stop) -> list:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_attach_args(self, pid):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class GDBDebugger(Debugger):
|
||||||
|
def get_args(self, args, non_stop) -> list:
|
||||||
|
if non_stop:
|
||||||
|
return [
|
||||||
|
self.executable,
|
||||||
|
"-ex",
|
||||||
|
"run",
|
||||||
|
"-ex",
|
||||||
|
"bt",
|
||||||
|
"-ex",
|
||||||
|
"quit",
|
||||||
|
"--args",
|
||||||
|
] + args
|
||||||
|
else:
|
||||||
|
return [self.executable, "--args"] + args
|
||||||
|
|
||||||
|
def get_attach_args(self, pid):
|
||||||
|
return [self.executable, "-p", str(pid)]
|
||||||
|
|
||||||
|
|
||||||
|
class LLDBDebugger(Debugger):
|
||||||
|
def get_args(self, args, non_stop) -> list:
|
||||||
|
if non_stop:
|
||||||
|
return [self.executable, "-o", "run", "-o", "bt", "-o", "quit", "--"] + args
|
||||||
|
return [self.executable, "--"] + args
|
||||||
|
|
||||||
|
def get_attach_args(self, pid):
|
||||||
|
return [self.executable, "-p", str(pid)]
|
||||||
|
|
||||||
|
|
||||||
class Test(Loggable):
|
class Test(Loggable):
|
||||||
|
@ -365,6 +422,7 @@ class Test(Loggable):
|
||||||
message, error))
|
message, error))
|
||||||
|
|
||||||
if result is Result.TIMEOUT:
|
if result is Result.TIMEOUT:
|
||||||
|
self.add_stack_trace_to_logfile()
|
||||||
if self.options.debug is True:
|
if self.options.debug is True:
|
||||||
if self.options.gdb:
|
if self.options.gdb:
|
||||||
printc("Timeout, you should process <ctrl>c to get into gdb",
|
printc("Timeout, you should process <ctrl>c to get into gdb",
|
||||||
|
@ -373,11 +431,21 @@ class Test(Loggable):
|
||||||
self.process.communicate()
|
self.process.communicate()
|
||||||
else:
|
else:
|
||||||
pname = self.command[0]
|
pname = self.command[0]
|
||||||
input("%sTimeout happened on %s you can attach gdb doing:\n $gdb %s %d%s\n"
|
while True:
|
||||||
"Press enter to continue" % (Colors.FAIL, self.classname,
|
debugger = get_debugger()
|
||||||
pname, self.process.pid, Colors.ENDC))
|
if not debugger:
|
||||||
else:
|
res = input(f"{Colors.FAIL}Timeout happened on {self.classname} no known debugger found but the process PID is {self.process.pid}\n"
|
||||||
self.add_stack_trace_to_logfile()
|
f"You can find log file at {self.logfile}\n"
|
||||||
|
f"Press 'ok(o)' enter to continue\n\n")
|
||||||
|
else:
|
||||||
|
res = input(f"{Colors.FAIL}Timeout happened on {self.classname} you can attach the debugger doing:\n"
|
||||||
|
f" $ {' '.join([shlex.quote(a) for a in debugger.get_attach_args(self.process.pid)])}\n"
|
||||||
|
f"You can find log file at {self.logfile}\n"
|
||||||
|
f"**Press ok(o) to continue**{Colors.ENDC}\n\n")
|
||||||
|
|
||||||
|
if res.lower() in ['o', 'ok']:
|
||||||
|
print("Continuing...\n")
|
||||||
|
break
|
||||||
|
|
||||||
self.result = result
|
self.result = result
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -544,10 +612,8 @@ class Test(Loggable):
|
||||||
self.timeout = sys.maxsize
|
self.timeout = sys.maxsize
|
||||||
self.hard_timeout = sys.maxsize
|
self.hard_timeout = sys.maxsize
|
||||||
|
|
||||||
args = ["gdb"]
|
assert DEBUGGER is not None
|
||||||
if self.options.gdb_non_stop:
|
args = DEBUGGER.get_args(command, self.options.gdb_non_stop)
|
||||||
args += ["-ex", "run", "-ex", "backtrace", "-ex", "quit"]
|
|
||||||
args += ["--args"] + command
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def use_rr(self, command, subenv):
|
def use_rr(self, command, subenv):
|
||||||
|
@ -1621,6 +1687,10 @@ class TestsManager(Loggable):
|
||||||
for patterns in options.blacklisted_tests:
|
for patterns in options.blacklisted_tests:
|
||||||
self._add_blacklist(patterns)
|
self._add_blacklist(patterns)
|
||||||
|
|
||||||
|
if options.gdb:
|
||||||
|
if get_debugger() is None:
|
||||||
|
raise RuntimeError("No debugger found, can't run tests with --gdb")
|
||||||
|
|
||||||
def check_blacklists(self):
|
def check_blacklists(self):
|
||||||
if self.options.check_bugs_status:
|
if self.options.check_bugs_status:
|
||||||
if not check_bugs_resolution(self.blacklisted_tests):
|
if not check_bugs_resolution(self.blacklisted_tests):
|
||||||
|
|
|
@ -266,12 +266,6 @@ class LauncherConfig(Loggable):
|
||||||
self.logsdir = "stdout"
|
self.logsdir = "stdout"
|
||||||
self.debug = True
|
self.debug = True
|
||||||
self.num_jobs = 1
|
self.num_jobs = 1
|
||||||
try:
|
|
||||||
subprocess.check_output("gdb --help", shell=True)
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
printc("Want to use gdb, but not available on the system",
|
|
||||||
Colors.FAIL)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# other output directories
|
# other output directories
|
||||||
if self.logsdir in ['stdout', 'stderr']:
|
if self.logsdir in ['stdout', 'stderr']:
|
||||||
|
|
|
@ -385,6 +385,7 @@ class BackTraceGenerator(Loggable):
|
||||||
self.warning(e)
|
self.warning(e)
|
||||||
self.coredumpctl = None
|
self.coredumpctl = None
|
||||||
self.gdb = shutil.which('gdb')
|
self.gdb = shutil.which('gdb')
|
||||||
|
self.lldb = shutil.which('lldb')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_default(cls):
|
def get_default(cls):
|
||||||
|
@ -404,8 +405,21 @@ class BackTraceGenerator(Loggable):
|
||||||
" supported way to get backtraces for now.")
|
" supported way to get backtraces for now.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_trace_on_running_process_with_lldb(self, test):
|
||||||
|
lldb = ['lldb', '-o', 'bt all', '-o', 'quit', '-p', str(test.process.pid)]
|
||||||
|
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(
|
||||||
|
lldb, stderr=subprocess.STDOUT, timeout=30).decode()
|
||||||
|
except Exception as e:
|
||||||
|
return "Could not run `lldb` on process (pid: %d):\n%s" % (
|
||||||
|
test.process.pid, e)
|
||||||
|
|
||||||
def get_trace_on_running_process(self, test):
|
def get_trace_on_running_process(self, test):
|
||||||
if not self.gdb:
|
if not self.gdb:
|
||||||
|
if self.lldb:
|
||||||
|
return self.get_trace_on_running_process_with_lldb(test)
|
||||||
|
|
||||||
return "Can not generate stack trace as `gdb` is not" \
|
return "Can not generate stack trace as `gdb` is not" \
|
||||||
"installed."
|
"installed."
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue