42
42
#include <sys/user.h>
43
43
#include <sys/wait.h>
44
44
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
+
45
67
#if VEX_HOST_WORDSIZE == 8
46
68
typedef Addr64 CORE_ADDR ;
47
69
#elif VEX_HOST_WORDSIZE == 4
@@ -492,8 +514,11 @@ void detach_from_all_threads (pid_t pid)
492
514
}
493
515
}
494
516
517
+ # if defined(VGA_arm64 )
518
+ static struct user_pt_regs user_save ;
519
+ # else
495
520
static struct user user_save ;
496
-
521
+ # endif
497
522
// The below indicates if ptrace_getregs (and ptrace_setregs) can be used.
498
523
// Note that some linux versions are defining PTRACE_GETREGS but using
499
524
// it gives back EIO.
@@ -505,6 +530,10 @@ static struct user user_save;
505
530
#ifdef HAVE_PTRACE_GETREGS
506
531
static int has_working_ptrace_getregs = -1 ;
507
532
#endif
533
+ // Similar but for PTRACE_GETREGSET
534
+ #ifdef HAVE_PTRACE_GETREGSET
535
+ static int has_working_ptrace_getregset = -1 ;
536
+ #endif
508
537
509
538
/* Get the registers from pid into regs.
510
539
regs_bsz value gives the length of *regs.
@@ -513,6 +542,52 @@ static
513
542
Bool getregs (pid_t pid , void * regs , long regs_bsz )
514
543
{
515
544
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
+
516
591
# ifdef HAVE_PTRACE_GETREGS
517
592
if (has_working_ptrace_getregs ) {
518
593
// Platforms having GETREGS
@@ -570,8 +645,8 @@ Bool getregs (pid_t pid, void *regs, long regs_bsz)
570
645
return True ;
571
646
}
572
647
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.
575
650
assert (0 );
576
651
}
577
652
@@ -582,6 +657,30 @@ static
582
657
Bool setregs (pid_t pid , void * regs , long regs_bsz )
583
658
{
584
659
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
+
585
684
// Note : the below is checking for GETREGS, not SETREGS
586
685
// as if one is defined and working, the other one should also work.
587
686
# ifdef HAVE_PTRACE_GETREGS
@@ -683,7 +782,11 @@ Bool invoker_invoke_gdbserver (pid_t pid)
683
782
{
684
783
long res ;
685
784
Bool stopped ;
785
+ # if defined(VGA_arm64 )
786
+ struct user_pt_regs user_mod ;
787
+ # else
686
788
struct user user_mod ;
789
+ # endif
687
790
Addr sp ;
688
791
/* A specific int value is passed to invoke_gdbserver, to check
689
792
everything goes according to the plan. */
@@ -736,6 +839,8 @@ Bool invoker_invoke_gdbserver (pid_t pid)
736
839
}
737
840
#elif defined(VGA_arm )
738
841
sp = user_mod .regs .uregs [13 ];
842
+ #elif defined(VGA_arm64 )
843
+ sp = user_mod .sp ;
739
844
#elif defined(VGA_ppc32 )
740
845
sp = user_mod .regs .gpr [1 ];
741
846
#elif defined(VGA_ppc64 )
@@ -817,6 +922,9 @@ Bool invoker_invoke_gdbserver (pid_t pid)
817
922
user_mod .regs .uregs [14 ] = bad_return ;
818
923
user_mod .regs .uregs [15 ] = shared32 -> invoke_gdbserver ;
819
924
925
+ #elif defined(VGA_arm64 )
926
+ XERROR (0 , "TBD arm64: vgdb a 32 bits executable with a 64 bits exe" );
927
+
820
928
#elif defined(VGA_s390x )
821
929
XERROR (0 , "(fn32) s390x has no 32bits implementation" );
822
930
#elif defined(VGA_mips32 )
@@ -867,6 +975,13 @@ Bool invoker_invoke_gdbserver (pid_t pid)
867
975
868
976
#elif defined(VGA_arm )
869
977
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
+
870
985
#elif defined(VGA_ppc32 )
871
986
assert (0 ); // cannot vgdb a 64 bits executable with a 32 bits exe
872
987
#elif defined(VGA_ppc64 )
0 commit comments