Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/hexagon/kernel/ptrace.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Ptrace support for Hexagon
4
*
5
* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
6
*/
7
8
#include <linux/kernel.h>
9
#include <linux/sched.h>
10
#include <linux/sched/task_stack.h>
11
#include <linux/mm.h>
12
#include <linux/smp.h>
13
#include <linux/errno.h>
14
#include <linux/ptrace.h>
15
#include <linux/regset.h>
16
#include <linux/user.h>
17
#include <linux/elf.h>
18
19
#include <asm/user.h>
20
21
#if arch_has_single_step()
22
/* Both called from ptrace_resume */
23
void user_enable_single_step(struct task_struct *child)
24
{
25
pt_set_singlestep(task_pt_regs(child));
26
set_tsk_thread_flag(child, TIF_SINGLESTEP);
27
}
28
29
void user_disable_single_step(struct task_struct *child)
30
{
31
pt_clr_singlestep(task_pt_regs(child));
32
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
33
}
34
#endif
35
36
static int genregs_get(struct task_struct *target,
37
const struct user_regset *regset,
38
struct membuf to)
39
{
40
struct pt_regs *regs = task_pt_regs(target);
41
42
/* The general idea here is that the copyout must happen in
43
* exactly the same order in which the userspace expects these
44
* regs. Now, the sequence in userspace does not match the
45
* sequence in the kernel, so everything past the 32 gprs
46
* happens one at a time.
47
*/
48
membuf_write(&to, &regs->r00, 32*sizeof(unsigned long));
49
/* Must be exactly same sequence as struct user_regs_struct */
50
membuf_store(&to, regs->sa0);
51
membuf_store(&to, regs->lc0);
52
membuf_store(&to, regs->sa1);
53
membuf_store(&to, regs->lc1);
54
membuf_store(&to, regs->m0);
55
membuf_store(&to, regs->m1);
56
membuf_store(&to, regs->usr);
57
membuf_store(&to, regs->preds);
58
membuf_store(&to, regs->gp);
59
membuf_store(&to, regs->ugp);
60
membuf_store(&to, pt_elr(regs)); // pc
61
membuf_store(&to, (unsigned long)pt_cause(regs)); // cause
62
membuf_store(&to, pt_badva(regs)); // badva
63
#if CONFIG_HEXAGON_ARCH_VERSION >=4
64
membuf_store(&to, regs->cs0);
65
membuf_store(&to, regs->cs1);
66
return membuf_zero(&to, sizeof(unsigned long));
67
#else
68
return membuf_zero(&to, 3 * sizeof(unsigned long));
69
#endif
70
}
71
72
static int genregs_set(struct task_struct *target,
73
const struct user_regset *regset,
74
unsigned int pos, unsigned int count,
75
const void *kbuf, const void __user *ubuf)
76
{
77
int ret, ignore_offset;
78
unsigned long bucket;
79
struct pt_regs *regs = task_pt_regs(target);
80
81
if (!regs)
82
return -EIO;
83
84
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
85
&regs->r00, 0, 32*sizeof(unsigned long));
86
87
#define INEXT(KPT_REG, USR_REG) \
88
if (!ret) \
89
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
90
KPT_REG, offsetof(struct user_regs_struct, USR_REG), \
91
offsetof(struct user_regs_struct, USR_REG) + \
92
sizeof(unsigned long));
93
94
/* Must be exactly same sequence as struct user_regs_struct */
95
INEXT(&regs->sa0, sa0);
96
INEXT(&regs->lc0, lc0);
97
INEXT(&regs->sa1, sa1);
98
INEXT(&regs->lc1, lc1);
99
INEXT(&regs->m0, m0);
100
INEXT(&regs->m1, m1);
101
INEXT(&regs->usr, usr);
102
INEXT(&regs->preds, p3_0);
103
INEXT(&regs->gp, gp);
104
INEXT(&regs->ugp, ugp);
105
INEXT(&pt_elr(regs), pc);
106
107
/* CAUSE and BADVA aren't writeable. */
108
INEXT(&bucket, cause);
109
INEXT(&bucket, badva);
110
111
#if CONFIG_HEXAGON_ARCH_VERSION >=4
112
INEXT(&regs->cs0, cs0);
113
INEXT(&regs->cs1, cs1);
114
ignore_offset = offsetof(struct user_regs_struct, pad1);
115
#else
116
ignore_offset = offsetof(struct user_regs_struct, cs0);
117
#endif
118
119
/* Ignore the rest, if needed */
120
if (!ret)
121
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
122
ignore_offset, -1);
123
else
124
return ret;
125
126
/*
127
* This is special; SP is actually restored by the VM via the
128
* special event record which is set by the special trap.
129
*/
130
regs->hvmer.vmpsp = regs->r29;
131
return 0;
132
}
133
134
enum hexagon_regset {
135
REGSET_GENERAL,
136
};
137
138
static const struct user_regset hexagon_regsets[] = {
139
[REGSET_GENERAL] = {
140
USER_REGSET_NOTE_TYPE(PRSTATUS),
141
.n = ELF_NGREG,
142
.size = sizeof(unsigned long),
143
.align = sizeof(unsigned long),
144
.regset_get = genregs_get,
145
.set = genregs_set,
146
},
147
};
148
149
static const struct user_regset_view hexagon_user_view = {
150
.name = "hexagon",
151
.e_machine = ELF_ARCH,
152
.ei_osabi = ELF_OSABI,
153
.regsets = hexagon_regsets,
154
.e_flags = ELF_CORE_EFLAGS,
155
.n = ARRAY_SIZE(hexagon_regsets)
156
};
157
158
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
159
{
160
return &hexagon_user_view;
161
}
162
163
void ptrace_disable(struct task_struct *child)
164
{
165
/* Boilerplate - resolves to null inline if no HW single-step */
166
user_disable_single_step(child);
167
}
168
169
long arch_ptrace(struct task_struct *child, long request,
170
unsigned long addr, unsigned long data)
171
{
172
return ptrace_request(child, request, addr, data);
173
}
174
175