[Pal] Rewrite GDB integration, part 1

For now only gdb-script and Python parts. This is mostly a clean-up of
both Linux and Linux-SGX integration which additionally removes some
annoying user prompts we had in the old scripts.
This commit is contained in:
Michał Kowalczyk
2020-09-12 15:52:52 +02:00
parent 6c614e26ad
commit fd15780628
28 changed files with 242 additions and 193 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ THE_BIG_LIST_OF_NAUGHTY_FILES = list(map(pathlib.Path, [
'LibOS/shim/test/regression/test_libos.py',
'Pal/regression/test_pal.py',
'Pal/src/host/Linux-SGX/sgx-driver/link-intel-driver.py',
'Pal/src/host/Linux/pal-gdb.py',
'Pal/src/host/Linux/gdb_integration/graphene_gdb.py',
'Scripts/regression.py',
'Tools',
]))
-1
View File
@@ -8,7 +8,6 @@ shellcheck "$@" \
Examples/bash/scripts/bash_test.sh \
Examples/common_tools/benchmark-http.sh \
Examples/python-simple/run-tests.sh \
Pal/src/host/Linux-SGX/debugger/gdb \
Runtime/pal_loader \
Scripts/clean-check \
Scripts/clean-check-prepare \
+1 -12
View File
@@ -11,7 +11,6 @@ pal_lib =
pal_lib_deps =
pal_lib_post =
pal_static =
pal_gdb =
HOST_DIR = host/$(PAL_HOST)
LIB_DIR = $(HOST_DIR)/.lib
@@ -63,7 +62,6 @@ host_lib = $(HOST_DIR)/libpal-$(PAL_HOST).a
# Install Targets (all in RUNTIME_DIR):
# pal-{Host Name}: loader for PAL (as an executable)
# libpal-{Host Name}.so: dynamic-linking library
# pal_gdb-{Host Name}: debugger for PAL (as an executable)
ifneq ($(pal_loader),)
runtime_loader += $(RUNTIME_DIR)/pal-$(PAL_HOST)
@@ -73,11 +71,7 @@ ifneq ($(pal_lib),)
runtime_lib += $(RUNTIME_DIR)/libpal-$(PAL_HOST)$(suffix $(pal_lib))
endif
ifneq ($(pal_gdb),)
runtime_gdb += $(RUNTIME_DIR)/pal_gdb-$(PAL_HOST)
endif
files_to_install = $(runtime_loader) $(runtime_lib) $(runtime_sec) $(runtime_gdb)
files_to_install = $(runtime_loader) $(runtime_lib) $(runtime_sec)
###########################
@@ -117,11 +111,6 @@ $(runtime_lib): $(pal_lib)
$(call cmd,ln_sfr)
endif
ifneq ($(pal_gdb),)
$(runtime_gdb): $(pal_gdb)
$(call cmd,ln_sfr)
endif
ifneq ($(pal_lib_post),)
$(pal_lib_post): $(pal_lib)
@$(MAKE) -C $(HOST_DIR) $@
+9 -9
View File
@@ -23,7 +23,7 @@ ASFLAGS += \
-I../../../include \
-I../../../include/arch/$(ARCH)/Linux
host_files = libpal-Linux-SGX.a pal-sgx debugger/sgx_gdb.so pal.map generated_offsets.py
host_files = libpal-Linux-SGX.a pal-sgx gdb_integration/sgx_gdb.so pal.map generated_offsets.py
defs = -DIN_PAL
CFLAGS += $(defs)
@@ -73,7 +73,7 @@ urts-objs = \
sgx_main.o \
sgx_platform.o \
sgx_process.o \
sgx_rtld.o \
sgx_gdb_info.o \
sgx_thread.o \
quote/aesm.pb-c.o \
$(commons_objs_urts)
@@ -125,9 +125,9 @@ quote/aesm.pb-c.c quote/aesm.pb-c.h: quote/aesm.proto
@echo [ host/Linux-SGX/quote/aesm.pb-c.h ]
@protoc-c --c_out=. $<
debugger/sgx_gdb.so: CFLAGS =
CFLAGS-debugger/sgx_gdb.so = -shared -Wall -fPIC -O2 -std=c11
debugger/sgx_gdb.so: debugger/sgx_gdb.c
gdb_integration/sgx_gdb.so: CFLAGS =
CFLAGS-gdb_integration/sgx_gdb.so = -shared -Wall -fPIC -O2 -std=c11
gdb_integration/sgx_gdb.so: gdb_integration/sgx_gdb.c
$(call cmd,csingle)
enclave_entry.o sgx_entry.o: asm-offsets.h
@@ -136,7 +136,7 @@ sgx-driver/sgx.h:
$(MAKE) -C sgx-driver $(notdir $@)
ifeq ($(filter %clean,$(MAKECMDGOALS)),)
include $(wildcard *.d) $(wildcard debugger/*.d)
include $(wildcard *.d) $(wildcard gdb_integration/*.d)
endif
include ../../../../Scripts/Makefile.rules
@@ -146,13 +146,13 @@ tools:
$(MAKE) -C tools
CLEAN_FILES += $(notdir $(pal_static) $(pal_lib) $(pal_loader))
CLEAN_FILES += debugger/sgx_gdb.so
CLEAN_FILES += gdb_integration/sgx_gdb.so
CLEAN_FILES += quote/aesm.pb-c.c quote/aesm.pb-c.h quote/aesm.pb-c.d quote/aesm.pb-c.o
.PHONY: clean_
clean_:
$(RM) -r *.o *.e *.i *.s $(host_files) $(CLEAN_FILES) *.d debugger/*.d signer/*.pyc __pycache__ \
signer/__pycache__
$(RM) -r *.o *.e *.i *.s $(host_files) $(CLEAN_FILES) *.d gdb_integration/*.d signer/*.pyc \
__pycache__ signer/__pycache__
$(RM) -r protected-files/*.o protected-files/*.d
.PHONY: clean
-1
View File
@@ -18,5 +18,4 @@ pal_loader = $(HOST_DIR)/pal-sgx
pal_lib = $(HOST_DIR)/libpal.so
pal_lib_deps = pal-symbols $(HOST_DIR)/pal.map.template $(HOST_DIR)/enclave.lds
pal_static = $(HOST_DIR)/libpal.a
pal_gdb = $(HOST_DIR)/debugger/gdb
pal_signer = pal-sgx-get-token pal-sgx-sign aesm_pb2.py
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/env bash
DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
GDB_SCRIPT=$DIR/pal-gdb.py
GDB_SO=$DIR/sgx_gdb.so
if [ -z "$INSIDE_EMACS" ]; then
set -x
fi
LD_PRELOAD=$GDB_SO gdb -iex "add-auto-load-safe-path $GDB_SCRIPT" "$@"
@@ -1,49 +0,0 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
import gdb # pylint: disable=import-error
# pylint: enable=invalid-name
# pylint: disable=no-self-use,too-few-public-methods
class LoadCommandBreakpoint(gdb.Breakpoint):
def __init__(self):
gdb.Breakpoint.__init__(self, spec="load_gdb_command", internal=1)
def stop(self):
command = gdb.parse_and_eval("(const char *) $rdi").string()
gdb.execute(command)
return False
def signal_handler(event):
if isinstance(event, gdb.SignalEvent):
if event.stop_signal == 'SIGILL':
# handle CPUINFO and RDTSC
inst = gdb.parse_and_eval("*(const unsigned short *) $rip")
if inst == 0xa20f:
print("CPUID bypassed. Ignore this exception.")
gdb.execute("continue")
return
if inst == 0x310f:
print("RDTSC bypassed. Ignore this exception.")
gdb.execute("continue")
return
if __name__ == "__main__":
gdb.execute("set env IN_GDB = 1")
gdb.execute("set env LD_PRELOAD = ")
gdb.execute("handle SIGCONT pass noprint nostop")
gdb.execute("handle SIGKILL pass print stop")
gdb.execute("set disable-randomization off")
gdb.execute("set detach-on-fork off")
gdb.execute("set schedule-multiple on")
gdb.execute("set follow-exec-mode same")
gdb.execute("set follow-fork-mode child")
# Need to disable displaced stepping
gdb.execute("set displaced-stepping off")
LoadCommandBreakpoint()
gdb.events.stop.connect(signal_handler)
@@ -0,0 +1,63 @@
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@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.
# 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
set displaced-stepping off
# CPUID/RDTSC SIGILL skipping. See [2] above.
catch signal SIGILL
# break only on CPUID (0fa2) and RDTSC (0f31)
condition $bpnum *(uint16_t*)$rip == 0xa20f || *(uint16_t*)$rip == 0x310f
commands
silent
# If we don't disable pagination then successive prints from this handler (even despite it's
# called for different events) will stop and prompt the user for continuation, which is really
# annoying.
push-pagination off
if *(uint16_t*)$rip == 0xa20f
echo [graphene_sgx.gdb] Passing SIGILL caused by CPUID to the enclave\n
end
if *(uint16_t*)$rip == 0x310f
echo [graphene_sgx.gdb] Passing SIGILL caused by RDTSC to the enclave\n
end
pop-pagination
continue
end
@@ -0,0 +1,71 @@
# 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
# pylint: disable=no-self-use,too-few-public-methods
_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(PushPagination, self).__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(PopPagination, self).__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'))
class LoadCommandBreakpoint(gdb.Breakpoint):
def __init__(self):
gdb.Breakpoint.__init__(self, spec="execute_gdb_command", internal=1)
def stop(self):
command = gdb.parse_and_eval("(const char*)$rdi").string()
gdb.execute(command)
return False
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)
LoadCommandBreakpoint()
if __name__ == "__main__":
main()
@@ -333,7 +333,7 @@ static int open_memdevice(pid_t tid, int* memdev, struct enclave_dbginfo** ei) {
for (int i = 0; i < g_memdevs_cnt; i++) {
if (g_memdevs[i].pid == tid) {
*memdev = g_memdevs[i].memdev;
*ei = &g_memdevs[i].ei;
*ei = &g_memdevs[i].ei;
return update_thread_tids(*ei);
}
}
@@ -356,7 +356,7 @@ static int open_memdevice(pid_t tid, int* memdev, struct enclave_dbginfo** ei) {
for (int i = 0; i < g_memdevs_cnt; i++) {
if (g_memdevs[i].pid == eib.pid) {
*memdev = g_memdevs[i].memdev;
*ei = &g_memdevs[i].ei;
*ei = &g_memdevs[i].ei;
return update_thread_tids(*ei);
}
}
@@ -408,7 +408,7 @@ static int open_memdevice(pid_t tid, int* memdev, struct enclave_dbginfo** ei) {
sizeof(g_memdevs[g_memdevs_cnt].ei.thread_stepping));
*memdev = fd;
*ei = &g_memdevs[g_memdevs_cnt].ei;
*ei = &g_memdevs[g_memdevs_cnt].ei;
g_memdevs_cnt++;
return 0;
+1 -1
View File
@@ -632,7 +632,7 @@ static long sgx_ocall_eventfd(void* pms) {
static long sgx_ocall_load_debug(void* pms) {
const char* command = (const char*)pms;
ODEBUG(OCALL_LOAD_DEBUG, (void*)command);
load_gdb_command(command);
execute_gdb_command(command);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2020 Intel Corporation
* Michał Kowalczyk <mkow@invisiblethingslab.com>
*/
#include "pal_debug.h"
#include "sgx_internal.h"
/* This function is hooked by our gdb integration script and should be left as is. */
__attribute__((__noinline__)) void execute_gdb_command(const char* command) {
__UNUSED(command);
__asm__ volatile(""); // Required in addition to __noinline__ to prevent deleting this function.
// See GCC docs.
}
+1 -1
View File
@@ -138,6 +138,6 @@ int sgx_signal_setup(void);
int block_signals(bool block, const int* sigs, int nsig);
int block_async_signals(bool block);
void load_gdb_command(const char* command);
void execute_gdb_command(const char* command);
#endif
+1 -1
View File
@@ -8,7 +8,7 @@
#include "pal_rtld.h"
#include "hex.h"
#include "debugger/sgx_gdb.h"
#include "gdb_integration/sgx_gdb.h"
#include "linux_utils.h"
#include "rpc_queue.h"
#include "sgx_api.h"
-27
View File
@@ -1,27 +0,0 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2014 Stony Brook University */
/*
* db_rtld.c
*
* This file contains utilities to load ELF binaries into the memory
* and link them against each other.
* The source code in this file is imported and modified from the GNU C
* Library.
*/
#include "api.h"
#include "pal_internal.h"
#include "sgx_internal.h"
__asm__(
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\r\n"
".byte 1\r\n"
".asciz \"debugger/pal-gdb.py\"\r\n"
".popsection\r\n");
/* This function is hooked by our gdb integration script and should be
* left as is. */
void load_gdb_command(const char* command) {
__UNUSED(command);
}
+1 -1
View File
@@ -11,7 +11,7 @@
#include <linux/signal.h>
#include "assert.h"
#include "debugger/sgx_gdb.h"
#include "gdb_integration/sgx_gdb.h"
#include "pal_internal.h"
#include "pal_security.h"
#include "sgx_enclave.h"
-1
View File
@@ -17,4 +17,3 @@ pal_lib = $(HOST_DIR)/libpal.so
pal_lib_deps = pal-symbols $(HOST_DIR)/pal.map.template $(HOST_DIR)/pal-$(ARCH).lds
pal_lib_post =
pal_static = $(HOST_DIR)/libpal.a
pal_gdb =
-9
View File
@@ -30,15 +30,6 @@
/* pal_start is the entry point of libpal.so, which calls pal_main */
#define _ENTRY pal_start
/* use objfile-gdb convention instead of .debug_gdb_scripts */
#ifdef DEBUG
__asm__(
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\r\n"
".byte 1\r\n"
".asciz \"pal-gdb.py\"\r\n"
".popsection\r\n");
#endif
char* g_pal_loader_path = NULL;
/* Currently content of this variable is only passed as an argument while spawning new processes
* - this is to keep uniformity with other PALs. */
@@ -0,0 +1,38 @@
# 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
@@ -0,0 +1,15 @@
#!/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()
-16
View File
@@ -1,16 +0,0 @@
#!/usr/bin/env python3
import os, sys, gdb
if len(gdb.inferiors()) == 1:
gdb.execute("set env IN_GDB = 1")
gdb.execute("set auto-load off")
sys.stdout.write("Are you loading the script [Y]/n ? ")
sys.stdout.flush()
ans = sys.stdin.readline()
if ans[0] != 'n' and ans[0] != 'N':
gdbfile = os.path.dirname(__file__) + "/pal.gdb"
gdb.execute("source " + gdbfile)
sys.stdout.write("script %s loaded\n" % gdbfile)
-27
View File
@@ -1,27 +0,0 @@
handle SIGCONT pass noprint nostop
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
-1
View File
@@ -16,4 +16,3 @@ pal_lib = $(HOST_DIR)/libpal.so
pal_lib_deps = pal-symbols $(HOST_DIR)/pal.map.template $(HOST_DIR)/pal-$(ARCH).lds
pal_lib_post =
pal_static =
pal_gdb =
-1
View File
@@ -1,3 +1,2 @@
/pal-Linux
/pal-Linux-SGX
/pal_gdb-Linux-SGX
+1 -1
View File
@@ -3,7 +3,7 @@ all:
.PHONY: clean
clean:
$(RM) *.a *.o *.so *.so.* pal_gdb* pal-*
$(RM) *.a *.o *.so *.so.* pal-*
.PHONY: distclean
distclean: clean
+16 -18
View File
@@ -1,4 +1,9 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-3.0-or-later */
# Copyright (C) 2014 Stony Brook University
# Copyright (C) 2019 Invisible Things Lab
# Copyright (C) 2020 Intel Corporation
# Michał Kowalczyk <mkow@invisiblethingslab.com>
while :
do
@@ -42,28 +47,22 @@ if [ -z "$PAL_HOST" ]; then
fi
MANIFEST=
ENVS=()
PREFIX=()
PAL_CMD=$RUNTIME_DIR/pal-$PAL_HOST
PAL_CMD="$RUNTIME_DIR/pal-$PAL_HOST"
LIBPAL_PATH=$(realpath "$RUNTIME_DIR/libpal-$PAL_HOST.so")
HOST_PAL_PATH=$(realpath "$RUNTIME_DIR/../Pal/src/host/$PAL_HOST")
if [ "$GDB" == "1" ]; then
GDB=$RUNTIME_DIR/pal_gdb-$PAL_HOST
if [ ! -f "$GDB" ]; then
GDB="gdb"
fi
fi
if [ "$GDB" != "" ] && [ "$GDB" != "0" ]; then
PREFIX=("$GDB" -q)
PREFIX=("gdb" "-q")
if [ -n "$INSIDE_EMACS" ]; then
PREFIX+=("-i=mi")
fi
if [ -v SGX ]; then
PREFIX+=("-iex")
PREFIX+=("dir $RUNTIME_DIR/../Pal/src/host/Linux-SGX")
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/graphene_sgx_gdb.py")
ENVS+=("LD_PRELOAD=$HOST_PAL_PATH/gdb_integration/sgx_gdb.so")
else
PREFIX+=("-iex")
PREFIX+=("dir $RUNTIME_DIR/../Pal/src/host/Linux")
PREFIX+=("-x" "$HOST_PAL_PATH/gdb_integration/graphene_gdb.py")
fi
PREFIX+=("--args")
fi
@@ -93,8 +92,7 @@ if [ ! -f "$PAL_CMD" ]; then
exit 1
fi
if [ ${#PREFIX[@]} -eq 0 ]; then
exec "$PAL_CMD" "$LIBPAL_PATH" init "$MANIFEST" "$@"
else
exec "${PREFIX[@]}" "$PAL_CMD" "$LIBPAL_PATH" init "$MANIFEST" "$@"
fi
CMD=("${ENVS[@]}")
CMD+=("${PREFIX[@]}")
CMD+=("$PAL_CMD" "$LIBPAL_PATH" init "$MANIFEST" "$@")
exec env "${CMD[@]}"
@@ -47,8 +47,12 @@ COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/signer/pal_sgx_sign.py /gr
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/generated_offsets.py /graphene/signer/
COPY --from=graphene /graphene/Tools/argv_serializer /graphene/Tools
{% if debug %}
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/debugger/sgx_gdb.so /graphene/Runtime
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/debugger/pal-gdb.py /graphene/Runtime
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/gdb_integration/sgx_gdb.so \
/graphene/Pal/src/host/Linux-SGX/gdb_integration/
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/gdb_integration/graphene_sgx_gdb.py \
/graphene/Pal/src/host/Linux-SGX/gdb_integration/
COPY --from=graphene /graphene/Pal/src/host/Linux-SGX/gdb_integration/graphene_sgx.gdb \
/graphene/Pal/src/host/Linux-SGX/gdb_integration/
{% endif %}
# Copy template scripts and manifests