Skip to content

Commit 230a109

Browse files
author
philippe
committed
Enable vgdb ptrace invoker for aarch64.
This only works in non-bi arch mode. If ever aarch64+arm are compiled bi-arch, then some more work is needed to have a 64 bits vgdb able to ptrace invoke a 32 bits valgrind. Note also that PTRACE_GETREGSET is defined on other platforms (e.g. ppc64 fedora 18 defines it), but it is not used on these platforms, as again, PTRACE_GETREGSET implies some work for bi-arch to work properly. So, on all platforms except arm64, we use PTRACE_GETREGS or PTRACE_PEEKUSER. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13981 a5019735-40e9-0310-863c-91ae7b9d1cf9
1 parent 743047f commit 230a109

File tree

4 files changed

+121
-16
lines changed

4 files changed

+121
-16
lines changed

README.aarch64

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ the 64-bit ARM architecture. Currently it supports integer and FP
77
instructions and can run anything generated by gcc-4.8.2 -O3. The
88
port is under active development.
99

10-
Current limitations, as of mid-March 2014.
10+
Current limitations, as of mid-May 2014.
1111

1212
* limited support of vector (SIMD) instructions. Initial target is
1313
support for instructions created by gcc-4.8.2 -O3
1414
(via autovectorisation). This is complete.
1515

1616
* Integration with the built in GDB server:
17-
- basically works but breakpoints may be problematic (unclear)
18-
Use --vgdb=full to bypass the problem.
17+
- works ok (breakpoint, attach to a process blocked in a syscall, ...)
1918
- still to do:
2019
arm64 xml register description files (allowing shadow registers
2120
to be looked at).
22-
ptrace invoker : currently disabled for both arm and arm64
2321
cpsr transfer to/from gdb to be looked at (see also arm equivalent code)
2422

2523
* limited syscall support

coregrind/Makefile.am

-7
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,13 @@ endif
6161

6262

6363
vgdb_SOURCES = vgdb.c
64-
if VGCONF_PLATFORMS_INCLUDE_ARM64_LINUX
65-
# vgdb-invoker-ptrace.c isn't buildable on arm64-linux yet
66-
# so skip it. Unfortunately this also causes it to be skipped
67-
# for 32-bit ARM builds which are part of a bi-arch ARM build.
68-
vgdb_SOURCES += vgdb-invoker-none.c
69-
else
7064
if VGCONF_OS_IS_LINUX
7165
if VGCONF_PLATVARIANT_IS_ANDROID
7266
vgdb_SOURCES += vgdb-invoker-none.c
7367
else
7468
vgdb_SOURCES += vgdb-invoker-ptrace.c
7569
endif
7670
endif
77-
endif
7871
if VGCONF_OS_IS_DARWIN
7972
# Some darwin specific stuff is needed as ptrace is not
8073
# fully supported on MacOS. Till we find someone courageous

coregrind/m_options.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ Bool VG_(clo_error_limit) = True;
4848
Int VG_(clo_error_exitcode) = 0;
4949

5050
#if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
51-
|| defined(VGPV_mips32_linux_android) \
52-
|| defined(VGP_arm64_linux) // temporarily disabled on arm64-linux
51+
|| defined(VGPV_mips32_linux_android)
5352
VgVgdb VG_(clo_vgdb) = Vg_VgdbNo; // currently disabled on Android
5453
#else
5554
VgVgdb VG_(clo_vgdb) = Vg_VgdbYes;

coregrind/vgdb-invoker-ptrace.c

+118-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@
4242
#include <sys/user.h>
4343
#include <sys/wait.h>
4444

45+
#ifdef PTRACE_GETREGSET
46+
// TBD: better have a configure test instead ?
47+
#define HAVE_PTRACE_GETREGSET
48+
49+
// A bi-arch build using PTRACE_GET/SETREGSET needs
50+
// some conversion code for register structures.
51+
// So, better do not use PTRACE_GET/SETREGSET
52+
// Rather we use PTRACE_GETREGS or PTRACE_PEEKUSER.
53+
54+
// The only platform on which we must use PTRACE_GETREGSET is arm64.
55+
// The resulting vgdb cannot work in a bi-arch setup.
56+
// -1 means we will check that PTRACE_GETREGSET works.
57+
# if defined(VGA_arm64)
58+
#define USE_PTRACE_GETREGSET
59+
# endif
60+
#endif
61+
62+
#include <sys/uio.h>
63+
#include <elf.h>
64+
65+
#include <sys/procfs.h>
66+
4567
#if VEX_HOST_WORDSIZE == 8
4668
typedef Addr64 CORE_ADDR;
4769
#elif VEX_HOST_WORDSIZE == 4
@@ -492,8 +514,11 @@ void detach_from_all_threads (pid_t pid)
492514
}
493515
}
494516

517+
# if defined(VGA_arm64)
518+
static struct user_pt_regs user_save;
519+
# else
495520
static struct user user_save;
496-
521+
# endif
497522
// The below indicates if ptrace_getregs (and ptrace_setregs) can be used.
498523
// Note that some linux versions are defining PTRACE_GETREGS but using
499524
// it gives back EIO.
@@ -505,6 +530,10 @@ static struct user user_save;
505530
#ifdef HAVE_PTRACE_GETREGS
506531
static int has_working_ptrace_getregs = -1;
507532
#endif
533+
// Similar but for PTRACE_GETREGSET
534+
#ifdef HAVE_PTRACE_GETREGSET
535+
static int has_working_ptrace_getregset = -1;
536+
#endif
508537

509538
/* Get the registers from pid into regs.
510539
regs_bsz value gives the length of *regs.
@@ -513,6 +542,52 @@ static
513542
Bool getregs (pid_t pid, void *regs, long regs_bsz)
514543
{
515544
DEBUG(1, "getregs regs_bsz %ld\n", regs_bsz);
545+
# ifdef HAVE_PTRACE_GETREGSET
546+
# ifndef USE_PTRACE_GETREGSET
547+
if (has_working_ptrace_getregset)
548+
DEBUG(1, "PTRACE_GETREGSET defined, not used (yet?) by vgdb\n");
549+
has_working_ptrace_getregset = 0;
550+
# endif
551+
if (has_working_ptrace_getregset) {
552+
// Platforms having GETREGSET
553+
long res;
554+
elf_gregset_t elf_regs;
555+
struct iovec iovec;
556+
557+
DEBUG(1, "getregs PTRACE_GETREGSET sizeof(elf_regs) %d\n", sizeof(elf_regs));
558+
iovec.iov_base = regs;
559+
iovec.iov_len = sizeof(elf_regs);
560+
561+
res = ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &iovec);
562+
if (res == 0) {
563+
if (has_working_ptrace_getregset == -1) {
564+
// First call to PTRACE_GETREGSET succesful =>
565+
has_working_ptrace_getregset = 1;
566+
DEBUG(1, "detected a working PTRACE_GETREGSET\n");
567+
}
568+
assert (has_working_ptrace_getregset == 1);
569+
return True;
570+
}
571+
else if (has_working_ptrace_getregset == 1) {
572+
// We had a working call, but now it fails.
573+
// This is unexpected.
574+
ERROR(errno, "PTRACE_GETREGSET %ld\n", res);
575+
return False;
576+
} else {
577+
// Check this is the first call:
578+
assert (has_working_ptrace_getregset == -1);
579+
if (errno == EIO) {
580+
DEBUG(1, "detected a broken PTRACE_GETREGSET with EIO\n");
581+
has_working_ptrace_getregset = 0;
582+
// Fall over to the PTRACE_GETREGS or PTRACE_PEEKUSER case.
583+
} else {
584+
ERROR(errno, "broken PTRACE_GETREGSET unexpected errno %ld\n", res);
585+
return False;
586+
}
587+
}
588+
}
589+
# endif
590+
516591
# ifdef HAVE_PTRACE_GETREGS
517592
if (has_working_ptrace_getregs) {
518593
// Platforms having GETREGS
@@ -570,8 +645,8 @@ Bool getregs (pid_t pid, void *regs, long regs_bsz)
570645
return True;
571646
}
572647

573-
// If neither PTRACE_GETREGS not PTRACE_PEEKUSER have returned,
574-
// then we are in serious trouble.
648+
// If neither of PTRACE_GETREGSET PTRACE_GETREGS PTRACE_PEEKUSER have
649+
// returned, then we are in serious trouble.
575650
assert (0);
576651
}
577652

@@ -582,6 +657,30 @@ static
582657
Bool setregs (pid_t pid, void *regs, long regs_bsz)
583658
{
584659
DEBUG(1, "setregs regs_bsz %ld\n", regs_bsz);
660+
661+
// Note : the below is checking for GETREGSET, not SETREGSET
662+
// as if one is defined and working, the other one should also work.
663+
# ifdef HAVE_PTRACE_GETREGSET
664+
if (has_working_ptrace_getregset) {
665+
// Platforms having SETREGSET
666+
long res;
667+
elf_gregset_t elf_regs;
668+
struct iovec iovec;
669+
670+
// setregset can never be called before getregset has done a runtime check.
671+
assert (has_working_ptrace_getregset == 1);
672+
DEBUG(1, "setregs PTRACE_SETREGSET sizeof(elf_regs) %d\n", sizeof(elf_regs));
673+
iovec.iov_base = regs;
674+
iovec.iov_len = sizeof(elf_regs);
675+
res = ptrace (PTRACE_SETREGSET, pid, NT_PRSTATUS, &iovec);
676+
if (res != 0) {
677+
ERROR(errno, "PTRACE_SETREGSET %ld\n", res);
678+
return False;
679+
}
680+
return True;
681+
}
682+
# endif
683+
585684
// Note : the below is checking for GETREGS, not SETREGS
586685
// as if one is defined and working, the other one should also work.
587686
# ifdef HAVE_PTRACE_GETREGS
@@ -683,7 +782,11 @@ Bool invoker_invoke_gdbserver (pid_t pid)
683782
{
684783
long res;
685784
Bool stopped;
785+
# if defined(VGA_arm64)
786+
struct user_pt_regs user_mod;
787+
# else
686788
struct user user_mod;
789+
# endif
687790
Addr sp;
688791
/* A specific int value is passed to invoke_gdbserver, to check
689792
everything goes according to the plan. */
@@ -736,6 +839,8 @@ Bool invoker_invoke_gdbserver (pid_t pid)
736839
}
737840
#elif defined(VGA_arm)
738841
sp = user_mod.regs.uregs[13];
842+
#elif defined(VGA_arm64)
843+
sp = user_mod.sp;
739844
#elif defined(VGA_ppc32)
740845
sp = user_mod.regs.gpr[1];
741846
#elif defined(VGA_ppc64)
@@ -817,6 +922,9 @@ Bool invoker_invoke_gdbserver (pid_t pid)
817922
user_mod.regs.uregs[14] = bad_return;
818923
user_mod.regs.uregs[15] = shared32->invoke_gdbserver;
819924

925+
#elif defined(VGA_arm64)
926+
XERROR(0, "TBD arm64: vgdb a 32 bits executable with a 64 bits exe");
927+
820928
#elif defined(VGA_s390x)
821929
XERROR(0, "(fn32) s390x has no 32bits implementation");
822930
#elif defined(VGA_mips32)
@@ -867,6 +975,13 @@ Bool invoker_invoke_gdbserver (pid_t pid)
867975

868976
#elif defined(VGA_arm)
869977
assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
978+
#elif defined(VGA_arm64)
979+
user_mod.regs[0] = check;
980+
user_mod.sp = sp;
981+
user_mod.pc = shared64->invoke_gdbserver;
982+
/* put NULL return address in Link Register */
983+
user_mod.regs[30] = bad_return;
984+
870985
#elif defined(VGA_ppc32)
871986
assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
872987
#elif defined(VGA_ppc64)

0 commit comments

Comments
 (0)