2019-10-25 13:22:33 +00:00
package native
import (
"debug/elf"
"fmt"
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
2021-03-04 18:28:28 +00:00
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
2019-10-25 13:22:33 +00:00
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
const (
2020-03-26 12:05:09 +00:00
_AARCH64_GREGS_SIZE = 34 * 8
_AARCH64_FPREGS_SIZE = 32 * 16 + 8
2021-02-23 20:38:52 +00:00
_NT_ARM_TLS = 0x401 // used in PTRACE_GETREGSET on ARM64 to retrieve the value of TPIDR_EL0, see source/include/uapi/linux/elf.h and source/arch/arm64/kernel/ptrace.c
2019-10-25 13:22:33 +00:00
)
func ptraceGetGRegs ( pid int , regs * linutil . ARM64PtraceRegs ) ( err error ) {
2020-03-26 12:05:09 +00:00
iov := sys . Iovec { Base : ( * byte ) ( unsafe . Pointer ( regs ) ) , Len : _AARCH64_GREGS_SIZE }
2019-10-25 13:22:33 +00:00
_ , _ , err = syscall . Syscall6 ( syscall . SYS_PTRACE , sys . PTRACE_GETREGSET , uintptr ( pid ) , uintptr ( elf . NT_PRSTATUS ) , uintptr ( unsafe . Pointer ( & iov ) ) , 0 , 0 )
if err == syscall . Errno ( 0 ) {
err = nil
}
return
}
2021-02-23 20:38:52 +00:00
func ptraceGetTpidr_el0 ( pid int , tpidr_el0 * uint64 ) ( err error ) {
iov := sys . Iovec { Base : ( * byte ) ( unsafe . Pointer ( tpidr_el0 ) ) , Len : uint64 ( unsafe . Sizeof ( * tpidr_el0 ) ) }
_ , _ , err = syscall . Syscall6 ( syscall . SYS_PTRACE , sys . PTRACE_GETREGSET , uintptr ( pid ) , uintptr ( _NT_ARM_TLS ) , uintptr ( unsafe . Pointer ( & iov ) ) , 0 , 0 )
if err == syscall . Errno ( 0 ) {
err = nil
}
return
}
2019-10-25 13:22:33 +00:00
func ptraceSetGRegs ( pid int , regs * linutil . ARM64PtraceRegs ) ( err error ) {
2020-03-26 12:05:09 +00:00
iov := sys . Iovec { Base : ( * byte ) ( unsafe . Pointer ( regs ) ) , Len : _AARCH64_GREGS_SIZE }
2019-10-25 13:22:33 +00:00
_ , _ , err = syscall . Syscall6 ( syscall . SYS_PTRACE , sys . PTRACE_SETREGSET , uintptr ( pid ) , uintptr ( elf . NT_PRSTATUS ) , uintptr ( unsafe . Pointer ( & iov ) ) , 0 , 0 )
if err == syscall . Errno ( 0 ) {
err = nil
}
return
}
2020-03-26 12:05:09 +00:00
// ptraceGetFpRegset returns floating point registers of the specified thread
2019-10-25 13:22:33 +00:00
// using PTRACE.
2020-03-26 12:05:09 +00:00
func ptraceGetFpRegset ( tid int ) ( fpregset [ ] byte , err error ) {
var arm64_fpregs [ _AARCH64_FPREGS_SIZE ] byte
iov := sys . Iovec { Base : & arm64_fpregs [ 0 ] , Len : _AARCH64_FPREGS_SIZE }
2019-10-25 13:22:33 +00:00
_ , _ , err = syscall . Syscall6 ( syscall . SYS_PTRACE , sys . PTRACE_GETREGSET , uintptr ( tid ) , uintptr ( elf . NT_FPREGSET ) , uintptr ( unsafe . Pointer ( & iov ) ) , 0 , 0 )
if err != syscall . Errno ( 0 ) {
if err == syscall . ENODEV {
err = nil
}
return
} else {
err = nil
}
fpregset = arm64_fpregs [ : iov . Len - 8 ]
return fpregset , err
}
2021-03-04 18:28:28 +00:00
// setPC sets PC to the value specified by 'pc'.
func ( thread * nativeThread ) setPC ( pc uint64 ) error {
2020-05-13 18:56:50 +00:00
ir , err := registers ( thread )
2019-10-25 13:22:33 +00:00
if err != nil {
return err
}
r := ir . ( * linutil . ARM64Registers )
r . Regs . Pc = pc
thread . dbp . execPtraceFunc ( func ( ) { err = ptraceSetGRegs ( thread . ID , r . Regs ) } )
return err
}
2021-03-04 18:28:28 +00:00
func ( thread * nativeThread ) SetReg ( regNum uint64 , reg * op . DwarfRegister ) error {
ir , err := registers ( thread )
2019-10-25 13:22:33 +00:00
if err != nil {
return err
}
r := ir . ( * linutil . ARM64Registers )
2021-03-04 18:28:28 +00:00
switch regNum {
case regnum . ARM64_PC :
r . Regs . Pc = reg . Uint64Val
case regnum . ARM64_SP :
r . Regs . Sp = reg . Uint64Val
default :
//TODO(aarzilli): when the register calling convention is adopted by Go on
// arm64 this should be implemented.
return fmt . Errorf ( "changing register %d not implemented" , regNum )
}
thread . dbp . execPtraceFunc ( func ( ) { err = ptraceSetGRegs ( thread . ID , r . Regs ) } )
return err
2019-10-25 13:22:33 +00:00
}
2020-05-13 18:56:50 +00:00
func registers ( thread * nativeThread ) ( proc . Registers , error ) {
2019-10-25 13:22:33 +00:00
var (
regs linutil . ARM64PtraceRegs
err error
)
thread . dbp . execPtraceFunc ( func ( ) { err = ptraceGetGRegs ( thread . ID , & regs ) } )
if err != nil {
return nil , err
}
2021-02-23 20:38:52 +00:00
var tpidr_el0 uint64
if thread . dbp . iscgo {
thread . dbp . execPtraceFunc ( func ( ) { err = ptraceGetTpidr_el0 ( thread . ID , & tpidr_el0 ) } )
if err != nil {
return nil , err
}
}
r := linutil . NewARM64Registers ( & regs , thread . dbp . iscgo , tpidr_el0 , func ( r * linutil . ARM64Registers ) error {
2020-05-13 18:56:50 +00:00
var floatLoadError error
r . Fpregs , r . Fpregset , floatLoadError = thread . fpRegisters ( )
return floatLoadError
} )
2019-10-25 13:22:33 +00:00
return r , nil
}