1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/*
* ISA-dependent functions for SPARC and SPARC64.
*/
/*
* Oracle Linux DTrace.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/ptrace.h>
#include <asm/ptrace.h> /* for struct pt_regs */
#include "Pcontrol.h"
#include "libproc.h"
#include "platform.h"
#define PTRACE_GETREGSET 0x4204
/*
* Get a SPARC64 regset.
*/
static struct pt_regs *
getregs_sparc64(struct ps_prochandle *P, struct pt_regs *regs)
{
if (Pstate(P) == PS_RUN ||
Pstate(P) == PS_DEAD)
return NULL;
if (wrapped_ptrace(P, PTRACE_GETREGS64, P->pid, regs) < 0)
return NULL;
return regs;
}
static struct pt_regs32 *
getregs_sparc32(struct ps_prochandle *P, struct pt_regs32 *regs)
{
if (Pstate(P) == PS_RUN ||
Pstate(P) == PS_DEAD)
return NULL;
if (wrapped_ptrace(P, PTRACE_GETREGS, P->pid, regs) < 0)
return NULL;
return regs;
}
/*
* Read the first argument of the function at which the process P is halted,
* which must be a pointer (though other integral arguments happen to work for
* the SPARC and SPARC64 ABI).
*
* For SPARC, the first integral argument to a function will always be in %i0.
* Horrifically, the value of all the UREG_* constants is off by 1, so we have
* to correct for that.
*
* On error, -1 cast to a uintptr_t is returned, and errno is set.
*/
uintptr_t
Pread_first_arg_sparc64(struct ps_prochandle *P)
{
struct pt_regs regs;
if (getregs_sparc64(P, ®s) == NULL)
return (uintptr_t)-1;
return regs.u_regs[UREG_I0 - 1];
}
uintptr_t
Pread_first_arg_sparc32(struct ps_prochandle *P)
{
struct pt_regs32 regs;
if (getregs_sparc32(P, ®s) == NULL)
return (uintptr_t)-1;
return regs.u_regs[UREG_I0 - 1];
}
/*
* Get the address at which we stopped at a breakpoint. Unlike on x86, no post
* facto adjustment is required.
*/
uintptr_t
Pget_bkpt_ip_sparc64(struct ps_prochandle *P, int expect_esrch)
{
struct pt_regs regs;
if (getregs_sparc64(P, ®s) == NULL) {
if ((errno == ESRCH) && (expect_esrch))
return 0;
else {
_dprintf("Unexpected ptrace (PTRACE_GETREGSET) "
"error: %s\n", strerror(errno));
return -1;
}
}
return regs.tpc;
}
/*
* Reset the instruction pointer address at which the process P is stopped.
* (Not needed on SPARC.)
*/
long
Preset_bkpt_ip_sparc(struct ps_prochandle *P, uintptr_t addr)
{
return 0; /* nothing doing */
}
/*
* Get the address at which the temporary breakpoint should be dropped when a
* breakpoint is hit.
*/
extern long Pget_next_ip_sparc64(struct ps_prochandle *P, uintptr_t addr)
{
struct pt_regs regs;
if (getregs_sparc64(P, ®s) == NULL) {
_dprintf("Unexpected ptrace (PTRACE_GETREGSET) "
"error: %s\n", strerror(errno));
return -1;
}
return regs.tnpc;
}
|