2023-02-07 17:36:23 +08:00
|
|
|
/* Common native Linux code for the AArch64 scalable extensions: SVE and SME.
|
2018-05-31 21:36:48 +08:00
|
|
|
|
2024-01-12 23:30:44 +08:00
|
|
|
Copyright (C) 2018-2024 Free Software Foundation, Inc.
|
2018-05-31 21:36:48 +08:00
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
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 3 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/>. */
|
|
|
|
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <sys/uio.h>
|
Rename common to gdbsupport
This is the next patch in the ongoing series to move gdbsever to the
top level.
This patch just renames the "common" directory. The idea is to do
this move in two parts: first rename the directory (this patch), then
move the directory to the top. This approach makes the patches a bit
more tractable.
I chose the name "gdbsupport" for the directory. However, as this
patch was largely written by sed, we could pick a new name without too
much difficulty.
Tested by the buildbot.
gdb/ChangeLog
2019-07-09 Tom Tromey <tom@tromey.com>
* contrib/ari/gdb_ari.sh: Change common to gdbsupport.
* configure: Rebuild.
* configure.ac: Change common to gdbsupport.
* gdbsupport: Rename from common.
* acinclude.m4: Change common to gdbsupport.
* Makefile.in (CONFIG_SRC_SUBDIR, COMMON_SFILES)
(HFILES_NO_SRCDIR, stamp-version, ALLDEPFILES): Change common to
gdbsupport.
* aarch64-tdep.c, ada-lang.c, ada-lang.h, agent.c, alloc.c,
amd64-darwin-tdep.c, amd64-dicos-tdep.c, amd64-fbsd-nat.c,
amd64-fbsd-tdep.c, amd64-linux-nat.c, amd64-linux-tdep.c,
amd64-nbsd-tdep.c, amd64-obsd-tdep.c, amd64-sol2-tdep.c,
amd64-tdep.c, amd64-windows-tdep.c, arch-utils.c,
arch/aarch64-insn.c, arch/aarch64.c, arch/aarch64.h, arch/amd64.c,
arch/amd64.h, arch/arm-get-next-pcs.c, arch/arm-linux.c,
arch/arm.c, arch/i386.c, arch/i386.h, arch/ppc-linux-common.c,
arch/riscv.c, arch/riscv.h, arch/tic6x.c, arm-tdep.c, auto-load.c,
auxv.c, ax-gdb.c, ax-general.c, ax.h, breakpoint.c, breakpoint.h,
btrace.c, btrace.h, build-id.c, build-id.h, c-lang.h, charset.c,
charset.h, cli/cli-cmds.c, cli/cli-cmds.h, cli/cli-decode.c,
cli/cli-dump.c, cli/cli-option.h, cli/cli-script.c,
coff-pe-read.c, command.h, compile/compile-c-support.c,
compile/compile-c.h, compile/compile-cplus-symbols.c,
compile/compile-cplus-types.c, compile/compile-cplus.h,
compile/compile-loc2c.c, compile/compile.c, completer.c,
completer.h, contrib/ari/gdb_ari.sh, corefile.c, corelow.c,
cp-support.c, cp-support.h, cp-valprint.c, csky-tdep.c, ctf.c,
darwin-nat.c, debug.c, defs.h, disasm-selftests.c, disasm.c,
disasm.h, dtrace-probe.c, dwarf-index-cache.c,
dwarf-index-cache.h, dwarf-index-write.c, dwarf2-frame.c,
dwarf2expr.c, dwarf2loc.c, dwarf2read.c, event-loop.c,
event-top.c, exceptions.c, exec.c, extension.h, fbsd-nat.c,
features/aarch64-core.c, features/aarch64-fpu.c,
features/aarch64-pauth.c, features/aarch64-sve.c,
features/i386/32bit-avx.c, features/i386/32bit-avx512.c,
features/i386/32bit-core.c, features/i386/32bit-linux.c,
features/i386/32bit-mpx.c, features/i386/32bit-pkeys.c,
features/i386/32bit-segments.c, features/i386/32bit-sse.c,
features/i386/64bit-avx.c, features/i386/64bit-avx512.c,
features/i386/64bit-core.c, features/i386/64bit-linux.c,
features/i386/64bit-mpx.c, features/i386/64bit-pkeys.c,
features/i386/64bit-segments.c, features/i386/64bit-sse.c,
features/i386/x32-core.c, features/riscv/32bit-cpu.c,
features/riscv/32bit-csr.c, features/riscv/32bit-fpu.c,
features/riscv/64bit-cpu.c, features/riscv/64bit-csr.c,
features/riscv/64bit-fpu.c, features/tic6x-c6xp.c,
features/tic6x-core.c, features/tic6x-gp.c, filename-seen-cache.h,
findcmd.c, findvar.c, fork-child.c, gcore.c, gdb_bfd.c, gdb_bfd.h,
gdb_proc_service.h, gdb_regex.c, gdb_select.h, gdb_usleep.c,
gdbarch-selftests.c, gdbthread.h, gdbtypes.h, gnu-nat.c,
go32-nat.c, guile/guile.c, guile/scm-ports.c,
guile/scm-safe-call.c, guile/scm-type.c, i386-fbsd-nat.c,
i386-fbsd-tdep.c, i386-go32-tdep.c, i386-linux-nat.c,
i386-linux-tdep.c, i386-tdep.c, i387-tdep.c,
ia64-libunwind-tdep.c, ia64-linux-nat.c, inf-child.c,
inf-ptrace.c, infcall.c, infcall.h, infcmd.c, inferior-iter.h,
inferior.c, inferior.h, inflow.c, inflow.h, infrun.c, infrun.h,
inline-frame.c, language.h, linespec.c, linux-fork.c, linux-nat.c,
linux-tdep.c, linux-thread-db.c, location.c, machoread.c,
macrotab.h, main.c, maint.c, maint.h, memattr.c, memrange.h,
mi/mi-cmd-break.h, mi/mi-cmd-env.c, mi/mi-cmd-stack.c,
mi/mi-cmd-var.c, mi/mi-interp.c, mi/mi-main.c, mi/mi-parse.h,
minsyms.c, mips-linux-tdep.c, namespace.h,
nat/aarch64-linux-hw-point.c, nat/aarch64-linux-hw-point.h,
nat/aarch64-linux.c, nat/aarch64-sve-linux-ptrace.c,
nat/amd64-linux-siginfo.c, nat/fork-inferior.c,
nat/linux-btrace.c, nat/linux-btrace.h, nat/linux-namespaces.c,
nat/linux-nat.h, nat/linux-osdata.c, nat/linux-personality.c,
nat/linux-procfs.c, nat/linux-ptrace.c, nat/linux-ptrace.h,
nat/linux-waitpid.c, nat/mips-linux-watch.c,
nat/mips-linux-watch.h, nat/ppc-linux.c, nat/x86-dregs.c,
nat/x86-dregs.h, nat/x86-linux-dregs.c, nat/x86-linux.c,
nto-procfs.c, nto-tdep.c, objfile-flags.h, objfiles.c, objfiles.h,
obsd-nat.c, observable.h, osdata.c, p-valprint.c, parse.c,
parser-defs.h, ppc-linux-nat.c, printcmd.c, probe.c, proc-api.c,
procfs.c, producer.c, progspace.h, psymtab.h,
python/py-framefilter.c, python/py-inferior.c, python/py-ref.h,
python/py-type.c, python/python.c, record-btrace.c, record-full.c,
record.c, record.h, regcache-dump.c, regcache.c, regcache.h,
remote-fileio.c, remote-fileio.h, remote-sim.c, remote.c,
riscv-tdep.c, rs6000-aix-tdep.c, rust-exp.y, s12z-tdep.c,
selftest-arch.c, ser-base.c, ser-event.c, ser-pipe.c, ser-tcp.c,
ser-unix.c, skip.c, solib-aix.c, solib-target.c, solib.c,
source-cache.c, source.c, source.h, sparc-nat.c, spu-linux-nat.c,
stack.c, stap-probe.c, symfile-add-flags.h, symfile.c, symfile.h,
symtab.c, symtab.h, target-descriptions.c, target-descriptions.h,
target-memory.c, target.c, target.h, target/waitstatus.c,
target/waitstatus.h, thread-iter.h, thread.c, tilegx-tdep.c,
top.c, top.h, tracefile-tfile.c, tracefile.c, tracepoint.c,
tracepoint.h, tui/tui-io.c, ui-file.c, ui-out.h,
unittests/array-view-selftests.c,
unittests/child-path-selftests.c, unittests/cli-utils-selftests.c,
unittests/common-utils-selftests.c,
unittests/copy_bitwise-selftests.c, unittests/environ-selftests.c,
unittests/format_pieces-selftests.c,
unittests/function-view-selftests.c,
unittests/lookup_name_info-selftests.c,
unittests/memory-map-selftests.c, unittests/memrange-selftests.c,
unittests/mkdir-recursive-selftests.c,
unittests/observable-selftests.c,
unittests/offset-type-selftests.c, unittests/optional-selftests.c,
unittests/parse-connection-spec-selftests.c,
unittests/ptid-selftests.c, unittests/rsp-low-selftests.c,
unittests/scoped_fd-selftests.c,
unittests/scoped_mmap-selftests.c,
unittests/scoped_restore-selftests.c,
unittests/string_view-selftests.c, unittests/style-selftests.c,
unittests/tracepoint-selftests.c, unittests/unpack-selftests.c,
unittests/utils-selftests.c, unittests/xml-utils-selftests.c,
utils.c, utils.h, valarith.c, valops.c, valprint.c, value.c,
value.h, varobj.c, varobj.h, windows-nat.c, x86-linux-nat.c,
xml-support.c, xml-support.h, xml-tdesc.h, xstormy16-tdep.c,
xtensa-linux-nat.c, dwarf2read.h: Change common to gdbsupport.
gdb/gdbserver/ChangeLog
2019-07-09 Tom Tromey <tom@tromey.com>
* configure: Rebuild.
* configure.ac: Change common to gdbsupport.
* acinclude.m4: Change common to gdbsupport.
* Makefile.in (SFILES, OBS, GDBREPLAY_OBS, IPA_OBJS)
(version-generated.c, gdbsupport/%-ipa.o, gdbsupport/%.o): Change
common to gdbsupport.
* ax.c, event-loop.c, fork-child.c, gdb_proc_service.h,
gdbreplay.c, gdbthread.h, hostio-errno.c, hostio.c, i387-fp.c,
inferiors.c, inferiors.h, linux-aarch64-tdesc-selftest.c,
linux-amd64-ipa.c, linux-i386-ipa.c, linux-low.c,
linux-tic6x-low.c, linux-x86-low.c, linux-x86-tdesc-selftest.c,
linux-x86-tdesc.c, lynx-i386-low.c, lynx-low.c, mem-break.h,
nto-x86-low.c, regcache.c, regcache.h, remote-utils.c, server.c,
server.h, spu-low.c, symbol.c, target.h, tdesc.c, tdesc.h,
thread-db.c, tracepoint.c, win32-i386-low.c, win32-low.c: Change
common to gdbsupport.
2019-05-06 10:29:24 +08:00
|
|
|
#include "gdbsupport/common-defs.h"
|
2018-05-31 21:36:48 +08:00
|
|
|
#include "elf/external.h"
|
|
|
|
#include "elf/common.h"
|
2023-02-07 01:24:32 +08:00
|
|
|
#include "aarch64-scalable-linux-ptrace.h"
|
2018-05-31 21:36:48 +08:00
|
|
|
#include "arch/aarch64.h"
|
Rename common to gdbsupport
This is the next patch in the ongoing series to move gdbsever to the
top level.
This patch just renames the "common" directory. The idea is to do
this move in two parts: first rename the directory (this patch), then
move the directory to the top. This approach makes the patches a bit
more tractable.
I chose the name "gdbsupport" for the directory. However, as this
patch was largely written by sed, we could pick a new name without too
much difficulty.
Tested by the buildbot.
gdb/ChangeLog
2019-07-09 Tom Tromey <tom@tromey.com>
* contrib/ari/gdb_ari.sh: Change common to gdbsupport.
* configure: Rebuild.
* configure.ac: Change common to gdbsupport.
* gdbsupport: Rename from common.
* acinclude.m4: Change common to gdbsupport.
* Makefile.in (CONFIG_SRC_SUBDIR, COMMON_SFILES)
(HFILES_NO_SRCDIR, stamp-version, ALLDEPFILES): Change common to
gdbsupport.
* aarch64-tdep.c, ada-lang.c, ada-lang.h, agent.c, alloc.c,
amd64-darwin-tdep.c, amd64-dicos-tdep.c, amd64-fbsd-nat.c,
amd64-fbsd-tdep.c, amd64-linux-nat.c, amd64-linux-tdep.c,
amd64-nbsd-tdep.c, amd64-obsd-tdep.c, amd64-sol2-tdep.c,
amd64-tdep.c, amd64-windows-tdep.c, arch-utils.c,
arch/aarch64-insn.c, arch/aarch64.c, arch/aarch64.h, arch/amd64.c,
arch/amd64.h, arch/arm-get-next-pcs.c, arch/arm-linux.c,
arch/arm.c, arch/i386.c, arch/i386.h, arch/ppc-linux-common.c,
arch/riscv.c, arch/riscv.h, arch/tic6x.c, arm-tdep.c, auto-load.c,
auxv.c, ax-gdb.c, ax-general.c, ax.h, breakpoint.c, breakpoint.h,
btrace.c, btrace.h, build-id.c, build-id.h, c-lang.h, charset.c,
charset.h, cli/cli-cmds.c, cli/cli-cmds.h, cli/cli-decode.c,
cli/cli-dump.c, cli/cli-option.h, cli/cli-script.c,
coff-pe-read.c, command.h, compile/compile-c-support.c,
compile/compile-c.h, compile/compile-cplus-symbols.c,
compile/compile-cplus-types.c, compile/compile-cplus.h,
compile/compile-loc2c.c, compile/compile.c, completer.c,
completer.h, contrib/ari/gdb_ari.sh, corefile.c, corelow.c,
cp-support.c, cp-support.h, cp-valprint.c, csky-tdep.c, ctf.c,
darwin-nat.c, debug.c, defs.h, disasm-selftests.c, disasm.c,
disasm.h, dtrace-probe.c, dwarf-index-cache.c,
dwarf-index-cache.h, dwarf-index-write.c, dwarf2-frame.c,
dwarf2expr.c, dwarf2loc.c, dwarf2read.c, event-loop.c,
event-top.c, exceptions.c, exec.c, extension.h, fbsd-nat.c,
features/aarch64-core.c, features/aarch64-fpu.c,
features/aarch64-pauth.c, features/aarch64-sve.c,
features/i386/32bit-avx.c, features/i386/32bit-avx512.c,
features/i386/32bit-core.c, features/i386/32bit-linux.c,
features/i386/32bit-mpx.c, features/i386/32bit-pkeys.c,
features/i386/32bit-segments.c, features/i386/32bit-sse.c,
features/i386/64bit-avx.c, features/i386/64bit-avx512.c,
features/i386/64bit-core.c, features/i386/64bit-linux.c,
features/i386/64bit-mpx.c, features/i386/64bit-pkeys.c,
features/i386/64bit-segments.c, features/i386/64bit-sse.c,
features/i386/x32-core.c, features/riscv/32bit-cpu.c,
features/riscv/32bit-csr.c, features/riscv/32bit-fpu.c,
features/riscv/64bit-cpu.c, features/riscv/64bit-csr.c,
features/riscv/64bit-fpu.c, features/tic6x-c6xp.c,
features/tic6x-core.c, features/tic6x-gp.c, filename-seen-cache.h,
findcmd.c, findvar.c, fork-child.c, gcore.c, gdb_bfd.c, gdb_bfd.h,
gdb_proc_service.h, gdb_regex.c, gdb_select.h, gdb_usleep.c,
gdbarch-selftests.c, gdbthread.h, gdbtypes.h, gnu-nat.c,
go32-nat.c, guile/guile.c, guile/scm-ports.c,
guile/scm-safe-call.c, guile/scm-type.c, i386-fbsd-nat.c,
i386-fbsd-tdep.c, i386-go32-tdep.c, i386-linux-nat.c,
i386-linux-tdep.c, i386-tdep.c, i387-tdep.c,
ia64-libunwind-tdep.c, ia64-linux-nat.c, inf-child.c,
inf-ptrace.c, infcall.c, infcall.h, infcmd.c, inferior-iter.h,
inferior.c, inferior.h, inflow.c, inflow.h, infrun.c, infrun.h,
inline-frame.c, language.h, linespec.c, linux-fork.c, linux-nat.c,
linux-tdep.c, linux-thread-db.c, location.c, machoread.c,
macrotab.h, main.c, maint.c, maint.h, memattr.c, memrange.h,
mi/mi-cmd-break.h, mi/mi-cmd-env.c, mi/mi-cmd-stack.c,
mi/mi-cmd-var.c, mi/mi-interp.c, mi/mi-main.c, mi/mi-parse.h,
minsyms.c, mips-linux-tdep.c, namespace.h,
nat/aarch64-linux-hw-point.c, nat/aarch64-linux-hw-point.h,
nat/aarch64-linux.c, nat/aarch64-sve-linux-ptrace.c,
nat/amd64-linux-siginfo.c, nat/fork-inferior.c,
nat/linux-btrace.c, nat/linux-btrace.h, nat/linux-namespaces.c,
nat/linux-nat.h, nat/linux-osdata.c, nat/linux-personality.c,
nat/linux-procfs.c, nat/linux-ptrace.c, nat/linux-ptrace.h,
nat/linux-waitpid.c, nat/mips-linux-watch.c,
nat/mips-linux-watch.h, nat/ppc-linux.c, nat/x86-dregs.c,
nat/x86-dregs.h, nat/x86-linux-dregs.c, nat/x86-linux.c,
nto-procfs.c, nto-tdep.c, objfile-flags.h, objfiles.c, objfiles.h,
obsd-nat.c, observable.h, osdata.c, p-valprint.c, parse.c,
parser-defs.h, ppc-linux-nat.c, printcmd.c, probe.c, proc-api.c,
procfs.c, producer.c, progspace.h, psymtab.h,
python/py-framefilter.c, python/py-inferior.c, python/py-ref.h,
python/py-type.c, python/python.c, record-btrace.c, record-full.c,
record.c, record.h, regcache-dump.c, regcache.c, regcache.h,
remote-fileio.c, remote-fileio.h, remote-sim.c, remote.c,
riscv-tdep.c, rs6000-aix-tdep.c, rust-exp.y, s12z-tdep.c,
selftest-arch.c, ser-base.c, ser-event.c, ser-pipe.c, ser-tcp.c,
ser-unix.c, skip.c, solib-aix.c, solib-target.c, solib.c,
source-cache.c, source.c, source.h, sparc-nat.c, spu-linux-nat.c,
stack.c, stap-probe.c, symfile-add-flags.h, symfile.c, symfile.h,
symtab.c, symtab.h, target-descriptions.c, target-descriptions.h,
target-memory.c, target.c, target.h, target/waitstatus.c,
target/waitstatus.h, thread-iter.h, thread.c, tilegx-tdep.c,
top.c, top.h, tracefile-tfile.c, tracefile.c, tracepoint.c,
tracepoint.h, tui/tui-io.c, ui-file.c, ui-out.h,
unittests/array-view-selftests.c,
unittests/child-path-selftests.c, unittests/cli-utils-selftests.c,
unittests/common-utils-selftests.c,
unittests/copy_bitwise-selftests.c, unittests/environ-selftests.c,
unittests/format_pieces-selftests.c,
unittests/function-view-selftests.c,
unittests/lookup_name_info-selftests.c,
unittests/memory-map-selftests.c, unittests/memrange-selftests.c,
unittests/mkdir-recursive-selftests.c,
unittests/observable-selftests.c,
unittests/offset-type-selftests.c, unittests/optional-selftests.c,
unittests/parse-connection-spec-selftests.c,
unittests/ptid-selftests.c, unittests/rsp-low-selftests.c,
unittests/scoped_fd-selftests.c,
unittests/scoped_mmap-selftests.c,
unittests/scoped_restore-selftests.c,
unittests/string_view-selftests.c, unittests/style-selftests.c,
unittests/tracepoint-selftests.c, unittests/unpack-selftests.c,
unittests/utils-selftests.c, unittests/xml-utils-selftests.c,
utils.c, utils.h, valarith.c, valops.c, valprint.c, value.c,
value.h, varobj.c, varobj.h, windows-nat.c, x86-linux-nat.c,
xml-support.c, xml-support.h, xml-tdesc.h, xstormy16-tdep.c,
xtensa-linux-nat.c, dwarf2read.h: Change common to gdbsupport.
gdb/gdbserver/ChangeLog
2019-07-09 Tom Tromey <tom@tromey.com>
* configure: Rebuild.
* configure.ac: Change common to gdbsupport.
* acinclude.m4: Change common to gdbsupport.
* Makefile.in (SFILES, OBS, GDBREPLAY_OBS, IPA_OBJS)
(version-generated.c, gdbsupport/%-ipa.o, gdbsupport/%.o): Change
common to gdbsupport.
* ax.c, event-loop.c, fork-child.c, gdb_proc_service.h,
gdbreplay.c, gdbthread.h, hostio-errno.c, hostio.c, i387-fp.c,
inferiors.c, inferiors.h, linux-aarch64-tdesc-selftest.c,
linux-amd64-ipa.c, linux-i386-ipa.c, linux-low.c,
linux-tic6x-low.c, linux-x86-low.c, linux-x86-tdesc-selftest.c,
linux-x86-tdesc.c, lynx-i386-low.c, lynx-low.c, mem-break.h,
nto-x86-low.c, regcache.c, regcache.h, remote-utils.c, server.c,
server.h, spu-low.c, symbol.c, target.h, tdesc.c, tdesc.h,
thread-db.c, tracepoint.c, win32-i386-low.c, win32-low.c: Change
common to gdbsupport.
2019-05-06 10:29:24 +08:00
|
|
|
#include "gdbsupport/common-regcache.h"
|
|
|
|
#include "gdbsupport/byte-vector.h"
|
2020-03-19 00:06:05 +08:00
|
|
|
#include <endian.h>
|
2023-02-07 17:36:23 +08:00
|
|
|
#include "arch/aarch64-scalable-linux.h"
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_has_sve_state (int tid)
|
|
|
|
{
|
|
|
|
struct user_sve_header header;
|
|
|
|
|
|
|
|
if (!read_sve_header (tid, header))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ((header.flags & SVE_PT_REGS_SVE) == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sizeof (header) == header.size)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_has_ssve_state (int tid)
|
|
|
|
{
|
|
|
|
struct user_sve_header header;
|
|
|
|
|
|
|
|
if (!read_ssve_header (tid, header))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ((header.flags & SVE_PT_REGS_SVE) == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sizeof (header) == header.size)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_has_za_state (int tid)
|
|
|
|
{
|
|
|
|
struct user_za_header header;
|
|
|
|
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sizeof (header) == header.size)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
read_sve_header (int tid, struct user_sve_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* SVE is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
write_sve_header (int tid, const struct user_sve_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = (void *) &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* SVE is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
read_ssve_header (int tid, struct user_sve_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SSVE, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* SSVE is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
write_ssve_header (int tid, const struct user_sve_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = (void *) &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SSVE, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* SSVE is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
read_za_header (int tid, struct user_za_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* ZA is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
write_za_header (int tid, const struct user_za_header &header)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = (void *) &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* ZA is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given VL, the streaming vector length for SME, return true if it is valid
|
|
|
|
and false otherwise. */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
aarch64_sme_vl_valid (size_t vl)
|
|
|
|
{
|
|
|
|
return (vl == 16 || vl == 32 || vl == 64 || vl == 128 || vl == 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given VL, the vector length for SVE, return true if it is valid and false
|
|
|
|
otherwise. SVE_state is true when the check is for the SVE register set.
|
|
|
|
Otherwise the check is for the SSVE register set. */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
aarch64_sve_vl_valid (const bool sve_state, size_t vl)
|
|
|
|
{
|
|
|
|
if (sve_state)
|
|
|
|
return sve_vl_valid (vl);
|
|
|
|
|
|
|
|
/* We have an active SSVE state, where the valid vector length values are
|
|
|
|
more restrictive. */
|
|
|
|
return aarch64_sme_vl_valid (vl);
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2018-05-31 21:36:48 +08:00
|
|
|
|
2018-06-01 23:37:45 +08:00
|
|
|
uint64_t
|
2018-05-31 21:36:48 +08:00
|
|
|
aarch64_sve_get_vq (int tid)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
struct user_sve_header header;
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
/* Figure out which register set to use for the request. The vector length
|
|
|
|
for SVE can be different from the vector length for SSVE. */
|
|
|
|
bool has_sve_state = !aarch64_has_ssve_state (tid);
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE,
|
|
|
|
&iovec) < 0)
|
2018-05-31 21:36:48 +08:00
|
|
|
{
|
|
|
|
/* SVE is not supported. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
/* Ptrace gives the vector length in bytes. Convert it to VQ, the number of
|
|
|
|
128bit chunks in a Z register. We use VQ because 128 bits is the minimum
|
|
|
|
a Z register can increase in size. */
|
2018-06-15 19:21:31 +08:00
|
|
|
uint64_t vq = sve_vq_from_vl (header.vl);
|
2018-05-31 21:36:48 +08:00
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
if (!aarch64_sve_vl_valid (has_sve_state, header.vl))
|
2018-05-31 21:36:48 +08:00
|
|
|
{
|
|
|
|
warning (_("Invalid SVE state from kernel; SVE disabled."));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vq;
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2019-04-15 19:31:21 +08:00
|
|
|
bool
|
|
|
|
aarch64_sve_set_vq (int tid, uint64_t vq)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
struct user_sve_header header;
|
|
|
|
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
/* Figure out which register set to use for the request. The vector length
|
|
|
|
for SVE can be different from the vector length for SSVE. */
|
|
|
|
bool has_sve_state = !aarch64_has_ssve_state (tid);
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE,
|
|
|
|
&iovec) < 0)
|
2019-04-15 19:31:21 +08:00
|
|
|
{
|
2023-02-07 17:36:23 +08:00
|
|
|
/* SVE/SSVE is not supported. */
|
2019-04-15 19:31:21 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
header.vl = sve_vl_from_vq (vq);
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE,
|
|
|
|
&iovec) < 0)
|
2019-04-15 19:31:21 +08:00
|
|
|
{
|
|
|
|
/* Vector length change failed. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2019-04-15 19:31:21 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
|
|
|
|
{
|
[AArch64] When unavailable, fetch VG from ptrace.
I was doing some SVE tests on system QEMU and noticed quite a few failures
related to inferior function calls. Any attempt to do an inferior function
call would result in the following:
Unable to set VG register.: Success.
This happens because, after an inferior function call, GDB attempts to restore
the regcache state and updates the SVE register in order. Since the Z registers
show up before the VG register, VG is still INVALID by the time the first Z
register is being updated. So when executing the following code in
aarch64_sve_set_vq:
if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
return false;
By returning false, we signal something is wrong, then we get to this:
/* First store vector length to the thread. This is done first to ensure the
ptrace buffers read from the kernel are the correct size. */
if (!aarch64_sve_set_vq (tid, regcache))
perror_with_name (_("Unable to set VG register."));
Ideally we'd always have a valid VG before attempting to set the Z registers,
but in this case the ordering of registers doesn't make that possible.
I considered reordering the registers to put VG before the Z registers, like
the DWARF numbering, but that would break backwards compatibility with
existing implementations. Also, the Z register numbering is pinned to the V
registers, and adding VG before Z would create a gap for non-SVE targets,
since we wouldn't be able to undefine VG for non-SVE targets.
As a compromise, it seems we can safely fetch the VG register value from
ptrace. The value in the kernel is likely the updated value anyway.
This patch fixed all the failures i saw in the testsuite and caused no further
regressions.
gdb/ChangeLog:
2020-03-19 Luis Machado <luis.machado@linaro.org>
* nat/aarch64-sve-linux-ptrace.c (aarch64_sve_set_vq): If vg is not
valid, fetch vg value from ptrace.
2020-03-17 01:09:25 +08:00
|
|
|
uint64_t reg_vg = 0;
|
|
|
|
|
|
|
|
/* The VG register may not be valid if we've not collected any value yet.
|
|
|
|
This can happen, for example, if we're restoring the regcache after an
|
|
|
|
inferior function call, and the VG register comes after the Z
|
|
|
|
registers. */
|
2019-04-15 19:31:21 +08:00
|
|
|
if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
|
2021-05-28 03:01:28 +08:00
|
|
|
{
|
|
|
|
/* If vg is not available yet, fetch it from ptrace. The VG value from
|
|
|
|
ptrace is likely the correct one. */
|
|
|
|
uint64_t vq = aarch64_sve_get_vq (tid);
|
2019-04-15 19:31:21 +08:00
|
|
|
|
2021-05-28 03:01:28 +08:00
|
|
|
/* If something went wrong, just bail out. */
|
|
|
|
if (vq == 0)
|
|
|
|
return false;
|
[AArch64] When unavailable, fetch VG from ptrace.
I was doing some SVE tests on system QEMU and noticed quite a few failures
related to inferior function calls. Any attempt to do an inferior function
call would result in the following:
Unable to set VG register.: Success.
This happens because, after an inferior function call, GDB attempts to restore
the regcache state and updates the SVE register in order. Since the Z registers
show up before the VG register, VG is still INVALID by the time the first Z
register is being updated. So when executing the following code in
aarch64_sve_set_vq:
if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
return false;
By returning false, we signal something is wrong, then we get to this:
/* First store vector length to the thread. This is done first to ensure the
ptrace buffers read from the kernel are the correct size. */
if (!aarch64_sve_set_vq (tid, regcache))
perror_with_name (_("Unable to set VG register."));
Ideally we'd always have a valid VG before attempting to set the Z registers,
but in this case the ordering of registers doesn't make that possible.
I considered reordering the registers to put VG before the Z registers, like
the DWARF numbering, but that would break backwards compatibility with
existing implementations. Also, the Z register numbering is pinned to the V
registers, and adding VG before Z would create a gap for non-SVE targets,
since we wouldn't be able to undefine VG for non-SVE targets.
As a compromise, it seems we can safely fetch the VG register value from
ptrace. The value in the kernel is likely the updated value anyway.
This patch fixed all the failures i saw in the testsuite and caused no further
regressions.
gdb/ChangeLog:
2020-03-19 Luis Machado <luis.machado@linaro.org>
* nat/aarch64-sve-linux-ptrace.c (aarch64_sve_set_vq): If vg is not
valid, fetch vg value from ptrace.
2020-03-17 01:09:25 +08:00
|
|
|
|
2021-05-28 03:01:28 +08:00
|
|
|
reg_vg = sve_vg_from_vq (vq);
|
|
|
|
}
|
[AArch64] When unavailable, fetch VG from ptrace.
I was doing some SVE tests on system QEMU and noticed quite a few failures
related to inferior function calls. Any attempt to do an inferior function
call would result in the following:
Unable to set VG register.: Success.
This happens because, after an inferior function call, GDB attempts to restore
the regcache state and updates the SVE register in order. Since the Z registers
show up before the VG register, VG is still INVALID by the time the first Z
register is being updated. So when executing the following code in
aarch64_sve_set_vq:
if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
return false;
By returning false, we signal something is wrong, then we get to this:
/* First store vector length to the thread. This is done first to ensure the
ptrace buffers read from the kernel are the correct size. */
if (!aarch64_sve_set_vq (tid, regcache))
perror_with_name (_("Unable to set VG register."));
Ideally we'd always have a valid VG before attempting to set the Z registers,
but in this case the ordering of registers doesn't make that possible.
I considered reordering the registers to put VG before the Z registers, like
the DWARF numbering, but that would break backwards compatibility with
existing implementations. Also, the Z register numbering is pinned to the V
registers, and adding VG before Z would create a gap for non-SVE targets,
since we wouldn't be able to undefine VG for non-SVE targets.
As a compromise, it seems we can safely fetch the VG register value from
ptrace. The value in the kernel is likely the updated value anyway.
This patch fixed all the failures i saw in the testsuite and caused no further
regressions.
gdb/ChangeLog:
2020-03-19 Luis Machado <luis.machado@linaro.org>
* nat/aarch64-sve-linux-ptrace.c (aarch64_sve_set_vq): If vg is not
valid, fetch vg value from ptrace.
2020-03-17 01:09:25 +08:00
|
|
|
else
|
|
|
|
reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, ®_vg);
|
2019-04-15 19:31:21 +08:00
|
|
|
|
|
|
|
return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
|
|
|
|
}
|
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2019-04-15 19:31:21 +08:00
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
uint64_t
|
|
|
|
aarch64_za_get_svq (int tid)
|
|
|
|
{
|
|
|
|
struct user_za_header header;
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uint64_t vq = sve_vq_from_vl (header.vl);
|
|
|
|
|
|
|
|
if (!aarch64_sve_vl_valid (false, header.vl))
|
|
|
|
{
|
|
|
|
warning (_("Invalid ZA state from kernel; ZA disabled."));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_za_set_svq (int tid, uint64_t vq)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
|
|
|
|
/* Read the NT_ARM_ZA header. */
|
|
|
|
struct user_za_header header;
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
{
|
|
|
|
/* ZA is not supported. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the size is the correct one already, don't update it. If we do
|
|
|
|
update the streaming vector length, we will invalidate the register
|
|
|
|
state for ZA, and we do not want that. */
|
|
|
|
if (header.vl == sve_vl_from_vq (vq))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* The streaming vector length is about to get updated. Set the new value
|
|
|
|
in the NT_ARM_ZA header and adjust the size as well. */
|
|
|
|
|
|
|
|
header.vl = sve_vl_from_vq (vq);
|
|
|
|
header.size = sizeof (struct user_za_header);
|
|
|
|
|
|
|
|
/* Update the NT_ARM_ZA register set with the new streaming vector
|
|
|
|
length. */
|
|
|
|
iovec.iov_len = sizeof (header);
|
|
|
|
iovec.iov_base = &header;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
{
|
|
|
|
/* Streaming vector length change failed. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* At this point we have successfully adjusted the streaming vector length
|
|
|
|
for the NT_ARM_ZA register set, and it should have no payload
|
|
|
|
(no ZA state). */
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
aarch64_za_set_svq (int tid, const struct reg_buffer_common *reg_buf,
|
|
|
|
int svg_regnum)
|
|
|
|
{
|
|
|
|
uint64_t reg_svg = 0;
|
|
|
|
|
|
|
|
/* The svg register may not be valid if we've not collected any value yet.
|
|
|
|
This can happen, for example, if we're restoring the regcache after an
|
|
|
|
inferior function call, and the svg register comes after the Z
|
|
|
|
registers. */
|
|
|
|
if (reg_buf->get_register_status (svg_regnum) != REG_VALID)
|
|
|
|
{
|
|
|
|
/* If svg is not available yet, fetch it from ptrace. The svg value from
|
|
|
|
ptrace is likely the correct one. */
|
|
|
|
uint64_t svq = aarch64_za_get_svq (tid);
|
|
|
|
|
|
|
|
/* If something went wrong, just bail out. */
|
|
|
|
if (svq == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
reg_svg = sve_vg_from_vq (svq);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
reg_buf->raw_collect (svg_regnum, ®_svg);
|
|
|
|
|
|
|
|
return aarch64_za_set_svq (tid, sve_vq_from_vg (reg_svg));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
gdb::byte_vector
|
|
|
|
aarch64_fetch_sve_regset (int tid)
|
2018-06-15 19:21:31 +08:00
|
|
|
{
|
|
|
|
uint64_t vq = aarch64_sve_get_vq (tid);
|
|
|
|
|
|
|
|
if (vq == 0)
|
2023-02-07 17:36:23 +08:00
|
|
|
perror_with_name (_("Unable to fetch SVE/SSVE vector length"));
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
/* A ptrace call with NT_ARM_SVE will return a header followed by either a
|
|
|
|
dump of all the SVE and FP registers, or an fpsimd structure (identical to
|
|
|
|
the one returned by NT_FPREGSET) if the kernel has not yet executed any
|
|
|
|
SVE code. Make sure we allocate enough space for a full SVE dump. */
|
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
gdb::byte_vector sve_state (SVE_PT_SIZE (vq, SVE_PT_REGS_SVE), 0);
|
|
|
|
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_base = sve_state.data ();
|
|
|
|
iovec.iov_len = sve_state.size ();
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
bool has_sve_state = !aarch64_has_ssve_state (tid);
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE,
|
|
|
|
&iovec) < 0)
|
|
|
|
perror_with_name (_("Unable to fetch SVE/SSVE registers"));
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
return sve_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_store_sve_regset (int tid, const gdb::byte_vector &sve_state)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
/* We need to cast from (const void *) here. */
|
|
|
|
iovec.iov_base = (void *) sve_state.data ();
|
|
|
|
iovec.iov_len = sve_state.size ();
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
bool has_sve_state = !aarch64_has_ssve_state (tid);
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, has_sve_state? NT_ARM_SVE : NT_ARM_SSVE,
|
|
|
|
&iovec) < 0)
|
|
|
|
perror_with_name (_("Unable to store SVE/SSVE registers"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
gdb::byte_vector
|
|
|
|
aarch64_fetch_za_regset (int tid)
|
|
|
|
{
|
|
|
|
struct user_za_header header;
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
error (_("Failed to read NT_ARM_ZA header."));
|
|
|
|
|
|
|
|
if (!aarch64_sme_vl_valid (header.vl))
|
|
|
|
error (_("Found invalid vector length for NT_ARM_ZA."));
|
|
|
|
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_len = header.size;
|
|
|
|
gdb::byte_vector za_state (header.size);
|
|
|
|
iovec.iov_base = za_state.data ();
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
perror_with_name (_("Failed to fetch NT_ARM_ZA register set."));
|
|
|
|
|
|
|
|
return za_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_store_za_regset (int tid, const gdb::byte_vector &za_state)
|
|
|
|
{
|
|
|
|
struct iovec iovec;
|
|
|
|
/* We need to cast from (const void *) here. */
|
|
|
|
iovec.iov_base = (void *) za_state.data ();
|
|
|
|
iovec.iov_len = za_state.size ();
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
perror_with_name (_("Failed to write to the NT_ARM_ZA register set."));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_initialize_za_regset (int tid)
|
|
|
|
{
|
|
|
|
/* First fetch the NT_ARM_ZA header so we can fetch the streaming vector
|
|
|
|
length. */
|
|
|
|
struct user_za_header header;
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
error (_("Failed to read NT_ARM_ZA header."));
|
|
|
|
|
|
|
|
/* The vector should be default-initialized to zero, and we should account
|
|
|
|
for the payload as well. */
|
|
|
|
std::vector<gdb_byte> za_new_state (ZA_PT_SIZE (sve_vq_from_vl (header.vl)));
|
|
|
|
|
|
|
|
/* Adjust the header size since we are adding the initialized ZA
|
|
|
|
payload. */
|
|
|
|
header.size = ZA_PT_SIZE (sve_vq_from_vl (header.vl));
|
|
|
|
|
|
|
|
/* Overlay the modified header onto the new ZA state. */
|
|
|
|
const gdb_byte *base = (gdb_byte *) &header;
|
|
|
|
memcpy (za_new_state.data (), base, sizeof (user_za_header));
|
|
|
|
|
|
|
|
/* Set the ptrace request up and update the NT_ARM_ZA register set. */
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_len = za_new_state.size ();
|
|
|
|
iovec.iov_base = za_new_state.data ();
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
|
|
|
|
perror_with_name (_("Failed to initialize the NT_ARM_ZA register set."));
|
|
|
|
|
2023-04-05 00:20:46 +08:00
|
|
|
if (supports_zt_registers (tid))
|
|
|
|
{
|
|
|
|
/* If this target supports SME2, upon initializing ZA, we also need to
|
|
|
|
initialize the ZT registers with 0 values. Do so now. */
|
|
|
|
gdb::byte_vector zt_new_state (AARCH64_SME2_ZT0_SIZE, 0);
|
|
|
|
aarch64_store_zt_regset (tid, zt_new_state);
|
|
|
|
}
|
|
|
|
|
2023-02-07 17:36:23 +08:00
|
|
|
/* The NT_ARM_ZA register set should now contain a zero-initialized ZA
|
|
|
|
payload. */
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
|
2023-04-05 00:20:46 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
gdb::byte_vector
|
|
|
|
aarch64_fetch_zt_regset (int tid)
|
|
|
|
{
|
|
|
|
/* Read NT_ARM_ZT. This register set is only available if
|
|
|
|
the ZA bit is non-zero. */
|
|
|
|
gdb::byte_vector zt_state (AARCH64_SME2_ZT0_SIZE);
|
|
|
|
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_len = AARCH64_SME2_ZT0_SIZE;
|
|
|
|
iovec.iov_base = zt_state.data ();
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
|
|
|
|
perror_with_name (_("Failed to fetch NT_ARM_ZT register set."));
|
|
|
|
|
|
|
|
return zt_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_store_zt_regset (int tid, const gdb::byte_vector &zt_state)
|
|
|
|
{
|
|
|
|
gdb_assert (zt_state.size () == AARCH64_SME2_ZT0_SIZE
|
|
|
|
|| zt_state.size () == 0);
|
|
|
|
|
|
|
|
/* We need to be mindful of writing data to NT_ARM_ZT. If the ZA bit
|
|
|
|
is 0 and we write something to ZT, it will flip the ZA bit.
|
|
|
|
|
|
|
|
Right now this is taken care of by callers of this function. */
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_len = zt_state.size ();
|
|
|
|
iovec.iov_base = (void *) zt_state.data ();
|
|
|
|
|
|
|
|
/* Write the contents of ZT_STATE to the NT_ARM_ZT register set. */
|
|
|
|
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
|
|
|
|
perror_with_name (_("Failed to write to the NT_ARM_ZT register set."));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
bool
|
|
|
|
supports_zt_registers (int tid)
|
|
|
|
{
|
|
|
|
gdb_byte zt_state[AARCH64_SME2_ZT0_SIZE];
|
|
|
|
|
|
|
|
struct iovec iovec;
|
|
|
|
iovec.iov_len = AARCH64_SME2_ZT0_SIZE;
|
|
|
|
iovec.iov_base = (void *) zt_state;
|
|
|
|
|
|
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:06:05 +08:00
|
|
|
/* If we are running in BE mode, byteswap the contents
|
|
|
|
of SRC to DST for SIZE bytes. Other, just copy the contents
|
|
|
|
from SRC to DST. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size)
|
|
|
|
{
|
|
|
|
gdb_assert (src != nullptr && dst != nullptr);
|
|
|
|
gdb_assert (size > 1);
|
|
|
|
|
|
|
|
#if (__BYTE_ORDER == __BIG_ENDIAN)
|
|
|
|
for (int i = 0; i < size - 1; i++)
|
|
|
|
dst[i] = src[size - i];
|
|
|
|
#else
|
|
|
|
memcpy (dst, src, size);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
void
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf)
|
2018-06-15 19:21:31 +08:00
|
|
|
{
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid);
|
|
|
|
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
gdb_byte *base = sve_state.data ();
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
struct user_sve_header *header
|
|
|
|
= (struct user_sve_header *) sve_state.data ();
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2019-04-15 19:31:21 +08:00
|
|
|
uint64_t vq = sve_vq_from_vl (header->vl);
|
|
|
|
uint64_t vg = sve_vg_from_vl (header->vl);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
/* Sanity check the data in the header. */
|
|
|
|
if (!sve_vl_valid (header->vl)
|
|
|
|
|| SVE_PT_SIZE (vq, header->flags) != header->size)
|
|
|
|
error (_("Invalid SVE header from kernel."));
|
|
|
|
|
2019-04-15 19:31:21 +08:00
|
|
|
/* Update VG. Note, the registers in the regcache will already be of the
|
|
|
|
correct length. */
|
|
|
|
reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
if (HAS_SVE_STATE (*header))
|
|
|
|
{
|
|
|
|
/* The register dump contains a set of SVE registers. */
|
|
|
|
|
|
|
|
for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
|
|
|
|
reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i,
|
|
|
|
base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
|
|
|
|
|
|
|
|
for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
|
|
|
|
reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i,
|
|
|
|
base + SVE_PT_SVE_PREG_OFFSET (vq, i));
|
|
|
|
|
|
|
|
reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FFR_OFFSET (vq));
|
|
|
|
reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FPSR_OFFSET (vq));
|
|
|
|
reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FPCR_OFFSET (vq));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-19 00:06:05 +08:00
|
|
|
/* WARNING: SIMD state is laid out in memory in target-endian format,
|
|
|
|
while SVE state is laid out in an endianness-independent format (LE).
|
|
|
|
|
|
|
|
So we have a couple cases to consider:
|
|
|
|
|
|
|
|
1 - If the target is big endian, then SIMD state is big endian,
|
|
|
|
requiring a byteswap.
|
|
|
|
|
|
|
|
2 - If the target is little endian, then SIMD state is little endian,
|
|
|
|
which matches the SVE format, so no byteswap is needed. */
|
|
|
|
|
2018-06-15 19:21:31 +08:00
|
|
|
/* There is no SVE state yet - the register dump contains a fpsimd
|
|
|
|
structure instead. These registers still exist in the hardware, but
|
|
|
|
the kernel has not yet initialised them, and so they will be null. */
|
|
|
|
|
2020-03-19 00:06:05 +08:00
|
|
|
gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
|
2018-06-15 19:21:31 +08:00
|
|
|
struct user_fpsimd_state *fpsimd
|
|
|
|
= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
|
|
|
|
|
2020-03-19 00:06:05 +08:00
|
|
|
/* Make sure we have a zeroed register buffer. We will need the zero
|
|
|
|
padding below. */
|
|
|
|
memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
|
|
|
|
|
2018-06-15 19:21:31 +08:00
|
|
|
/* Copy across the V registers from fpsimd structure to the Z registers,
|
|
|
|
ensuring the non overlapping state is set to null. */
|
|
|
|
|
|
|
|
for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
|
|
|
|
{
|
2020-03-19 00:06:05 +08:00
|
|
|
/* Handle big endian/little endian SIMD/SVE conversion. */
|
|
|
|
aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i],
|
|
|
|
V_REGISTER_SIZE);
|
|
|
|
reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg);
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
|
|
|
|
(const gdb_byte *) &fpsimd->fpsr);
|
|
|
|
reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
|
|
|
|
(const gdb_byte *) &fpsimd->fpcr);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
/* Clear the SVE only registers. */
|
2020-03-19 00:06:05 +08:00
|
|
|
memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
|
2020-03-19 00:06:05 +08:00
|
|
|
reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
2020-03-19 00:06:05 +08:00
|
|
|
reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg);
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
|
|
|
|
/* At this point we have updated the register cache with the contents of
|
|
|
|
the NT_ARM_SVE register set. */
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 01:24:32 +08:00
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
void
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
aarch64_sve_regs_copy_from_reg_buf (int tid,
|
|
|
|
struct reg_buffer_common *reg_buf)
|
2018-06-15 19:21:31 +08:00
|
|
|
{
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* First store the vector length to the thread. This is done first to
|
|
|
|
ensure the ptrace buffers read from the kernel are the correct size. */
|
|
|
|
if (!aarch64_sve_set_vq (tid, reg_buf))
|
|
|
|
perror_with_name (_("Unable to set VG register"));
|
|
|
|
|
|
|
|
/* Obtain a dump of SVE registers from ptrace. */
|
|
|
|
gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid);
|
|
|
|
|
|
|
|
struct user_sve_header *header = (struct user_sve_header *) sve_state.data ();
|
2019-04-15 19:31:21 +08:00
|
|
|
uint64_t vq = sve_vq_from_vl (header->vl);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
gdb::byte_vector new_state (SVE_PT_SIZE (32, SVE_PT_REGS_SVE), 0);
|
|
|
|
memcpy (new_state.data (), sve_state.data (), sve_state.size ());
|
|
|
|
header = (struct user_sve_header *) new_state.data ();
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
gdb_byte *base = new_state.data ();
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
|
2018-06-15 19:21:31 +08:00
|
|
|
/* Sanity check the data in the header. */
|
|
|
|
if (!sve_vl_valid (header->vl)
|
|
|
|
|| SVE_PT_SIZE (vq, header->flags) != header->size)
|
|
|
|
error (_("Invalid SVE header from kernel."));
|
|
|
|
|
|
|
|
if (!HAS_SVE_STATE (*header))
|
|
|
|
{
|
|
|
|
/* There is no SVE state yet - the register dump contains a fpsimd
|
|
|
|
structure instead. Where possible we want to write the reg_buf data
|
|
|
|
back to the kernel using the fpsimd structure. However, if we cannot
|
|
|
|
then we'll need to reformat the fpsimd into a full SVE structure,
|
|
|
|
resulting in the initialization of SVE state written back to the
|
|
|
|
kernel, which is why we try to avoid it. */
|
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* Buffer (using the maximum size a Z register) used to look for zeroed
|
|
|
|
out sve state. */
|
|
|
|
gdb_byte reg[256];
|
|
|
|
memset (reg, 0, sizeof (reg));
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
/* Check in the reg_buf if any of the Z registers are set after the
|
|
|
|
first 128 bits, or if any of the other SVE registers are set. */
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
bool has_sve_state = false;
|
2018-06-15 19:21:31 +08:00
|
|
|
for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
|
|
|
|
{
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
if (!reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i, reg,
|
|
|
|
V_REGISTER_SIZE))
|
|
|
|
{
|
|
|
|
has_sve_state = true;
|
|
|
|
break;
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_sve_state)
|
|
|
|
for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
|
|
|
|
{
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
if (!reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i, reg, 0))
|
|
|
|
{
|
|
|
|
has_sve_state = true;
|
|
|
|
break;
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_sve_state)
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
has_sve_state
|
|
|
|
= !reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM, reg, 0);
|
|
|
|
|
|
|
|
struct user_fpsimd_state *fpsimd
|
|
|
|
= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
|
|
|
/* If no SVE state exists, then use the existing fpsimd structure to
|
|
|
|
write out state and return. */
|
|
|
|
if (!has_sve_state)
|
|
|
|
{
|
2020-03-19 00:06:05 +08:00
|
|
|
/* WARNING: SIMD state is laid out in memory in target-endian format,
|
|
|
|
while SVE state is laid out in an endianness-independent format
|
|
|
|
(LE).
|
|
|
|
|
|
|
|
So we have a couple cases to consider:
|
|
|
|
|
|
|
|
1 - If the target is big endian, then SIMD state is big endian,
|
|
|
|
requiring a byteswap.
|
|
|
|
|
|
|
|
2 - If the target is little endian, then SIMD state is little
|
|
|
|
endian, which matches the SVE format, so no byteswap is needed. */
|
|
|
|
|
2018-06-15 19:21:31 +08:00
|
|
|
/* The collects of the Z registers will overflow the size of a vreg.
|
|
|
|
There is enough space in the structure to allow for this, but we
|
|
|
|
cannot overflow into the next register as we might not be
|
|
|
|
collecting every register. */
|
|
|
|
|
|
|
|
for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
|
|
|
|
{
|
|
|
|
if (REG_VALID
|
|
|
|
== reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
|
|
|
|
{
|
2020-03-19 00:06:05 +08:00
|
|
|
reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, reg);
|
|
|
|
/* Handle big endian/little endian SIMD/SVE conversion. */
|
|
|
|
aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg,
|
|
|
|
V_REGISTER_SIZE);
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
|
|
|
|
(gdb_byte *) &fpsimd->fpsr);
|
2018-06-15 19:21:31 +08:00
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
|
|
|
|
(gdb_byte *) &fpsimd->fpcr);
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* At this point we have collected all the data from the register
|
|
|
|
cache and we are ready to update the FPSIMD register content
|
|
|
|
of the thread. */
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* Fall through so we can update the thread's contents with the
|
|
|
|
FPSIMD register cache values. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise, reformat the fpsimd structure into a full SVE set, by
|
|
|
|
expanding the V registers (working backwards so we don't splat
|
|
|
|
registers before they are copied) and using zero for everything
|
|
|
|
else.
|
|
|
|
Note that enough space for a full SVE dump was originally allocated
|
|
|
|
for base. */
|
|
|
|
|
|
|
|
header->flags |= SVE_PT_REGS_SVE;
|
|
|
|
header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
|
|
|
|
|
|
|
|
memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
|
|
|
|
sizeof (uint32_t));
|
|
|
|
memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
|
|
|
|
sizeof (uint32_t));
|
|
|
|
|
|
|
|
for (int i = AARCH64_SVE_Z_REGS_NUM - 1; i >= 0 ; i--)
|
|
|
|
{
|
|
|
|
memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
|
|
|
|
sizeof (__int128_t));
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* At this point we have converted the FPSIMD layout to an SVE
|
|
|
|
layout and copied the register data.
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
Fall through so we can update the thread's contents with the SVE
|
|
|
|
register cache values. */
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
|
|
|
}
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We already have SVE state for this thread, so we just need to update
|
|
|
|
the values of the registers. */
|
|
|
|
for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM
|
|
|
|
+ i))
|
|
|
|
reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i,
|
|
|
|
base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM
|
|
|
|
+ i))
|
|
|
|
reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i,
|
|
|
|
base + SVE_PT_SVE_PREG_OFFSET (vq, i));
|
|
|
|
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM))
|
|
|
|
reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FFR_OFFSET (vq));
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
|
|
|
|
reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FPSR_OFFSET (vq));
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
|
|
|
|
reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
|
|
|
|
base + SVE_PT_SVE_FPCR_OFFSET (vq));
|
|
|
|
}
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
/* At this point we have collected all the data from the register cache and
|
|
|
|
we are ready to update the SVE/FPSIMD register contents of the thread.
|
2018-06-15 19:21:31 +08:00
|
|
|
|
refactor: Simplify SVE interface to read/write registers
This is a patch in preparation to upcoming patches enabling SME support. It
attempts to simplify the gdb/gdbserver shared interface used to read/write
SVE registers.
Where the current code makes use of unique_ptr, allocating a new buffer by
hand and passing a buffer around, this patch makes that code use
gdb::byte_vector and passes a reference to this byte vector to the functions,
allowing the functions to have ready access to the size of the buffer.
It also shares a bit more code between gdb and gdbserver, in particular around
handling of ptrace get/set requests for SVE.
I think gdbserver could be refactored to handle register reads/writes more
like gdb's native layer as opposed to letting the generic linux-low layer do
the ptrace calls. This is not very flexible and assumes one size for the
responses. If you have something like NT_ARM_SVE, where you can have either
FPSIMD or SVE contents, it doesn't work that well.
I didn't want to change that interface right now as it is a bit too much work
and touches all the targets, some of which I can't easily test.
Hence the reason why the buffer the generic linux-now passes down to
linux-aarch64-low is unused or ignored.
No user-visible changes should happen as part of this refactor other than a
slightly reworded warning message.
While doing the refactor, I also noticed what seems to be a mistake in checking
if the register cache contains active (non-zero) SVE data.
For instance, the original code did something like this in
aarch64_sve_regs_copy_from_reg_buf:
has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i
reg, sizeof (__int128_t));
"reg" is a zeroed-out buffer that we compare the Z register contents
past the first 128 bits. The problem here is that raw_compare returns
1 if the contents compare the same, which means has_sve_state will be
true. But if we compared the Z register contents to 0, it means we
*do not* have SVE state, and therefore has_sve_state should be false.
The consequence of this mistake is that we convert the initial
FPSIMD-formatted data we get from ptrace for the NT_ARM_SVE register
set to a SVE-formatted one.
In the end, this doesn't cause user-visible differences because the
values of both the Z and V registers will still be the same. But the
logic is not correct.
I used the opportunity to fix this, and it gets tested later on by
the additional SME tests.
I do plan on submitting some SVE-specific tests to make sure we have
a bit more coverage in GDB's testsuite.
Regression-tested on aarch64-linux Ubuntu 22.04/20.04.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-07 18:08:23 +08:00
|
|
|
sve_state should contain all the data in the correct format, ready to be
|
|
|
|
passed on to ptrace. */
|
|
|
|
aarch64_store_sve_regset (tid, new_state);
|
2018-06-15 19:21:31 +08:00
|
|
|
}
|
2023-02-07 17:36:23 +08:00
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_za_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf,
|
|
|
|
int za_regnum, int svg_regnum,
|
|
|
|
int svcr_regnum)
|
|
|
|
{
|
|
|
|
/* Fetch the current ZA state from the thread. */
|
|
|
|
gdb::byte_vector za_state = aarch64_fetch_za_regset (tid);
|
|
|
|
|
|
|
|
/* Sanity check. */
|
|
|
|
gdb_assert (!za_state.empty ());
|
|
|
|
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
gdb_byte *base = za_state.data ();
|
2023-02-07 17:36:23 +08:00
|
|
|
struct user_za_header *header = (struct user_za_header *) base;
|
|
|
|
|
|
|
|
/* If we have ZA state, read it. Otherwise, make the contents of ZA
|
|
|
|
in the register cache all zeroes. This is how we present the ZA
|
|
|
|
state when it is not initialized. */
|
|
|
|
uint64_t svcr_value = 0;
|
|
|
|
if (aarch64_has_za_state (tid))
|
|
|
|
{
|
|
|
|
/* Sanity check the data in the header. */
|
|
|
|
if (!sve_vl_valid (header->vl)
|
|
|
|
|| ZA_PT_SIZE (sve_vq_from_vl (header->vl)) != header->size)
|
|
|
|
{
|
|
|
|
error (_("Found invalid streaming vector length in NT_ARM_ZA"
|
|
|
|
" register set"));
|
|
|
|
}
|
|
|
|
|
|
|
|
reg_buf->raw_supply (za_regnum, base + ZA_PT_ZA_OFFSET);
|
|
|
|
svcr_value |= SVCR_ZA_BIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t za_bytes = header->vl * header->vl;
|
|
|
|
gdb_byte za_zeroed[za_bytes];
|
|
|
|
memset (za_zeroed, 0, za_bytes);
|
|
|
|
reg_buf->raw_supply (za_regnum, za_zeroed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle the svg and svcr registers separately. We need to calculate
|
|
|
|
their values manually, as the Linux Kernel doesn't expose those
|
|
|
|
explicitly. */
|
|
|
|
svcr_value |= aarch64_has_ssve_state (tid)? SVCR_SM_BIT : 0;
|
|
|
|
uint64_t svg_value = sve_vg_from_vl (header->vl);
|
|
|
|
|
|
|
|
/* Update the contents of svg and svcr registers. */
|
|
|
|
reg_buf->raw_supply (svg_regnum, &svg_value);
|
|
|
|
reg_buf->raw_supply (svcr_regnum, &svcr_value);
|
|
|
|
|
|
|
|
/* The register buffer should now contain the updated copy of the NT_ARM_ZA
|
|
|
|
state. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_za_regs_copy_from_reg_buf (int tid,
|
|
|
|
struct reg_buffer_common *reg_buf,
|
|
|
|
int za_regnum, int svg_regnum,
|
|
|
|
int svcr_regnum)
|
|
|
|
{
|
|
|
|
/* REG_BUF contains the updated ZA state. We need to extract that state
|
|
|
|
and write it to the thread TID. */
|
|
|
|
|
|
|
|
|
|
|
|
/* First check if there is a change to the streaming vector length. Two
|
|
|
|
outcomes are possible here:
|
|
|
|
|
|
|
|
1 - The streaming vector length in the register cache differs from the
|
|
|
|
one currently on the thread state. This means that we will need to
|
|
|
|
update the NT_ARM_ZA register set to reflect the new streaming vector
|
|
|
|
length.
|
|
|
|
|
|
|
|
2 - The streaming vector length in the register cache is the same as in
|
|
|
|
the thread state. This means we do not need to update the NT_ARM_ZA
|
|
|
|
register set for a new streaming vector length, and we only need to
|
|
|
|
deal with changes to za, svg and svcr.
|
|
|
|
|
|
|
|
None of the two possibilities above imply that the ZA state actually
|
|
|
|
exists. They only determine what needs to be done with any ZA content
|
|
|
|
based on the state of the streaming vector length. */
|
|
|
|
|
|
|
|
/* First fetch the NT_ARM_ZA header so we can fetch the streaming vector
|
|
|
|
length. */
|
|
|
|
struct user_za_header header;
|
|
|
|
if (!read_za_header (tid, header))
|
|
|
|
error (_("Failed to read NT_ARM_ZA header."));
|
|
|
|
|
|
|
|
/* Fetch the current streaming vector length. */
|
|
|
|
uint64_t old_svg = sve_vg_from_vl (header.vl);
|
|
|
|
|
|
|
|
/* Fetch the (potentially) new streaming vector length. */
|
|
|
|
uint64_t new_svg;
|
|
|
|
reg_buf->raw_collect (svg_regnum, &new_svg);
|
|
|
|
|
|
|
|
/* Did the streaming vector length change? */
|
|
|
|
bool svg_changed = new_svg != old_svg;
|
|
|
|
|
|
|
|
/* First store the streaming vector length to the thread. This is done
|
|
|
|
first to ensure the ptrace buffers read from the kernel are the correct
|
|
|
|
size. If the streaming vector length is the same as the current one, it
|
|
|
|
won't be updated. */
|
|
|
|
if (!aarch64_za_set_svq (tid, reg_buf, svg_regnum))
|
|
|
|
error (_("Unable to set svg register"));
|
|
|
|
|
|
|
|
bool has_za_state = aarch64_has_za_state (tid);
|
|
|
|
|
|
|
|
size_t za_bytes = sve_vl_from_vg (old_svg) * sve_vl_from_vg (old_svg);
|
|
|
|
gdb_byte za_zeroed[za_bytes];
|
|
|
|
memset (za_zeroed, 0, za_bytes);
|
|
|
|
|
|
|
|
/* If the streaming vector length changed, zero out the contents of ZA in
|
|
|
|
the register cache. Otherwise, we will need to update the ZA contents
|
|
|
|
in the thread with the ZA contents from the register cache, and they will
|
|
|
|
differ in size. */
|
|
|
|
if (svg_changed)
|
|
|
|
reg_buf->raw_supply (za_regnum, za_zeroed);
|
|
|
|
|
|
|
|
/* When we update svg, we don't automatically initialize the ZA buffer. If
|
|
|
|
we have no ZA state and the ZA register contents in the register cache are
|
|
|
|
zero, just return and leave the ZA register cache contents as zero. */
|
|
|
|
if (!has_za_state
|
|
|
|
&& reg_buf->raw_compare (za_regnum, za_zeroed, 0))
|
|
|
|
{
|
|
|
|
/* No ZA state in the thread or in the register cache. This was likely
|
|
|
|
just an adjustment of the streaming vector length. Let this fall
|
|
|
|
through and update svcr and svg in the register cache. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If there is no ZA state but the register cache contains ZA data, we
|
|
|
|
need to initialize the ZA data through ptrace. First we initialize
|
|
|
|
all the bytes of ZA to zero. */
|
|
|
|
if (!has_za_state
|
|
|
|
&& !reg_buf->raw_compare (za_regnum, za_zeroed, 0))
|
|
|
|
aarch64_initialize_za_regset (tid);
|
|
|
|
|
|
|
|
/* From this point onwards, it is assumed we have a ZA payload in
|
|
|
|
the NT_ARM_ZA register set for this thread, and we need to update
|
|
|
|
such state based on the contents of the register cache. */
|
|
|
|
|
|
|
|
/* Fetch the current ZA state from the thread. */
|
|
|
|
gdb::byte_vector za_state = aarch64_fetch_za_regset (tid);
|
|
|
|
|
gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-02 00:27:18 +08:00
|
|
|
gdb_byte *base = za_state.data ();
|
2023-02-07 17:36:23 +08:00
|
|
|
struct user_za_header *za_header = (struct user_za_header *) base;
|
|
|
|
uint64_t svq = sve_vq_from_vl (za_header->vl);
|
|
|
|
|
|
|
|
/* Sanity check the data in the header. */
|
|
|
|
if (!sve_vl_valid (za_header->vl)
|
|
|
|
|| ZA_PT_SIZE (svq) != za_header->size)
|
|
|
|
error (_("Invalid vector length or payload size when reading ZA."));
|
|
|
|
|
|
|
|
/* Overwrite the ZA state contained in the thread with the ZA state from
|
|
|
|
the register cache. */
|
|
|
|
if (REG_VALID == reg_buf->get_register_status (za_regnum))
|
|
|
|
reg_buf->raw_collect (za_regnum, base + ZA_PT_ZA_OFFSET);
|
|
|
|
|
|
|
|
/* Write back the ZA state to the thread's NT_ARM_ZA register set. */
|
|
|
|
aarch64_store_za_regset (tid, za_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update svcr and svg accordingly. */
|
|
|
|
uint64_t svcr_value = 0;
|
|
|
|
svcr_value |= aarch64_has_ssve_state (tid)? SVCR_SM_BIT : 0;
|
|
|
|
svcr_value |= aarch64_has_za_state (tid)? SVCR_ZA_BIT : 0;
|
|
|
|
reg_buf->raw_supply (svcr_regnum, &svcr_value);
|
|
|
|
|
|
|
|
/* At this point we have written the data contained in the register cache to
|
|
|
|
the thread's NT_ARM_ZA register set. */
|
|
|
|
}
|
2023-04-05 00:20:46 +08:00
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_zt_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf,
|
|
|
|
int zt_regnum)
|
|
|
|
{
|
|
|
|
/* If we have ZA state, read the ZT state. Otherwise, make the contents of
|
|
|
|
ZT in the register cache all zeroes. This is how we present the ZT
|
|
|
|
state when it is not initialized (ZA not active). */
|
|
|
|
if (aarch64_has_za_state (tid))
|
|
|
|
{
|
|
|
|
/* Fetch the current ZT state from the thread. */
|
|
|
|
gdb::byte_vector zt_state = aarch64_fetch_zt_regset (tid);
|
|
|
|
|
|
|
|
/* Sanity check. */
|
|
|
|
gdb_assert (!zt_state.empty ());
|
|
|
|
|
|
|
|
/* Copy the ZT data to the register buffer. */
|
|
|
|
reg_buf->raw_supply (zt_regnum, zt_state.data ());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Zero out ZT. */
|
|
|
|
gdb::byte_vector zt_zeroed (AARCH64_SME2_ZT0_SIZE, 0);
|
|
|
|
reg_buf->raw_supply (zt_regnum, zt_zeroed.data ());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The register buffer should now contain the updated copy of the NT_ARM_ZT
|
|
|
|
state. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See nat/aarch64-scalable-linux-ptrace.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_zt_regs_copy_from_reg_buf (int tid,
|
|
|
|
struct reg_buffer_common *reg_buf,
|
|
|
|
int zt_regnum)
|
|
|
|
{
|
|
|
|
/* Do we have a valid ZA state? */
|
|
|
|
bool valid_za = aarch64_has_za_state (tid);
|
|
|
|
|
|
|
|
/* Is the register buffer contents for ZT all zeroes? */
|
|
|
|
gdb::byte_vector zt_bytes (AARCH64_SME2_ZT0_SIZE, 0);
|
|
|
|
bool zt_is_all_zeroes
|
|
|
|
= reg_buf->raw_compare (zt_regnum, zt_bytes.data (), 0);
|
|
|
|
|
|
|
|
/* If ZA state is valid or if we have non-zero data for ZT in the register
|
|
|
|
buffer, we will invoke ptrace to write the ZT state. Otherwise we don't
|
|
|
|
have to do anything here. */
|
|
|
|
if (valid_za || !zt_is_all_zeroes)
|
|
|
|
{
|
|
|
|
if (!valid_za)
|
|
|
|
{
|
|
|
|
/* ZA state is not valid. That means we need to initialize the ZA
|
|
|
|
state prior to writing the ZT state. */
|
|
|
|
aarch64_initialize_za_regset (tid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract the ZT data from the register buffer. */
|
|
|
|
reg_buf->raw_collect (zt_regnum, zt_bytes.data ());
|
|
|
|
|
|
|
|
/* Write the ZT data to thread TID. */
|
|
|
|
aarch64_store_zt_regset (tid, zt_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* At this point we have (potentially) written the data contained in the
|
|
|
|
register cache to the thread's NT_ARM_ZT register set. */
|
|
|
|
}
|