validate: launcher: Add support for lldb

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7452>
This commit is contained in:
Thibault Saunier 2024-05-08 11:34:34 -04:00 committed by GStreamer Marge Bot
parent 1b5a093b96
commit 0d24821167
3 changed files with 93 additions and 15 deletions

View file

@ -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')
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):
@ -365,6 +422,7 @@ class Test(Loggable):
message, error))
if result is Result.TIMEOUT:
self.add_stack_trace_to_logfile()
if self.options.debug is True:
if self.options.gdb:
printc("Timeout, you should process <ctrl>c to get into gdb",
@ -373,11 +431,21 @@ class Test(Loggable):
self.process.communicate()
else:
pname = self.command[0]
input("%sTimeout happened on %s you can attach gdb doing:\n $gdb %s %d%s\n"
"Press enter to continue" % (Colors.FAIL, self.classname,
pname, self.process.pid, Colors.ENDC))
while True:
debugger = get_debugger()
if not debugger:
res = input(f"{Colors.FAIL}Timeout happened on {self.classname} no known debugger found but the process PID is {self.process.pid}\n"
f"You can find log file at {self.logfile}\n"
f"Press 'ok(o)' enter to continue\n\n")
else:
self.add_stack_trace_to_logfile()
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.message = message
@ -544,10 +612,8 @@ class Test(Loggable):
self.timeout = sys.maxsize
self.hard_timeout = sys.maxsize
args = ["gdb"]
if self.options.gdb_non_stop:
args += ["-ex", "run", "-ex", "backtrace", "-ex", "quit"]
args += ["--args"] + command
assert DEBUGGER is not None
args = DEBUGGER.get_args(command, self.options.gdb_non_stop)
return args
def use_rr(self, command, subenv):
@ -1621,6 +1687,10 @@ class TestsManager(Loggable):
for patterns in options.blacklisted_tests:
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):
if self.options.check_bugs_status:
if not check_bugs_resolution(self.blacklisted_tests):

View file

@ -266,12 +266,6 @@ class LauncherConfig(Loggable):
self.logsdir = "stdout"
self.debug = True
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
if self.logsdir in ['stdout', 'stderr']:

View file

@ -385,6 +385,7 @@ class BackTraceGenerator(Loggable):
self.warning(e)
self.coredumpctl = None
self.gdb = shutil.which('gdb')
self.lldb = shutil.which('lldb')
@classmethod
def get_default(cls):
@ -404,8 +405,21 @@ class BackTraceGenerator(Loggable):
" supported way to get backtraces for now.")
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):
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" \
"installed."