Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-46599] Foreign debuginfo types #6625

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
275df27
Use NativeLibraries to idenitfy foreign word and pointer types
adinn Mar 17, 2023
7f93184
log details of foreign types
adinn Apr 27, 2023
6324cd2
Initial modelling + DWARF for foreign types minus struct layouts
adinn May 12, 2023
a45538b
Correct mangled names to omit P tag for foreign type arg or return value
adinn May 15, 2023
21183ae
model foreign structs and indirect pointers
adinn May 17, 2023
bd10b6d
style fixes
adinn May 17, 2023
403f3f0
more style fixes
adinn May 17, 2023
5dedcef
more style fixes and cleanups
adinn May 17, 2023
cc2456f
fix logic typo caught in stooke review
adinn May 18, 2023
919acf7
fix typo after fzakkak review
adinn May 22, 2023
174bb1b
Ensure foreign struct layouts inherit 'super' fields
adinn May 24, 2023
2be884f
support embedded values in foreign structs including arrays
adinn May 25, 2023
1a2ea14
rework for chaeubl review
adinn May 25, 2023
8c46372
allow for larger offsets in header/structs
adinn May 25, 2023
d165222
Generate correct array byte_size only where appropriate
adinn May 26, 2023
e073ec8
test foreign debug info
adinn May 26, 2023
a75336f
avoid python style issues for gdb script
adinn May 26, 2023
3d509a2
fix python style issue
adinn May 30, 2023
a780d49
more style fixes
adinn May 30, 2023
d5d4a7e
make debuginfotest use one native image and fix C inlude lookup
adinn May 30, 2023
34bb8e0
remove file added by accident
adinn May 31, 2023
241d3d7
disable CInterfaceDebugTestDirectives when not running debug test
adinn May 31, 2023
6bb3fc7
fix problem typing embedded pointer fields
adinn Jun 5, 2023
bbb3206
update and document assert condition for layout index
adinn Jun 7, 2023
5e11a03
Respond to review feedback
adinn Jun 12, 2023
59ed1cb
style fixes
adinn Jun 14, 2023
75a2a27
find all known targets of pointer types
adinn Jun 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions substratevm/mx.substratevm/gdb_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Copyright (c) 2023, 2023, 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.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# ----------------------------------------------------------------------------------------------------
# pylint: skip-file
#
# python utility code for use by the gdb scripts that test native debug info

import gdb
import re
import sys
import os

# set various gdb operating modes to desired setting

def configure_gdb():
# disable prompting to continue output
execute("set pagination off")
# enable pretty printing of structures
execute("set print pretty on")
# enable demangling of symbols in assembly code listings
execute("set print asm-demangle on")
# disable printing of address symbols
execute("set print symbol off")
# ensure file listings show only the current line
execute("set listsize 1")


# execute a gdb command and return the resulting output as a string

def execute(command):
print('(gdb) %s'%(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]+'
hex_digits_pattern = '[0-9a-f]+'
spaces_pattern = '[ \t]+'
maybe_spaces_pattern = '[ \t]*'
digits_pattern = '[0-9]+'
line_number_prefix_pattern = digits_pattern + ':' + spaces_pattern
package_pattern = '[a-z/]+'
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[.*$_\]]+)*\)"

# A helper class which checks that a sequence of lines of output
# from a gdb command matches a sequence of per-line regular
# expressions

class Checker:
# Create a checker to check gdb command output text.
# name - string to help identify the check if we have a failure.
# regexps - a list of regular expressions which must match.
# successive lines of checked
def __init__(self, name, regexps):
self.name = name
if not isinstance(regexps, list):
regexps = [regexps]
self.rexps = [re.compile(r) for r in regexps if r is not None]

# Check that successive lines of a gdb command's output text
# match the corresponding regexp patterns provided when this
# Checker was created.
# text - the full output of a gdb comand run by calling
# gdb.execute and passing to_string = True.
# Exits with status 1 if there are less lines in the text
# than regexp patterns or if any line fails to match the
# corresponding pattern otherwise prints the text and returns
# the set of matches.
def check(self, text, skip_fails=True):
lines = text.splitlines()
rexps = self.rexps
num_lines = len(lines)
num_rexps = len(rexps)
line_idx = 0
matches = []
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 not skip_fails:
print('Checker %s: match %d failed at line %d %s\n'%(self.name, i, line_idx, line))
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(self)
print(text)
sys.exit(1)
print(text)
return matches

# Format a Checker as a string
def __str__(self):
rexps = self.rexps
result = 'Checker %s '%(self.name)
result += '{\n'
for rexp in rexps:
result += ' %s\n'%(rexp)
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")
checker = Checker('show version',
r"GNU gdb %s (%s)\.(%s)%s"%(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
56 changes: 33 additions & 23 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,9 @@ def _debuginfotest(native_image, path, build_only, with_isolates_only, args):
mx.log("sourcepath=%s"%sourcepath)
sourcecache = join(path, 'sources')
mx.log("sourcecache=%s"%sourcecache)

# the header file for foreign types resides at the root of the
# com.oracle.svm.test source tree
cincludepath = sourcepath
javaProperties = {}
for dist in suite.dists:
if isinstance(dist, mx.ClasspathDependency):
Expand All @@ -807,23 +809,26 @@ def _debuginfotest(native_image, path, build_only, with_isolates_only, args):
for key, value in javaProperties.items():
args.append("-D" + key + "=" + value)


native_image_args = ["--native-image-info",
'-H:+VerifyNamingConventions',
'-cp', classpath('com.oracle.svm.test'),
'-Dgraal.LogFile=graal.log',
'-g',
'-H:+SourceLevelDebug',
'-H:DebugInfoSourceSearchPath=' + sourcepath,
# We do not want to step into class initializer, so initialize everything at build time.
'--initialize-at-build-time=hello',
'hello.Hello'] + args

def build_debug_test(variant_name, extra_args):
# set property controlling inclusion of foreign struct header
args.append("-DbuildDebugInfoTestExample=true")

native_image_args = [
'--native-compiler-options=-I' + cincludepath,
'-H:CLibraryPath=' + sourcepath,
'--native-image-info',
'-H:+VerifyNamingConventions',
'-cp', classpath('com.oracle.svm.test'),
'-Dgraal.LogFile=graal.log',
'-g',
'-H:+SourceLevelDebug',
'-H:DebugInfoSourceSearchPath=' + sourcepath,
] + args

def build_debug_test(variant_name, image_name, extra_args):
per_build_path = join(path, variant_name)
mkpath(per_build_path)
build_args = native_image_args + extra_args + [
'-o', join(per_build_path, 'hello_image')
'-o', join(per_build_path, image_name)
]
mx.log('native_image {}'.format(build_args))
return native_image(build_args)
Expand All @@ -832,20 +837,25 @@ def build_debug_test(variant_name, extra_args):
if '--libc=musl' in args:
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 not with_isolates_only:
hello_binary = build_debug_test('isolates_off', 'hello_image', testhello_args + ['-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])

hello_binary = build_debug_test('isolates_on', ['-H:+SpawnIsolates'])
hello_binary = build_debug_test('isolates_on', 'hello_image', testhello_args + ['-H:+SpawnIsolates'])
if mx.get_os() == 'linux' and not build_only:
os.environ.update({'debuginfotest_arch' : mx.get_arch()})
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', testhello_py, hello_binary])

if not with_isolates_only:
hello_binary = build_debug_test('isolates_off', ['-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', testhello_py, hello_binary])
mx.run([os.environ.get('GDB_BIN', 'gdb'), '-ex', 'python "ISOLATES=True"', '-x', gdb_utils_py, '-x', testhello_py, hello_binary])

def _javac_image(native_image, path, args=None):
args = [] if args is None else args
Expand Down
Loading