[Pal] Clean up GDB configuration

- Extract parts that are common for all hosts
- Remove some outdated/unnecessary options, we should now be
  closer to default configuration
- Disable libthread_db loading (does not work and crashes GDB 9.2)
- Disable pagination when loading debug maps
This commit is contained in:
Paweł Marczewski
2021-01-29 15:30:53 +01:00
committed by Michał Kowalczyk
parent c59a1438d5
commit 09c6307631
15 changed files with 146 additions and 142 deletions

View File

@@ -3,6 +3,9 @@
# Copyright (C) 2020 Intel Corporation
# Paweł Marczewski <pawel@invisiblethingslab.com>
# Debug map handling, so that GDB sees all ELF binaries loaded by Graphene. Connects with
# debug_map.c (in PAL) using a breakpoint on debug_map_update_debugger() function.
import os
import shlex
@@ -128,7 +131,14 @@ class UpdateDebugMaps(gdb.Command):
cmd += ' '.join('-s {} 0x{:x}'.format(shlex.quote(name), addr)
for name, addr in sections
if name != '.text')
gdb.execute(cmd)
try:
# Temporarily disable pagination, because 'add-symbol-file` produces a lot of
# noise.
gdb.execute('push-pagination off')
gdb.execute(cmd)
finally:
gdb.execute('pop-pagination')
progspace.debug_maps = new

View File

@@ -0,0 +1,31 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2021 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
# Paweł Marczewski <pawel@invisiblethingslab.com>
# Graphene GDB configuration (common for all hosts).
# Tell Graphene to behave more gdb-friendly.
set env IN_GDB=1
# Used internally by Graphene, generates a lot of noise if we don't silence it.
handle SIGCONT pass noprint nostop
# Disable loading inferior-specific libthread_db library. This does not work with our patched
# libpthread, and prevents newer GDB versions (9.2+) from working when a program uses libpthread.
set auto-load libthread-db off
set libthread-db-search-path ""
# Reenable address space layout randomization (ASLR). Graphene's features often take memory layout
# into account, so running with ASLR enabled is more realistic and allows us to catch issues sooner.
set disable-randomization off
# Make GDB follow both sides of the fork - GDB (at least version 8.1) crashes on Graphene running
# some applications otherwise (e.g. exit_group regression test).
set detach-on-fork off
# Resume all processes by default. This is to negate consequences of 'set detach-on-fork off': by
# default, it keeps running only one side of the fork. This is usually not what we want, and it's
# particularly annoying in Graphene, because checkpoint data is sent between processes just after
# forking.
set schedule-multiple on

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
# Paweł Marczewski <pawel@invisiblethingslab.com>
# Commands for temporarily changing pagination state. Used by other Graphene GDB scripts in
# situation where we produce a lot of noise and we don't want to repeatedly prompt user for
# continuation.
import gdb # pylint: disable=import-error
_g_paginations = []
class PushPagination(gdb.Command):
"""Temporarily change pagination and save the old state"""
def __init__(self):
super().__init__("push-pagination", gdb.COMMAND_USER)
def invoke(self, arg, _from_tty):
self.dont_repeat()
pagination_str = gdb.execute('show pagination', to_string=True).strip()
assert pagination_str in ('State of pagination is on.', 'State of pagination is off.')
pagination = pagination_str.endswith('on.')
_g_paginations.append(pagination)
assert arg in ('on', 'off')
gdb.execute('set pagination ' + arg)
class PopPagination(gdb.Command):
"""Recover pagination state saved by PushPagination"""
def __init__(self):
super().__init__("pop-pagination", gdb.COMMAND_USER)
def invoke(self, arg, _from_tty):
self.dont_repeat()
assert arg == ''
pagination = _g_paginations.pop()
gdb.execute('set pagination ' + ('on' if pagination else 'off'))
def main():
PushPagination()
PopPagination()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1 @@
../../../../gdb_integration/

View File

@@ -1 +0,0 @@
../../../../gdb_integration/debug_map_gdb.py

View File

@@ -1,47 +1,28 @@
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Copyright (C) 2021 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
# Paweł Marczewski <pawel@invisiblethingslab.com>
# GDB Python "API" [1] is so wonderful that what we need [2] is not possible to be implemented using
# it, so we have to fall back to raw GDB scripting. But raw GDB scripting is also broken, so we need
# to supply things like `push-pagination` command from Python.
#
# [1] It mostly consists of `gdb.execute()`, there isn't even gdb.continue() API, you need to call
# `gdb.execute('continue')`.
# [2] One of the things we want is to silently pass SIGILLs caused by CPUID and RDTSC to the
# application, but without silencing SIGILLs caused by other reasons. This is impossible to
# implement from GDB Python "API", neither using event handlers nor even executing raw commands
# with gdb.execute() - it doesn't support multiline commands, and gdb.execute('commands') blocks
# for input on the *user terminal*, not giving the script a chance to provide more lines.
# Graphene GDB configuration (Linux-SGX specific).
# Prevent the preloaded sgx_gdb.so from being preloaded to the debuggee.
set env LD_PRELOAD=
# Tell Graphene to behave more gdb-friendly.
set env IN_GDB=1
# Used internally by Graphene, generates a lot of noise if we don't silence it.
handle SIGCONT pass noprint nostop
# TODO: This block of commands was copied from an older Graphene integration script where they
# didn't have any comments with rationale why they are needed. We should revise and comment them.
handle SIGKILL pass print stop
set disable-randomization off
set detach-on-fork off
set schedule-multiple on
set follow-exec-mode same
set follow-fork-mode child
# Disable displaced stepping. Displaced stepping means GDB executes an out-of-line copy of an
# instruction, instead of the original instruction at breakpoint location. This does not work when
# the instruction in question is located in SGX enclave memory, and should be executed in enclave.
set displaced-stepping off
# CPUID/RDTSC SIGILL skipping. See [2] above.
# CPUID/RDTSC SIGILL skipping. We want to silently pass SIGILLs caused by CPUID and RDTSC
# instructions to the application, but without silencing SIGILLs caused by other reasons.
# (This seems impossible to implement in Python, either by using event handlers or even executing
# raw commands with gdb.execute(). gdb.execute() doesn't support multiline commands, and instead
# blocks for input on the *user terminal*, not giving the script a chance to provide more lines.)
catch signal SIGILL
# break only on CPUID (0fa2) and RDTSC (0f31)
condition $bpnum *(uint16_t*)$rip == 0xa20f || *(uint16_t*)$rip == 0x310f
commands
silent

View File

@@ -7,53 +7,16 @@ import os
import gdb # pylint: disable=import-error
_g_paginations = []
class PushPagination(gdb.Command):
"""Temporarily changing pagination and saving the old state.
Supplements gdb interface with functionality it's missing and seems to not be possible to
implement from a gdb script. This command is used by graphene_sgx.gdb script.
"""
def __init__(self):
super().__init__("push-pagination", gdb.COMMAND_USER)
def invoke(self, arg, _from_tty):
self.dont_repeat()
pagination_str = gdb.execute('show pagination', to_string=True).strip()
assert pagination_str in ('State of pagination is on.', 'State of pagination is off.')
pagination = pagination_str.endswith('on.')
_g_paginations.append(pagination)
assert arg in ('on', 'off')
gdb.execute('set pagination ' + arg)
class PopPagination(gdb.Command):
"""Recover pagination state saved by PushPagination"""
def __init__(self):
super().__init__("pop-pagination", gdb.COMMAND_USER)
def invoke(self, arg, _from_tty):
self.dont_repeat()
assert arg == ''
pagination = _g_paginations.pop()
gdb.execute('set pagination ' + ('on' if pagination else 'off'))
def main():
PushPagination()
PopPagination()
# Some of the things we want to do can't be done using gdb Python API, we need to fall back to a
# standard gdb script.
gdb_script = os.path.dirname(__file__) + "/graphene_sgx.gdb"
print("[%s] Loading %s..." % (os.path.basename(__file__), gdb_script))
gdb.execute("source " + gdb_script)
for filename in [
'common/pagination_gdb.py',
'common/debug_map_gdb.py',
'common/graphene.gdb',
'graphene_sgx.gdb',
]:
print("[%s] Loading %s..." % (os.path.basename(__file__), filename))
path = os.path.join(os.path.dirname(__file__), filename)
gdb.execute("source " + path)
if __name__ == "__main__":

View File

@@ -0,0 +1 @@
../../../../gdb_integration/

View File

@@ -1 +0,0 @@
../../../../gdb_integration/debug_map_gdb.py

View File

@@ -1,38 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
# Tell Graphene to behave more gdb-friendly.
set env IN_GDB=1
# Used internally by Graphene, generates a lot of noise if we don't silence it.
handle SIGCONT pass noprint nostop
# TODO: This block of commands was copied from an older Graphene integration script where they
# didn't have any comments with rationale why they are needed. We should revise and comment them.
set auto-load off
handle SIGKILL pass print stop
set disable-randomization off
set detach-on-fork off
set schedule-multiple on
set follow-fork-mode child
break pal_start
command
silent
set scheduler-locking off
continue
end
break thread_start
command
silent
continue
end
catch vfork
command
silent
set scheduler-locking on
continue
end

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
import os
import gdb # pylint: disable=import-error
def main():
gdb_script = os.path.dirname(__file__) + "/graphene.gdb"
print("[%s] Loading %s..." % (os.path.basename(__file__), gdb_script))
gdb.execute("source " + gdb_script)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
import os
import gdb # pylint: disable=import-error
def main():
for filename in [
'common/pagination_gdb.py',
'common/debug_map_gdb.py',
'common/graphene.gdb',
]:
print("[%s] Loading %s..." % (os.path.basename(__file__), filename))
path = os.path.join(os.path.dirname(__file__), filename)
gdb.execute("source " + path)
if __name__ == '__main__':
main()

View File

@@ -6,9 +6,10 @@ if direct
install_dir: join_paths(pkglibexecdir, 'linux'))
install_subdir('../Pal/src/host/Linux/gdb_integration',
install_dir: join_paths(pkglibexecdir, 'linux'),
exclude_files: ['debug_map_gdb.py'])
exclude_directories: ['common'])
install_subdir('../Pal/gdb_integration',
install_dir: join_paths(pkglibexecdir, 'linux'))
install_dir: join_paths(pkglibexecdir, 'linux/gdb_integration/common'),
strip_directory: true)
hostpalpath_linux = join_paths(prefix, pkglibexecdir, 'linux')
conf_graphene = configuration_data()
@@ -33,9 +34,10 @@ if sgx
install_dir: join_paths(pkglibexecdir, 'linux-sgx'))
install_subdir('../Pal/src/host/Linux-SGX/gdb_integration',
install_dir: join_paths(pkglibexecdir, 'linux-sgx'),
exclude_files: ['debug_map_gdb.py'])
exclude_directories: ['common'])
install_subdir('../Pal/gdb_integration',
install_dir: join_paths(pkglibexecdir, 'linux-sgx'))
install_dir: join_paths(pkglibexecdir, 'linux-sgx/gdb_integration/common'),
strip_directory: true)
hostpalpath_linux_sgx = join_paths(prefix, pkglibexecdir, 'linux-sgx')
conf_graphene_sgx = configuration_data()

View File

@@ -77,12 +77,10 @@ if [ "$GDB" == "1" ]; then
PREFIX+=("-i=mi")
fi
if [ 0"$SGX" -gt 0 ]; then
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/debug_map_gdb.py")
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/graphene_sgx_gdb.py")
ENVS+=("LD_PRELOAD=$HOST_PAL_PATH/gdb_integration/sgx_gdb.so:$LD_PRELOAD")
else
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/debug_map_gdb.py")
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/graphene_gdb.py")
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/graphene_linux_gdb.py")
fi
if [ "$GDB_SCRIPT" != "" ]; then
# Run a script in batch mode, and without TTY (so that it can be piped, redirected etc.)

View File

@@ -40,13 +40,12 @@ class RegressionTestCase(unittest.TestCase):
# See also pal_loader.
prefix = ['gdb', '-q']
env = os.environ.copy()
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/debug_map_gdb.py')]
if HAS_SGX:
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/graphene_sgx_gdb.py')]
sgx_gdb = os.path.join(host_pal_path, 'gdb_integration/sgx_gdb.so')
env['LD_PRELOAD'] = sgx_gdb + ':' + env.get('LD_PRELOAD', '')
else:
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/graphene_gdb.py')]
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/graphene_linux_gdb.py')]
# Override TTY, as apparently os.setpgrp() confuses GDB and causes it to hang.
prefix += ['-x', gdb_script, '-batch', '-tty=/dev/null']