Testing, gdbstub and semihosting patches:

- clean-ups to docker images
   - drop duplicate jobs from shippable
   - prettier tag generation (+gtags)
   - generate browsable source tree
   - more Travis->GitLab migrations
   - fix checkpatch to deal with commits
   - gate gdbstub tests on 8.3.1, expand tests
   - support Xfer:auxv:read gdb packet
   - better gdbstub cleanup
   - use GDB's SVE register layout
   - make arm-compat-semihosting common
   - add riscv semihosting support
   - add HEAPINFO, ELAPSED, TICKFREQ, TMPNAM and ISERROR to semihosting
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmAFXkcACgkQ+9DbCVqe
 KkSP7Af/YNU4dWFf/N9CwvKQTSoJmBrO77HXccOJyYDS62hA8eoh83HWNll+xMV7
 GxJDwQs0GS8J3oqcq1DktGgTUkCNxUfbHROjI2YXfRzoWnl0PFHY+Z/qRsq+bRhX
 C3CiNCS/nM/NW2Q+H6TAD1MnXkia11+hqFhXrBRKVDON83MSvm0AspS5RO5eVpxo
 TUTOD1YND+tAPWi5xAN+NyDuvfoY3tG4S4/DFUrHQfpS7uaHY/4qe8gMmJczveeo
 uzJln9M7+pV5cgUWwr1fgCkbSyGgra+KX3GNoLIGS34C88cKRXAp7ZF19A3wQpiy
 LXljmOinLfKuJqeRGwcnt6f8GrTn7A==
 =XR0h
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-and-misc-180121-2' into staging

Testing, gdbstub and semihosting patches:

  - clean-ups to docker images
  - drop duplicate jobs from shippable
  - prettier tag generation (+gtags)
  - generate browsable source tree
  - more Travis->GitLab migrations
  - fix checkpatch to deal with commits
  - gate gdbstub tests on 8.3.1, expand tests
  - support Xfer:auxv:read gdb packet
  - better gdbstub cleanup
  - use GDB's SVE register layout
  - make arm-compat-semihosting common
  - add riscv semihosting support
  - add HEAPINFO, ELAPSED, TICKFREQ, TMPNAM and ISERROR to semihosting

# gpg: Signature made Mon 18 Jan 2021 10:09:11 GMT
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* remotes/stsquad/tags/pull-testing-and-misc-180121-2: (30 commits)
  semihosting: Implement SYS_ISERROR
  semihosting: Implement SYS_TMPNAM
  semihosting: Implement SYS_ELAPSED and SYS_TICKFREQ
  riscv: Add semihosting support for user mode
  riscv: Add semihosting support
  semihosting: Support SYS_HEAPINFO when env->boot_info is not set
  semihosting: Change internal common-semi interfaces to use CPUState *
  semihosting: Change common-semi API to be architecture-independent
  semihosting: Move ARM semihosting code to shared directories
  target/arm: use official org.gnu.gdb.aarch64.sve layout for registers
  gdbstub: ensure we clean-up when terminated
  gdbstub: drop gdbserver_cleanup in favour of gdb_exit
  gdbstub: drop CPUEnv from gdb_exit()
  gdbstub: add support to Xfer:auxv:read: packet
  gdbstub: implement a softmmu based test
  Revert "tests/tcg/multiarch/Makefile.target: Disable run-gdbstub-sha1 test"
  configure: gate our use of GDB to 8.3.1 or above
  test/guest-debug: echo QEMU command as well
  scripts/checkpatch.pl: fix git-show invocation to include diffstat
  gitlab: migrate the minimal tools and unit tests from Travis
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

# Conflicts:
#	default-configs/targets/riscv32-linux-user.mak
#	default-configs/targets/riscv64-linux-user.mak
This commit is contained in:
Peter Maydell 2021-01-18 12:09:21 +00:00
commit 8814b1327c
64 changed files with 982 additions and 336 deletions

3
.gitignore vendored
View File

@ -7,6 +7,9 @@
cscope.*
tags
TAGS
GPATH
GRTAGS
GTAGS
*~
*.ast_raw
*.depend_raw

View File

@ -79,7 +79,6 @@ build-system-ubuntu:
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
moxie-softmmu microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
CONFIGURE_ARGS: --enable-docs
artifacts:
expire_in: 2 days
paths:
@ -111,7 +110,6 @@ build-system-debian:
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
MAKE_CHECK_ARGS: check-build
CONFIGURE_ARGS: --enable-docs
artifacts:
expire_in: 2 days
paths:
@ -126,6 +124,19 @@ check-system-debian:
IMAGE: debian-amd64
MAKE_CHECK_ARGS: check
# No targets are built here, just tools, docs, and unit tests. This
# also feeds into the eventual documentation deployment steps later
build-tools-and-docs-debian:
<<: *native_build_job_definition
variables:
IMAGE: debian-amd64
MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
artifacts:
expire_in: 2 days
paths:
- build
acceptance-system-debian:
<<: *native_test_job_definition
needs:
@ -596,14 +607,21 @@ build-libvhost-user:
- meson
- ninja
# Prepare for GitLab pages deployment. Anything copied into the
# "public" directory will be deployed to $USER.gitlab.io/$PROJECT
pages:
image: $CI_REGISTRY_IMAGE/qemu/ubuntu2004:latest
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
stage: test
needs:
- job: build-system-ubuntu
artifacts: true
- job: build-tools-and-docs-debian
script:
- mkdir public
- mkdir -p public
# HTML-ised source tree
- make gtags
- htags -anT --tree-view=filetree -m qemu_init
-t "Welcome to the QEMU sourcecode"
- mv HTML public/src
# Project documentation
- mv build/docs/index.html public/
- for i in devel interop specs system tools user ; do mv build/docs/$i public/ ; done
artifacts:

View File

@ -7,20 +7,8 @@ env:
matrix:
- IMAGE=debian-amd64
TARGET_LIST=x86_64-softmmu,x86_64-linux-user
- IMAGE=debian-armel-cross
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
- IMAGE=debian-armhf-cross
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
- IMAGE=debian-arm64-cross
TARGET_LIST=aarch64-softmmu,aarch64-linux-user
- IMAGE=debian-s390x-cross
TARGET_LIST=s390x-softmmu,s390x-linux-user
- IMAGE=debian-mips-cross
TARGET_LIST=mips-softmmu,mipsel-linux-user
- IMAGE=debian-mips64el-cross
TARGET_LIST=mips64el-softmmu,mips64el-linux-user
- IMAGE=debian-ppc64el-cross
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
TARGET_LIST=mips-softmmu
build:
pre_ci_boot:
image_name: registry.gitlab.com/qemu-project/qemu/qemu/${IMAGE}

View File

@ -119,15 +119,6 @@ after_script:
jobs:
include:
# Just build tools and run minimal unit and softfloat checks
- name: "GCC check-unit and check-softfloat"
env:
- BASE_CONFIG="--enable-tools"
- CONFIG="--disable-user --disable-system"
- TEST_CMD="make check-unit check-softfloat -j${JOBS}"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
# --enable-debug implies --enable-debug-tcg, also runs quite a bit slower
- name: "GCC debug (main-softmmu)"
env:
@ -148,22 +139,6 @@ jobs:
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
# Check we can build docs and tools (out of tree)
- name: "tools and docs (bionic)"
dist: bionic
env:
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
- BASE_CONFIG="--enable-tools --enable-docs"
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
addons:
apt:
packages:
- ninja-build
- python3-sphinx
- perl
# Test with Clang for compile portability (Travis uses clang-5.0)
- name: "Clang (user)"
env:

View File

@ -2322,6 +2322,7 @@ R: Philippe Mathieu-Daudé <philmd@redhat.com>
S: Maintained
F: gdbstub*
F: gdb-xml/
F: tests/tcg/multiarch/gdbstub/
Memory API
M: Paolo Bonzini <pbonzini@redhat.com>
@ -2736,6 +2737,7 @@ Yank feature
M: Lukas Straub <lukasstraub2@web.de>
S: Odd fixes
F: util/yank.c
F: stubs/yank.c
F: include/qemu/yank.h
F: qapi/yank.json

View File

@ -250,19 +250,49 @@ find-src-path = find "$(SRC_PATH)/" -path "$(SRC_PATH)/meson" -prune -o \( -name
.PHONY: ctags
ctags:
rm -f "$(SRC_PATH)/"tags
$(find-src-path) -exec ctags -f "$(SRC_PATH)/"tags --append {} +
$(call quiet-command, \
rm -f "$(SRC_PATH)/"tags, \
"CTAGS", "Remove old tags")
$(call quiet-command, \
$(find-src-path) -exec ctags \
-f "$(SRC_PATH)/"tags --append {} +, \
"CTAGS", "Re-index $(SRC_PATH)")
.PHONY: gtags
gtags:
$(call quiet-command, \
rm -f "$(SRC_PATH)/"GTAGS; \
rm -f "$(SRC_PATH)/"GRTAGS; \
rm -f "$(SRC_PATH)/"GPATH, \
"GTAGS", "Remove old $@ files")
$(call quiet-command, \
(cd $(SRC_PATH) && \
$(find-src-path) | gtags -f -), \
"GTAGS", "Re-index $(SRC_PATH)")
.PHONY: TAGS
TAGS:
rm -f "$(SRC_PATH)/"TAGS
$(find-src-path) -exec etags -f "$(SRC_PATH)/"TAGS --append {} +
$(call quiet-command, \
rm -f "$(SRC_PATH)/"TAGS, \
"TAGS", "Remove old $@")
$(call quiet-command, \
$(find-src-path) -exec etags \
-f "$(SRC_PATH)/"TAGS --append {} +, \
"TAGS", "Re-index $(SRC_PATH)")
.PHONY: cscope
cscope:
rm -f "$(SRC_PATH)"/cscope.*
$(find-src-path) -print | sed -e 's,^\./,,' > "$(SRC_PATH)/cscope.files"
cscope -b -i"$(SRC_PATH)/cscope.files" -f"$(SRC_PATH)"/cscope.out
$(call quiet-command, \
rm -f "$(SRC_PATH)/"cscope.* , \
"cscope", "Remove old $@ files")
$(call quiet-command, \
($(find-src-path) -print | sed -e 's,^\./,,' \
> "$(SRC_PATH)/cscope.files"), \
"cscope", "Create file list")
$(call quiet-command, \
cscope -b -i"$(SRC_PATH)/cscope.files" \
-f"$(SRC_PATH)"/cscope.out, \
"cscope", "Re-index $(SRC_PATH)")
# Needed by "meson install"
export DESTDIR
@ -279,7 +309,7 @@ help:
$(call print-help,all,Build all)
$(call print-help,dir/file.o,Build specified target only)
$(call print-help,install,Install QEMU, documentation and tools)
$(call print-help,ctags/TAGS,Generate tags file for editors)
$(call print-help,ctags/gtags/TAGS,Generate tags file for editors)
$(call print-help,cscope,Generate cscope index)
$(call print-help,sparse,Run sparse on the QEMU source)
@echo ''

View File

@ -333,7 +333,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef CONFIG_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
gdb_exit(arg1);
qemu_plugin_atexit_cb();
/* XXX: should free thread stack and CPU env */
_exit(arg1);
@ -435,7 +435,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef CONFIG_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
gdb_exit(arg1);
qemu_plugin_atexit_cb();
/* XXX: should free thread stack and CPU env */
_exit(arg1);
@ -514,7 +514,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef CONFIG_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
gdb_exit(arg1);
qemu_plugin_atexit_cb();
/* XXX: should free thread stack and CPU env */
_exit(arg1);

7
configure vendored
View File

@ -6166,8 +6166,11 @@ if test "$plugins" = "yes" ; then
fi
fi
if test -n "$gdb_bin" ; then
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
if test -n "$gdb_bin"; then
gdb_version=$($gdb_bin --version | head -n 1)
if version_ge ${gdb_version##* } 8.3.1; then
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
fi
fi
if test "$secret_keyring" = "yes" ; then

View File

@ -42,4 +42,5 @@ CONFIG_FSL_IMX25=y
CONFIG_FSL_IMX7=y
CONFIG_FSL_IMX6UL=y
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
CONFIG_ALLWINNER_H3=y

View File

@ -3,6 +3,8 @@
# Uncomment the following lines to disable these optional devices:
#
#CONFIG_PCI_DEVICES=n
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
# Boards:
#

View File

@ -3,6 +3,8 @@
# Uncomment the following lines to disable these optional devices:
#
#CONFIG_PCI_DEVICES=n
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
# Boards:
#

View File

@ -2,3 +2,4 @@ TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -3,3 +3,4 @@ TARGET_BASE_ARCH=arm
TARGET_WORDS_BIGENDIAN=y
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common,oabi
TARGET_SYSTBL=syscall.tbl
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -4,3 +4,4 @@ TARGET_SYSTBL=syscall.tbl
TARGET_WORDS_BIGENDIAN=y
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -2,3 +2,4 @@ TARGET_ARCH=riscv32
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -2,3 +2,4 @@ TARGET_ARCH=riscv64
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -1978,6 +1978,7 @@ static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
/* Kill the target */
put_packet("OK");
error_report("QEMU: Terminated via GDBstub");
gdb_exit(0);
exit(0);
}
@ -2172,6 +2173,12 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
";ReverseStep+;ReverseContinue+");
}
#ifdef CONFIG_USER_ONLY
if (gdbserver_state.c_cpu->opaque) {
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
}
#endif
if (gdb_ctx->num_params &&
strstr(gdb_ctx->params[0].data, "multiprocess+")) {
gdbserver_state.multiprocess = true;
@ -2233,6 +2240,46 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
gdbserver_state.str_buf->len, true);
}
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER)
static void handle_query_xfer_auxv(GdbCmdContext *gdb_ctx, void *user_ctx)
{
TaskState *ts;
unsigned long offset, len, saved_auxv, auxv_len;
const char *mem;
if (gdb_ctx->num_params < 2) {
put_packet("E22");
return;
}
offset = gdb_ctx->params[0].val_ul;
len = gdb_ctx->params[1].val_ul;
ts = gdbserver_state.c_cpu->opaque;
saved_auxv = ts->info->saved_auxv;
auxv_len = ts->info->auxv_len;
mem = (const char *)(saved_auxv + offset);
if (offset > auxv_len) {
put_packet("E00");
return;
}
if (len > (MAX_PACKET_LENGTH - 5) / 2) {
len = (MAX_PACKET_LENGTH - 5) / 2;
}
if (len < auxv_len - offset) {
g_string_assign(gdbserver_state.str_buf, "m");
memtox(gdbserver_state.str_buf, mem, len);
} else {
g_string_assign(gdbserver_state.str_buf, "l");
memtox(gdbserver_state.str_buf, mem, auxv_len - offset);
}
put_packet_binary(gdbserver_state.str_buf->str,
gdbserver_state.str_buf->len, true);
}
#endif
static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
{
put_packet(GDB_ATTACHED);
@ -2338,6 +2385,14 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
.cmd_startswith = 1,
.schema = "s:l,l0"
},
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER)
{
.handler = handle_query_xfer_auxv,
.cmd = "Xfer:auxv:read::",
.cmd_startswith = 1,
.schema = "l,l0"
},
#endif
{
.handler = handle_query_attached,
.cmd = "Attached:",
@ -2485,6 +2540,7 @@ static int gdb_handle_packet(const char *line_buf)
case 'k':
/* Kill the target */
error_report("QEMU: Terminated via GDBstub");
gdb_exit(0);
exit(0);
case 'D':
{
@ -3014,7 +3070,7 @@ static void gdb_read_byte(uint8_t ch)
}
/* Tell the remote gdb that the process has exited. */
void gdb_exit(CPUArchState *env, int code)
void gdb_exit(int code)
{
char buf[4];
@ -3493,13 +3549,6 @@ int gdbserver_start(const char *device)
return 0;
}
void gdbserver_cleanup(void)
{
if (gdbserver_state.init) {
put_packet("W00");
}
}
static void register_types(void)
{
type_register_static(&char_gdb_type_info);

View File

@ -1,3 +1,7 @@
config SEMIHOSTING
bool
config ARM_COMPATIBLE_SEMIHOSTING
bool
select SEMIHOSTING

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/*
* Semihosting support for systems modeled on the Arm "Angel"
* semihosting syscalls design. This includes Arm and RISC-V processors
*
* Copyright (c) 2005, 2007 CodeSourcery.
* Copyright (c) 2019 Linaro
* Written by Paul Brook.
*
* Copyright © 2020 by Keith Packard <keithp@keithp.com>
* Adapted for systems other than ARM, including RISC-V, by Keith Packard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* ARM Semihosting is documented in:
* Semihosting for AArch32 and AArch64 Release 2.0
* https://static.docs.arm.com/100863/0200/semihosting.pdf
*
* RISC-V Semihosting is documented in:
* RISC-V Semihosting
* https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
*/
#ifndef COMMON_SEMI_H
#define COMMON_SEMI_H
target_ulong do_common_semihosting(CPUState *cs);
#endif /* COMMON_SEMI_H */

View File

@ -2,3 +2,6 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
'config.c',
'console.c',
))
specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
if_true: files('arm-compat-semi.c'))

View File

@ -46,7 +46,17 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va);
int use_gdb_syscalls(void);
void gdb_set_stop_cpu(CPUState *cpu);
void gdb_exit(CPUArchState *, int);
/**
* gdb_exit: exit gdb session, reporting inferior status
* @code: exit code reported
*
* This closes the session and sends a final packet to GDB reporting
* the exit status of the program. It also cleans up any connections
* detritus before returning.
*/
void gdb_exit(int code);
#ifdef CONFIG_USER_ONLY
/**
* gdb_handlesig: yield control to gdb
@ -187,8 +197,6 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
*/
int gdbserver_start(const char *port_or_device);
void gdbserver_cleanup(void);
/**
* gdb_has_xml:
* This is an ugly hack to cope with both new and old gdb.

View File

@ -808,6 +808,8 @@ static inline int64_t get_clock_realtime(void)
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
}
extern int64_t clock_start;
/* Warning: don't insert tracepoints into these functions, they are
also used by simpletrace backend and tracepoints would cause
an infinite recursion! */

View File

@ -22,6 +22,7 @@
#include "qemu.h"
#include "cpu_loop-common.h"
#include "qemu/guest-random.h"
#include "hw/semihosting/common-semi.h"
#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_SEMIHOST:
env->xregs[0] = do_arm_semihosting(env);
env->xregs[0] = do_common_semihosting(cs);
env->pc += 4;
break;
case EXCP_YIELD:

View File

@ -22,6 +22,7 @@
#include "qemu.h"
#include "elf.h"
#include "cpu_loop-common.h"
#include "hw/semihosting/common-semi.h"
#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
@ -421,7 +422,7 @@ void cpu_loop(CPUARMState *env)
}
break;
case EXCP_SEMIHOST:
env->regs[0] = do_arm_semihosting(env);
env->regs[0] = do_common_semihosting(cs);
env->regs[15] += env->thumb ? 2 : 4;
break;
case EXCP_INTERRUPT:

View File

@ -1,6 +1,3 @@
linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
subdir('nwfpe')
syscall_nr_generators += {

View File

@ -34,6 +34,6 @@ void preexit_cleanup(CPUArchState *env, int code)
#ifdef CONFIG_GCOV
__gcov_dump();
#endif
gdb_exit(env, code);
gdb_exit(code);
qemu_plugin_atexit_cb();
}

View File

@ -16,6 +16,7 @@ linux_user_ss.add(rt)
linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
syscall_nr_generators = {}

View File

@ -109,6 +109,8 @@ typedef struct TaskState {
/* FPA state */
FPA11 fpa;
# endif
#endif
#if defined(TARGET_ARM) || defined(TARGET_RISCV)
int swi_errno;
#endif
#if defined(TARGET_I386) && !defined(TARGET_X86_64)
@ -122,7 +124,7 @@ typedef struct TaskState {
#ifdef TARGET_M68K
abi_ulong tp_value;
#endif
#if defined(TARGET_ARM) || defined(TARGET_M68K)
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV)
/* Extra fields for semihosted binaries. */
abi_ulong heap_base;
abi_ulong heap_limit;

View File

@ -23,6 +23,7 @@
#include "qemu.h"
#include "cpu_loop-common.h"
#include "elf.h"
#include "hw/semihosting/common-semi.h"
void cpu_loop(CPURISCVState *env)
{
@ -91,6 +92,10 @@ void cpu_loop(CPURISCVState *env)
sigcode = TARGET_SEGV_MAPERR;
sigaddr = env->badaddr;
break;
case RISCV_EXCP_SEMIHOST:
env->gpr[xA0] = do_common_semihosting(cs);
env->pc += 4;
break;
case EXCP_DEBUG:
gdbstep:
signum = TARGET_SIGTRAP;

View File

@ -1,11 +1,11 @@
/*
* ARM Semihosting Console Support
* ARM Compatible Semihosting Console Support.
*
* Copyright (c) 2019 Linaro Ltd
*
* Currently ARM is unique in having support for semihosting support
* in linux-user. So for now we implement the common console API but
* just for arm linux-user.
* Currently ARM and RISC-V are unique in having support for
* semihosting support in linux-user. So for now we implement the
* common console API but just for arm and risc-v linux-user.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/

View File

@ -4207,10 +4207,10 @@ ERST
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
SRST
``-semihosting``
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only).
Note that this allows guest direct access to the host filesystem, so
should only be used with a trusted guest OS.
@ -4222,10 +4222,10 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
" semihosting configuration\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
SRST
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V
only).
Note that this allows guest direct access to the host filesystem, so
@ -4240,6 +4240,8 @@ SRST
open/read/write/seek/select. Tensilica baremetal libc for ISS and
linux platform "sim" use this interface.
On RISC-V this implements the standard semihosting API, version 0.2.
``target=native|gdb|auto``
Defines where the semihosting calls will be addressed, to QEMU
(``native``) or to GDB (``gdb``). The default is ``auto``, which

View File

@ -399,7 +399,7 @@ if ($chk_branch) {
my $num_patches = @patches;
for my $hash (@patches) {
my $FILE;
open($FILE, '-|', "git", "show", $hash) ||
open($FILE, '-|', "git", "show", "--patch-with-stat", $hash) ||
die "$P: git show $hash - $!\n";
while (<$FILE>) {
chomp;

View File

@ -775,7 +775,7 @@ void qemu_init_subsystems(void)
void qemu_cleanup(void)
{
gdbserver_cleanup();
gdb_exit(0);
/*
* cleaning up the migration object cancels any existing migration

View File

@ -47,6 +47,7 @@ stub_ss.add(files('vm-stop.c'))
stub_ss.add(files('win32-kbd-hook.c'))
stub_ss.add(files('cpu-synchronize-state.c'))
if have_block
stub_ss.add(files('yank.c'))
stub_ss.add(files('replay-tools.c'))
endif
if have_system

29
stubs/yank.c Normal file
View File

@ -0,0 +1,29 @@
#include "qemu/osdep.h"
#include "qemu/yank.h"
bool yank_register_instance(const YankInstance *instance, Error **errp)
{
return true;
}
void yank_unregister_instance(const YankInstance *instance)
{
}
void yank_register_function(const YankInstance *instance,
YankFn *func,
void *opaque)
{
}
void yank_unregister_function(const YankInstance *instance,
YankFn *func,
void *opaque)
{
}
void yank_generic_iochannel(void *opaque)
{
}

View File

@ -1068,14 +1068,6 @@ static inline void aarch64_sve_change_el(CPUARMState *env, int o,
static inline void aarch64_add_sve_properties(Object *obj) { }
#endif
#if !defined(CONFIG_TCG)
static inline target_ulong do_arm_semihosting(CPUARMState *env)
{
g_assert_not_reached();
}
#else
target_ulong do_arm_semihosting(CPUARMState *env);
#endif
void aarch64_sync_32_to_64(CPUARMState *env);
void aarch64_sync_64_to_32(CPUARMState *env);

View File

@ -195,22 +195,17 @@ static const struct TypeSize vec_lanes[] = {
{ "uint128", 128, 'q', 'u' },
{ "int128", 128, 'q', 's' },
/* 64 bit */
{ "ieee_double", 64, 'd', 'f' },
{ "uint64", 64, 'd', 'u' },
{ "int64", 64, 'd', 's' },
{ "ieee_double", 64, 'd', 'f' },
/* 32 bit */
{ "ieee_single", 32, 's', 'f' },
{ "uint32", 32, 's', 'u' },
{ "int32", 32, 's', 's' },
{ "ieee_single", 32, 's', 'f' },
/* 16 bit */
{ "ieee_half", 16, 'h', 'f' },
{ "uint16", 16, 'h', 'u' },
{ "int16", 16, 'h', 's' },
/*
* TODO: currently there is no reliable way of telling
* if the remote gdb actually understands ieee_half so
* we don't expose it in the target description for now.
* { "ieee_half", 16, 'h', 'f' },
*/
/* bytes */
{ "uint8", 8, 'b', 'u' },
{ "int8", 8, 'b', 's' },
@ -223,17 +218,16 @@ int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
GString *s = g_string_new(NULL);
DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
g_autoptr(GString) ts = g_string_new("");
int i, bits, reg_width = (cpu->sve_max_vq * 128);
int i, j, bits, reg_width = (cpu->sve_max_vq * 128);
info->num = 0;
g_string_printf(s, "<?xml version=\"1.0\"?>");
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.aarch64.sve\">");
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">");
/* First define types and totals in a whole VL */
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
int count = reg_width / vec_lanes[i].size;
g_string_printf(ts, "vq%d%c%c", count,
vec_lanes[i].sz, vec_lanes[i].suffix);
g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix);
g_string_append_printf(s,
"<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
ts->str, vec_lanes[i].gdb_type, count);
@ -243,39 +237,37 @@ int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
* signed and potentially float versions of each size from 128 to
* 8 bits.
*/
for (bits = 128; bits >= 8; bits /= 2) {
int count = reg_width / bits;
g_string_append_printf(s, "<union id=\"vq%dn\">", count);
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
if (vec_lanes[i].size == bits) {
g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",
vec_lanes[i].suffix,
count,
vec_lanes[i].sz, vec_lanes[i].suffix);
for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
const char suf[] = { 'q', 'd', 's', 'h', 'b' };
g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]);
for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
if (vec_lanes[j].size == bits) {
g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>",
vec_lanes[j].suffix,
vec_lanes[j].sz, vec_lanes[j].suffix);
}
}
g_string_append(s, "</union>");
}
/* And now the final union of unions */
g_string_append(s, "<union id=\"vq\">");
for (bits = 128; bits >= 8; bits /= 2) {
int count = reg_width / bits;
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
if (vec_lanes[i].size == bits) {
g_string_append_printf(s, "<field name=\"%c\" type=\"vq%dn\"/>",
vec_lanes[i].sz, count);
break;
}
}
g_string_append(s, "<union id=\"svev\">");
for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
const char suf[] = { 'q', 'd', 's', 'h', 'b' };
g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>",
suf[i], suf[i]);
}
g_string_append(s, "</union>");
/* Finally the sve prefix type */
g_string_append_printf(s,
"<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
reg_width / 8);
/* Then define each register in parts for each vq */
for (i = 0; i < 32; i++) {
g_string_append_printf(s,
"<reg name=\"z%d\" bitsize=\"%d\""
" regnum=\"%d\" group=\"vector\""
" type=\"vq\"/>",
" regnum=\"%d\" type=\"svev\"/>",
i, reg_width, base_reg++);
info->num++;
}
@ -287,31 +279,22 @@ int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
" regnum=\"%d\" group=\"float\""
" type=\"int\"/>", base_reg++);
info->num += 2;
/*
* Predicate registers aren't so big they are worth splitting up
* but we do need to define a type to hold the array of quad
* references.
*/
g_string_append_printf(s,
"<vector id=\"vqp\" type=\"uint16\" count=\"%d\"/>",
cpu->sve_max_vq);
for (i = 0; i < 16; i++) {
g_string_append_printf(s,
"<reg name=\"p%d\" bitsize=\"%d\""
" regnum=\"%d\" group=\"vector\""
" type=\"vqp\"/>",
" regnum=\"%d\" type=\"svep\"/>",
i, cpu->sve_max_vq * 16, base_reg++);
info->num++;
}
g_string_append_printf(s,
"<reg name=\"ffr\" bitsize=\"%d\""
" regnum=\"%d\" group=\"vector\""
" type=\"vqp\"/>",
" type=\"svep\"/>",
cpu->sve_max_vq * 16, base_reg++);
g_string_append_printf(s,
"<reg name=\"vg\" bitsize=\"64\""
" regnum=\"%d\" group=\"vector\""
" type=\"uint32\"/>",
" regnum=\"%d\" type=\"int\"/>",
base_reg++);
info->num += 2;
g_string_append_printf(s, "</feature>");

View File

@ -34,6 +34,7 @@
#ifdef CONFIG_TCG
#include "arm_ldst.h"
#include "exec/cpu_ldst.h"
#include "hw/semihosting/common-semi.h"
#endif
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
@ -276,7 +277,7 @@ static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
* while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
*/
int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
return gdb_get_reg32(buf, vq * 2);
return gdb_get_reg64(buf, vq * 2);
}
default:
/* gdbstub asked for something out our range */
@ -9875,13 +9876,13 @@ static void handle_semihosting(CPUState *cs)
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
env->xregs[0] = do_common_semihosting(cs);
env->pc += 4;
} else {
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
env->regs[0] = do_common_semihosting(cs);
env->regs[15] += env->thumb ? 2 : 4;
}
}

View File

@ -31,6 +31,7 @@
#ifdef CONFIG_TCG
#include "arm_ldst.h"
#include "exec/cpu_ldst.h"
#include "hw/semihosting/common-semi.h"
#endif
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
@ -2306,7 +2307,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
#ifdef CONFIG_TCG
env->regs[0] = do_common_semihosting(cs);
#else
g_assert_not_reached();
#endif
env->regs[15] += env->thumb ? 2 : 4;
return;
case EXCP_BKPT:

View File

@ -32,8 +32,6 @@ arm_ss.add(files(
))
arm_ss.add(zlib)
arm_ss.add(when: 'CONFIG_TCG', if_true: files('arm-semi.c'))
arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c'), if_false: files('kvm-stub.c'))
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(

View File

@ -195,7 +195,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
args = env->dregs[1];
switch (nr) {
case HOSTED_EXIT:
gdb_exit(env, env->dregs[0]);
gdb_exit(env->dregs[0]);
exit(env->dregs[0]);
case HOSTED_OPEN:
GET_ARG(0);

View File

@ -215,7 +215,7 @@ void do_nios2_semihosting(CPUNios2State *env)
args = env->regs[R_ARG1];
switch (nr) {
case HOSTED_EXIT:
gdb_exit(env, env->regs[R_ARG0]);
gdb_exit(env->regs[R_ARG0]);
exit(env->regs[R_ARG0]);
case HOSTED_OPEN:
GET_ARG(0);

View File

@ -542,6 +542,7 @@
#define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */
#define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */
#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */
#define RISCV_EXCP_SEMIHOST 0x10
#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14
#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15
#define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16

View File

@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "trace.h"
#include "hw/semihosting/common-semi.h"
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
{
@ -847,6 +848,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
target_ulong htval = 0;
target_ulong mtval2 = 0;
if (cause == RISCV_EXCP_SEMIHOST) {
if (env->priv >= PRV_S) {
env->gpr[xA0] = do_common_semihosting(cs);
env->pc += 4;
return;
}
cause = RISCV_EXCP_BREAKPOINT;
}
if (!async) {
/* set tval to badaddr for traps with address information */
switch (cause) {

View File

@ -29,7 +29,42 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
{
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
target_ulong ebreak_addr = ctx->base.pc_next;
target_ulong pre_addr = ebreak_addr - 4;
target_ulong post_addr = ebreak_addr + 4;
uint32_t pre = 0;
uint32_t ebreak = 0;
uint32_t post = 0;
/*
* The RISC-V semihosting spec specifies the following
* three-instruction sequence to flag a semihosting call:
*
* slli zero, zero, 0x1f 0x01f01013
* ebreak 0x00100073
* srai zero, zero, 0x7 0x40705013
*
* The two shift operations on the zero register are no-ops, used
* here to signify a semihosting exception, rather than a breakpoint.
*
* Uncompressed instructions are required so that the sequence is easy
* to validate.
*
* The three instructions are required to lie in the same page so
* that no exception will be raised when fetching them.
*/
if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) {
pre = opcode_at(&ctx->base, pre_addr);
ebreak = opcode_at(&ctx->base, ebreak_addr);
post = opcode_at(&ctx->base, post_addr);
}
if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
generate_exception(ctx, RISCV_EXCP_SEMIHOST);
} else {
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
}
exit_tb(ctx); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
return true;

View File

@ -64,6 +64,7 @@ typedef struct DisasContext {
uint16_t vlen;
uint16_t mlen;
bool vl_eq_vlmax;
CPUState *cs;
} DisasContext;
#ifdef TARGET_RISCV64
@ -747,6 +748,15 @@ static bool gen_shift(DisasContext *ctx, arg_r *a,
return true;
}
static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUState *cpu = ctx->cs;
CPURISCVState *env = cpu->env_ptr;
return cpu_ldl_code(env, pc);
}
/* Include insn module translation function */
#include "insn_trans/trans_rvi.c.inc"
#include "insn_trans/trans_rvm.c.inc"
@ -814,6 +824,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL);
ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul);
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
ctx->cs = cs;
}
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)

View File

@ -108,7 +108,6 @@ ifneq ($(HOST_ARCH),x86_64)
DOCKER_PARTIAL_IMAGES += debian-mips-cross debian-mipsel-cross debian-mips64el-cross
DOCKER_PARTIAL_IMAGES += debian-ppc64el-cross
DOCKER_PARTIAL_IMAGES += debian-s390x-cross
DOCKER_PARTIAL_IMAGES += debian-win32-cross debian-win64-cross
DOCKER_PARTIAL_IMAGES += fedora travis
endif

View File

@ -332,9 +332,9 @@ class Docker(object):
(uname, uid, uname))
tmp_df.write("\n")
tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s" % (checksum))
tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s\n" % (checksum))
for f, c in extra_files_cksum:
tmp_df.write("LABEL com.qemu.%s-checksum=%s" % (f, c))
tmp_df.write("LABEL com.qemu.%s-checksum=%s\n" % (f, c))
tmp_df.flush()

View File

@ -1,7 +1,7 @@
#
# Docker x86_64 target
#
# This docker target builds on the debian Stretch base image. Further
# This docker target builds on the Debian Buster base image. Further
# libraries which are not widely available are installed by hand.
#
FROM qemu/debian10
@ -14,7 +14,10 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
cscope \
genisoimage \
exuberant-ctags \
global \
libbz2-dev \
liblzo2-dev \
libgcrypt20-dev \

View File

@ -16,6 +16,7 @@ import subprocess
import shutil
import shlex
import os
from time import sleep
from tempfile import TemporaryDirectory
def get_args():
@ -27,10 +28,21 @@ def get_args():
required=True)
parser.add_argument("--test", help="GDB test script",
required=True)
parser.add_argument("--gdb", help="The gdb binary to use", default=None)
parser.add_argument("--gdb", help="The gdb binary to use",
default=None)
parser.add_argument("--output", help="A file to redirect output to")
return parser.parse_args()
def log(output, msg):
if output:
output.write(msg + "\n")
output.flush()
else:
print(msg)
if __name__ == '__main__':
args = get_args()
@ -42,17 +54,25 @@ if __name__ == '__main__':
if not args.gdb:
print("We need gdb to run the test")
exit(-1)
if args.output:
output = open(args.output, "w")
else:
output = None
socket_dir = TemporaryDirectory("qemu-gdbstub")
socket_name = os.path.join(socket_dir.name, "gdbstub.socket")
# Launch QEMU with binary
if "system" in args.qemu:
cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary)
cmd = "%s %s %s -gdb unix:path=%s,server" % (args.qemu,
args.qargs,
args.binary,
socket_name)
else:
cmd = "%s %s -g %s %s" % (args.qemu, args.qargs, socket_name,
args.binary)
log(output, "QEMU CMD: %s" % (cmd))
inferior = subprocess.Popen(shlex.split(cmd))
# Now launch gdb with our test and collect the result
@ -62,16 +82,15 @@ if __name__ == '__main__':
# disable prompts in case of crash
gdb_cmd += " -ex 'set confirm off'"
# connect to remote
if "system" in args.qemu:
gdb_cmd += " -ex 'target remote localhost:1234'"
else:
gdb_cmd += " -ex 'target remote %s'" % (socket_name)
gdb_cmd += " -ex 'target remote %s'" % (socket_name)
# finally the test script itself
gdb_cmd += " -x %s" % (args.test)
print("GDB CMD: %s" % (gdb_cmd))
result = subprocess.call(gdb_cmd, shell=True);
sleep(1)
log(output, "GDB CMD: %s" % (gdb_cmd))
result = subprocess.call(gdb_cmd, shell=True, stdout=output)
# A negative result is the result of an internal gdb failure like
# a crash. We force a return of 0 so we don't fail the test on

View File

@ -15,6 +15,7 @@ CRT_PATH=$(AARCH64_SYSTEM_SRC)
LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc

View File

@ -40,6 +40,17 @@ class TestBreakpoint(gdb.Breakpoint):
except gdb.error:
report(False, "checking zregs (out of range)")
# Check the aliased V registers are set and GDB has correctly
# created them for us having recognised and handled SVE.
try:
for i in range(0, 16):
val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
val_v = gdb.parse_and_eval("$v0.b.u[%d]" % i)
report(int(val_z) == int(val_v),
"v0.b.u[%d] == z0.b.u[%d]" % (i, i))
except gdb.error:
report(False, "checking vregs (out of range)")
def run_test():
"Run through the tests one by one"

View File

@ -197,6 +197,7 @@ __start:
bl main
/* pass return value to sys exit */
_exit:
mov x1, x0
ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */
stp x0, x1, [sp, #-16]!

View File

@ -19,6 +19,7 @@ CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
TESTS+=$(MULTIARCH_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
# building head blobs
.PRECIOUS: $(CRT_OBJS)

View File

@ -76,7 +76,7 @@ _start:
*/
call main
/* output any non-zero result in eax to isa-debug-exit device */
_exit: /* output any non-zero result in eax to isa-debug-exit device */
test %al, %al
jz 1f
out %ax, $0xf4

View File

@ -54,9 +54,16 @@ run-gdbstub-sha1: sha1
--bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \
"basic gdbstub support")
# Disable this for now -- it provokes a gdb internal-error on
# Ubuntu gdb 8.1.1-0ubuntu1.
# EXTRA_RUNS += run-gdbstub-sha1
EXTRA_RUNS += run-gdbstub-sha1
run-gdbstub-qxfer-auxv-read: sha1
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(HAVE_GDB_BIN) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
"basic gdbstub qXfer:auxv:read support")
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read
endif

View File

@ -0,0 +1,130 @@
from __future__ import print_function
#
# Test some of the softmmu debug features with the multiarch memory
# test. It is a port of the original vmlinux focused test case but
# using the "memory" test instead.
#
# This is launched via tests/guest-debug/run-test.py
#
import gdb
import sys
failcount = 0
def report(cond, msg):
"Report success/fail of test"
if cond:
print("PASS: %s" % (msg))
else:
print("FAIL: %s" % (msg))
global failcount
failcount += 1
def check_step():
"Step an instruction, check it moved."
start_pc = gdb.parse_and_eval('$pc')
gdb.execute("si")
end_pc = gdb.parse_and_eval('$pc')
return not (start_pc == end_pc)
#
# Currently it's hard to create a hbreak with the pure python API and
# manually matching PC to symbol address is a bit flaky thanks to
# function prologues. However internally QEMU's gdbstub treats them
# the same as normal breakpoints so it will do for now.
#
def check_break(sym_name):
"Setup breakpoint, continue and check we stopped."
sym, ok = gdb.lookup_symbol(sym_name)
bp = gdb.Breakpoint(sym_name, gdb.BP_BREAKPOINT)
gdb.execute("c")
# hopefully we came back
end_pc = gdb.parse_and_eval('$pc')
report(bp.hit_count == 1,
"break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count))
bp.delete()
def do_one_watch(sym, wtype, text):
wp = gdb.Breakpoint(sym, gdb.BP_WATCHPOINT, wtype)
gdb.execute("c")
report_str = "%s for %s" % (text, sym)
if wp.hit_count > 0:
report(True, report_str)
wp.delete()
else:
report(False, report_str)
def check_watches(sym_name):
"Watch a symbol for any access."
# Should hit for any read
do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")
# Again should hit for reads
do_one_watch(sym_name, gdb.WP_READ, "rwatch")
# Finally when it is written
do_one_watch(sym_name, gdb.WP_WRITE, "watch")
def run_test():
"Run through the tests one by one"
print("Checking we can step the first few instructions")
step_ok = 0
for i in range(3):
if check_step():
step_ok += 1
report(step_ok == 3, "single step in boot code")
# If we get here we have missed some of the other breakpoints.
print("Setup catch-all for _exit")
cbp = gdb.Breakpoint("_exit", gdb.BP_BREAKPOINT)
check_break("main")
check_watches("test_data[128]")
report(cbp.hit_count == 0, "didn't reach backstop")
#
# This runs as the script it sourced (via -x, via run-test.py)
#
try:
inferior = gdb.selected_inferior()
arch = inferior.architecture()
print("ATTACHED: %s" % arch.name())
except (gdb.error, AttributeError):
print("SKIPPING (not connected)", file=sys.stderr)
exit(0)
if gdb.parse_and_eval('$pc') == 0:
print("SKIP: PC not set")
exit(0)
try:
# These are not very useful in scripts
gdb.execute("set pagination off")
# Run the actual tests
run_test()
except (gdb.error):
print("GDB Exception: %s" % (sys.exc_info()[0]))
failcount += 1
pass
# Finally kill the inferior and exit gdb with a count of failures
gdb.execute("kill")
exit(failcount)

View File

@ -0,0 +1,57 @@
from __future__ import print_function
#
# Test auxiliary vector is loaded via gdbstub
#
# This is launched via tests/guest-debug/run-test.py
#
import gdb
import sys
failcount = 0
def report(cond, msg):
"Report success/fail of test"
if cond:
print ("PASS: %s" % (msg))
else:
print ("FAIL: %s" % (msg))
global failcount
failcount += 1
def run_test():
"Run through the tests one by one"
auxv = gdb.execute("info auxv", False, True)
report(isinstance(auxv, str), "Fetched auxv from inferior")
report(auxv.find("sha1"), "Found test binary name in auxv")
#
# This runs as the script it sourced (via -x, via run-test.py)
#
try:
inferior = gdb.selected_inferior()
arch = inferior.architecture()
print("ATTACHED: %s" % arch.name())
except (gdb.error, AttributeError):
print("SKIPPING (not connected)", file=sys.stderr)
exit(0)
if gdb.parse_and_eval('$pc') == 0:
print("SKIP: PC not set")
exit(0)
try:
# These are not very useful in scripts
gdb.execute("set pagination off")
gdb.execute("set confirm off")
# Run the actual tests
run_test()
except (gdb.error):
print ("GDB Exception: %s" % (sys.exc_info()[0]))
failcount += 1
pass
print("All tests complete: %d failures" % failcount)
exit(failcount)

View File

@ -7,8 +7,25 @@
# complications of building.
#
MULTIARCH_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/multiarch/system
MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch
MULTIARCH_SYSTEM_SRC=$(MULTIARCH_SRC)/system
VPATH+=$(MULTIARCH_SYSTEM_SRC)
MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c)
MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS))
ifneq ($(HAVE_GDB_BIN),)
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
run-gdbstub-memory: memory
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(HAVE_GDB_BIN) \
--qemu $(QEMU) \
--output $<.gdb.out \
--qargs \
"-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
--bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \
"softmmu gdbstub support")
MULTIARCH_RUNS += run-gdbstub-memory
endif

View File

@ -19,6 +19,7 @@ CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
TESTS+=$(MULTIARCH_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
# building head blobs
.PRECIOUS: $(CRT_OBJS)

View File

@ -124,7 +124,7 @@ _start:
/* don't worry about stack frame, assume everthing is garbage when we return */
call main
/* output any non-zero result in eax to isa-debug-exit device */
_exit: /* output any non-zero result in eax to isa-debug-exit device */
test %al, %al
jz 1f
out %ax, $0xf4

View File

@ -27,6 +27,8 @@
/***********************************************************/
/* real time host monotonic timer */
int64_t clock_start;
#ifdef _WIN32
int64_t clock_freq;
@ -41,6 +43,7 @@ static void __attribute__((constructor)) init_get_clock(void)
exit(1);
}
clock_freq = freq.QuadPart;
clock_start = get_clock();
}
#else
@ -55,5 +58,6 @@ static void __attribute__((constructor)) init_get_clock(void)
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
use_rt_clock = 1;
}
clock_start = get_clock();
}
#endif