1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
13 #include <as-layout.h>
16 #include <ptrace_user.h>
17 #include <registers.h>
19 #include <sysdep/ptrace.h>
20 #include <sysdep/stub.h>
21 #include "../internal.h"
23 extern char __syscall_stub_start[];
25 void syscall_stub_dump_error(struct mm_id *mm_idp)
27 struct stub_data *proc_data = (void *)mm_idp->stack;
28 struct stub_syscall *sc;
30 if (proc_data->syscall_data_len < 0 ||
31 proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
32 panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
33 proc_data->syscall_data_len,
34 mm_idp->syscall_data_len);
36 sc = &proc_data->syscall_data[proc_data->syscall_data_len];
38 printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
39 __func__, mm_idp->syscall_data_len,
40 proc_data->syscall_data_len);
41 printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
42 __func__, sc->syscall, proc_data->err);
44 print_hex_dump(UM_KERN_ERR, " syscall data: ", 0,
45 16, 4, sc, sizeof(*sc), 0);
48 static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
52 stack = (unsigned long *) mm_idp->stack + 2;
58 static unsigned long syscall_regs[MAX_REG_NR];
60 static int __init init_syscall_regs(void)
62 get_safe_registers(syscall_regs, NULL);
64 syscall_regs[REGS_IP_INDEX] = STUB_CODE +
65 ((unsigned long) stub_syscall_handler -
66 (unsigned long) __syscall_stub_start);
67 syscall_regs[REGS_SP_INDEX] = STUB_DATA +
68 offsetof(struct stub_data, sigstack) +
69 sizeof(((struct stub_data *) 0)->sigstack) -
75 __initcall(init_syscall_regs);
77 static inline long do_syscall_stub(struct mm_id *mm_idp)
79 struct stub_data *proc_data = (void *)mm_idp->stack;
81 int err, pid = mm_idp->pid;
83 n = ptrace_setregs(pid, syscall_regs);
85 printk(UM_KERN_ERR "Registers - \n");
86 for (i = 0; i < MAX_REG_NR; i++)
87 printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]);
88 panic("%s : PTRACE_SETREGS failed, errno = %d\n",
92 /* Inform process how much we have filled in. */
93 proc_data->syscall_data_len = mm_idp->syscall_data_len;
95 err = ptrace(PTRACE_CONT, pid, 0, 0);
97 panic("Failed to continue stub, pid = %d, errno = %d\n", pid,
103 * proc_data->err will be non-zero if there was an (unexpected) error.
104 * In that case, syscall_data_len points to the last executed syscall,
105 * otherwise it will be zero (but we do not need to rely on that).
107 if (proc_data->err < 0) {
108 syscall_stub_dump_error(mm_idp);
110 /* Store error code in case someone tries to add more syscalls */
111 mm_idp->syscall_data_len = proc_data->err;
113 mm_idp->syscall_data_len = 0;
116 return mm_idp->syscall_data_len;
119 int syscall_stub_flush(struct mm_id *mm_idp)
123 if (mm_idp->syscall_data_len == 0)
126 /* If an error happened already, report it and reset the state. */
127 if (mm_idp->syscall_data_len < 0) {
128 res = mm_idp->syscall_data_len;
129 mm_idp->syscall_data_len = 0;
133 res = do_syscall_stub(mm_idp);
134 mm_idp->syscall_data_len = 0;
139 struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
141 struct stub_syscall *sc;
142 struct stub_data *proc_data = (struct stub_data *) mm_idp->stack;
144 if (mm_idp->syscall_data_len > 0 &&
145 mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data))
146 do_syscall_stub(mm_idp);
148 if (mm_idp->syscall_data_len < 0) {
149 /* Return dummy to retain error state. */
150 sc = &proc_data->syscall_data[0];
152 sc = &proc_data->syscall_data[mm_idp->syscall_data_len];
153 mm_idp->syscall_data_len += 1;
155 memset(sc, 0, sizeof(*sc));
160 static struct stub_syscall *syscall_stub_get_previous(struct mm_id *mm_idp,
164 if (mm_idp->syscall_data_len > 0) {
165 struct stub_data *proc_data = (void *) mm_idp->stack;
166 struct stub_syscall *sc;
168 sc = &proc_data->syscall_data[mm_idp->syscall_data_len - 1];
170 if (sc->syscall == syscall_type &&
171 sc->mem.addr + sc->mem.length == virt)
178 int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
179 int phys_fd, unsigned long long offset)
181 struct stub_syscall *sc;
183 /* Compress with previous syscall if that is possible */
184 sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MMAP, virt);
185 if (sc && sc->mem.prot == prot && sc->mem.fd == phys_fd &&
186 sc->mem.offset == MMAP_OFFSET(offset - sc->mem.length)) {
187 sc->mem.length += len;
191 sc = syscall_stub_alloc(mm_idp);
192 sc->syscall = STUB_SYSCALL_MMAP;
194 sc->mem.length = len;
196 sc->mem.fd = phys_fd;
197 sc->mem.offset = MMAP_OFFSET(offset);
202 int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
204 struct stub_syscall *sc;
206 /* Compress with previous syscall if that is possible */
207 sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MUNMAP, addr);
209 sc->mem.length += len;
213 sc = syscall_stub_alloc(mm_idp);
214 sc->syscall = STUB_SYSCALL_MUNMAP;
216 sc->mem.length = len;