Skip to content

Commit

Permalink
Update existing debuginfo tests to work with gdb 14, Bugfixes and Cle…
Browse files Browse the repository at this point in the history
…anup
  • Loading branch information
dominikmascherbauer committed Sep 10, 2024
1 parent 2f3eb04 commit fef1f79
Show file tree
Hide file tree
Showing 6 changed files with 538 additions and 580 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permalink: /reference-manual/native-image/guides/debug-native-image-process/

### Which GDB to Use?

* Please use GDB 10.2 or later. The debug info is tested via `mx debuginfotest` against 10.2.
* Please use GDB 14.2 or later. The debug info is tested via `mx debuginfotest` against 14.2.
* Note that later versions might have slightly different formatting of debugger output (which, for example, may cause CI/CD gate checks to fail)
* GDB bundled in recent Linux releases works just fine for debugging sessions

Expand Down
42 changes: 19 additions & 23 deletions substratevm/mx.substratevm/gdb_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2023, 2023, Red Hat Inc. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
Expand Down Expand Up @@ -29,7 +29,7 @@
import gdb
import re
import sys
import os


# set various gdb operating modes to desired setting

Expand All @@ -49,13 +49,14 @@ def configure_gdb():
# execute a gdb command and return the resulting output as a string

def execute(command):
print('(gdb) %s'%(command))
print(f'(gdb) {command}')
try:
return gdb.execute(command, to_string=True)
except gdb.error as e:
print(e)
sys.exit(1)


# a variety of useful regular expression patterns

address_pattern = '0x[0-9a-f]+'
Expand All @@ -68,10 +69,12 @@ def execute(command):
package_file_pattern = '[a-zA-Z0-9_/]+\\.java'
varname_pattern = '[a-zA-Z0-9_]+'
wildcard_pattern = '.*'
no_arg_values_pattern = "\(\)"
arg_values_pattern = "\(([a-zA-Z0-9$_]+=[a-zA-Z0-9$_<> ]+)(, [a-zA-Z0-9$_]+=[a-zA-Z0-9$_<> ]+)*\)"
no_param_types_pattern = "\(\)"
param_types_pattern = "\(([a-zA-Z0-9[.*$_\]]+)(, [a-zA-Z0-9[.*$_\]]+)*\)"
no_arg_values_pattern = r"\(\)"
arg_values_pattern = r"\(([a-zA-Z0-9$_]+=[a-zA-Z0-9$_<> ]+)(, [a-zA-Z0-9$_]+=[a-zA-Z0-9$_<> ]+)*\)"
no_param_types_pattern = r"\(\)"
param_types_pattern = r"\(([a-zA-Z0-9[.*$_\]]+)(, [a-zA-Z0-9[.*$_\]]+)*\)"
compressed_pattern = r"_z_\."


# A helper class which checks that a sequence of lines of output
# from a gdb command matches a sequence of per-line regular
Expand Down Expand Up @@ -104,23 +107,23 @@ def check(self, text, skip_fails=True):
num_rexps = len(rexps)
line_idx = 0
matches = []
for i in range(0, (num_rexps)):
for i in range(0, num_rexps):
rexp = rexps[i]
match = None
while line_idx < num_lines and match is None:
line = lines[line_idx]
match = rexp.match(line)
if match is None:
if match is None:
if not skip_fails:
print('Checker %s: match %d failed at line %d %s\n'%(self.name, i, line_idx, line))
print(f'Checker {self.name}: match {i:d} failed at line {line_idx:d} {line}\n')
print(self)
print(text)
sys.exit(1)
else:
matches.append(match)
line_idx += 1
if len(matches) < num_rexps:
print('Checker %s: insufficient matching lines %d for regular expressions %d'%(self.name, len(matches), num_rexps))
print(f'Checker {self.name}: insufficient matching lines {len(matches):d} for regular expressions {num_rexps:d}')
print(self)
print(text)
sys.exit(1)
Expand All @@ -130,25 +133,18 @@ def check(self, text, skip_fails=True):
# Format a Checker as a string
def __str__(self):
rexps = self.rexps
result = 'Checker %s '%(self.name)
result = f'Checker {self.name} '
result += '{\n'
for rexp in rexps:
result += ' %s\n'%(rexp)
result += f' {rexp}\n'
result += '}\n'
return result


def match_gdb_version():
# obtain the gdb version
# n.b. we can only test printing in gdb 10.1 upwards
exec_string=execute("show version")
exec_string = execute("show version")
checker = Checker('show version',
r"GNU gdb %s (%s)\.(%s)%s"%(wildcard_pattern, digits_pattern, digits_pattern, wildcard_pattern))
fr"GNU gdb {wildcard_pattern} ({digits_pattern})\.({digits_pattern}){wildcard_pattern}")
matches = checker.check(exec_string, skip_fails=False)
return matches[0]

def check_print_data(major, minor):
# printing does not always work on gdb 10.x or earlier
can_print_data = major > 10
if os.environ.get('GDB_CAN_PRINT', '') == 'True':
can_print_data = True
return can_print_data
21 changes: 10 additions & 11 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -953,11 +953,11 @@ def _collector(x):
raise Exception('Unexpected output: ' + str(actual_output) + " != " + str(expected_output))

def _debuginfotest(native_image, path, build_only, with_isolates_only, args):
mx.log("path=%s"%path)
mx.log(f"path={path}")
sourcepath = mx.project('com.oracle.svm.test').source_dirs()[0]
mx.log("sourcepath=%s"%sourcepath)
mx.log(f"sourcepath={sourcepath}")
sourcecache = join(path, 'sources')
mx.log("sourcecache=%s"%sourcecache)
mx.log(f"sourcecache={sourcecache}")
# the header file for foreign types resides at the root of the
# com.oracle.svm.test source tree
cincludepath = sourcepath
Expand Down Expand Up @@ -993,33 +993,32 @@ def build_debug_test(variant_name, image_name, extra_args):
build_args = native_image_args + extra_args + [
'-o', join(per_build_path, image_name)
]
mx.log('native_image {}'.format(build_args))
mx.log(f'native_image {build_args}')
return native_image(build_args)

# build with and without Isolates and check both work
if '--libc=musl' in args:
os.environ.update({'debuginfotest_musl' : 'yes'})
os.environ.update({'debuginfotest_musl': 'yes'})

gdb_utils_py = join(suite.dir, 'mx.substratevm', 'gdb_utils.py')
testhello_py = join(suite.dir, 'mx.substratevm', 'testhello.py')
testhello_args = [
# We do not want to step into class initializer, so initialize everything at build time.
'--initialize-at-build-time=hello',
'hello.Hello'
]
if mx.get_os() == 'linux' and not build_only:
os.environ.update({'debuginfotest_arch' : mx.get_arch()})
os.environ.update({'debuginfotest_arch': mx.get_arch()})

if not with_isolates_only:
hello_binary = build_debug_test('isolates_off', 'hello_image', testhello_args + svm_experimental_options(['-H:-SpawnIsolates']))
if mx.get_os() == 'linux' and not build_only:
os.environ.update({'debuginfotest_isolates' : 'no'})
mx.run([os.environ.get('GDB_BIN', 'gdb'), '-ex', 'python "ISOLATES=False"', '-x', gdb_utils_py, '-x', testhello_py, hello_binary])
os.environ.update({'debuginfotest_isolates': 'no'})
mx.run([os.environ.get('GDB_BIN', 'gdb'), '--nx', '-q', '-iex', 'set pagination off', '-ex', 'python "ISOLATES=False"', '-x', testhello_py, hello_binary])

hello_binary = build_debug_test('isolates_on', 'hello_image', testhello_args + svm_experimental_options(['-H:+SpawnIsolates']))
if mx.get_os() == 'linux' and not build_only:
os.environ.update({'debuginfotest_isolates' : 'yes'})
mx.run([os.environ.get('GDB_BIN', 'gdb'), '-ex', 'python "ISOLATES=True"', '-x', gdb_utils_py, '-x', testhello_py, hello_binary])
os.environ.update({'debuginfotest_isolates': 'yes'})
mx.run([os.environ.get('GDB_BIN', 'gdb'), '--nx', '-q', '-iex', 'set pagination off', '-ex', 'python "ISOLATES=True"', '-x', testhello_py, hello_binary])


def _gdbdebughelperstest(native_image, path, with_isolates_only, args):
Expand Down
Loading

0 comments on commit fef1f79

Please sign in to comment.