[PATCH] C99 designated initializers for arch/sh
[linux-2.6/history.git] / kernel / ptrace.c
blobcc7a76bb65b7b87b053f8ac003b192a03a920891
1 /*
2 * linux/kernel/ptrace.c
4 * (C) Copyright 1999 Linus Torvalds
6 * Common interfaces for "ptrace()" which we do not want
7 * to continually duplicate across every architecture.
8 */
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/mm.h>
13 #include <linux/highmem.h>
14 #include <linux/pagemap.h>
15 #include <linux/smp_lock.h>
16 #include <linux/ptrace.h>
18 #include <asm/pgtable.h>
19 #include <asm/uaccess.h>
22 * ptrace a task: make the debugger its new parent and
23 * move it to the ptrace list.
25 * Must be called with the tasklist lock write-held.
27 void __ptrace_link(task_t *child, task_t *new_parent)
29 if (!list_empty(&child->ptrace_list))
30 BUG();
31 if (child->parent == new_parent)
32 return;
33 list_add(&child->ptrace_list, &child->parent->ptrace_children);
34 REMOVE_LINKS(child);
35 child->parent = new_parent;
36 SET_LINKS(child);
40 * unptrace a task: move it back to its original parent and
41 * remove it from the ptrace list.
43 * Must be called with the tasklist lock write-held.
45 void __ptrace_unlink(task_t *child)
47 if (!child->ptrace)
48 BUG();
49 child->ptrace = 0;
50 if (list_empty(&child->ptrace_list))
51 return;
52 list_del_init(&child->ptrace_list);
53 REMOVE_LINKS(child);
54 child->parent = child->real_parent;
55 SET_LINKS(child);
59 * Check that we have indeed attached to the thing..
61 int ptrace_check_attach(struct task_struct *child, int kill)
63 if (!(child->ptrace & PT_PTRACED))
64 return -ESRCH;
66 if (child->parent != current)
67 return -ESRCH;
69 if (!kill) {
70 if (child->state != TASK_STOPPED)
71 return -ESRCH;
72 wait_task_inactive(child);
75 /* All systems go.. */
76 return 0;
79 int ptrace_attach(struct task_struct *task)
81 int retval;
82 task_lock(task);
83 retval = -EPERM;
84 if (task->pid <= 1)
85 goto bad;
86 if (task == current)
87 goto bad;
88 if (!task->mm)
89 goto bad;
90 if(((current->uid != task->euid) ||
91 (current->uid != task->suid) ||
92 (current->uid != task->uid) ||
93 (current->gid != task->egid) ||
94 (current->gid != task->sgid) ||
95 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
96 goto bad;
97 rmb();
98 if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
99 goto bad;
100 /* the same process cannot be attached many times */
101 if (task->ptrace & PT_PTRACED)
102 goto bad;
103 retval = security_ops->ptrace(current, task);
104 if (retval)
105 goto bad;
107 /* Go */
108 task->ptrace |= PT_PTRACED;
109 if (capable(CAP_SYS_PTRACE))
110 task->ptrace |= PT_PTRACE_CAP;
111 task_unlock(task);
113 write_lock_irq(&tasklist_lock);
114 __ptrace_link(task, current);
115 write_unlock_irq(&tasklist_lock);
117 send_sig(SIGSTOP, task, 1);
118 return 0;
120 bad:
121 task_unlock(task);
122 return retval;
125 int ptrace_detach(struct task_struct *child, unsigned int data)
127 if ((unsigned long) data > _NSIG)
128 return -EIO;
130 /* Architecture-specific hardware disable .. */
131 ptrace_disable(child);
133 /* .. re-parent .. */
134 child->exit_code = data;
136 write_lock_irq(&tasklist_lock);
137 __ptrace_unlink(child);
138 /* .. and wake it up. */
139 if (child->state != TASK_ZOMBIE)
140 wake_up_process(child);
141 write_unlock_irq(&tasklist_lock);
143 return 0;
147 * Access another process' address space.
148 * Source/target buffer must be kernel space,
149 * Do not walk the page table directly, use get_user_pages
152 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
154 struct mm_struct *mm;
155 struct vm_area_struct *vma;
156 struct page *page;
157 void *old_buf = buf;
159 mm = get_task_mm(tsk);
160 if (!mm)
161 return 0;
163 down_read(&mm->mmap_sem);
164 /* ignore errors, just check how much was sucessfully transfered */
165 while (len) {
166 int bytes, ret, offset;
167 void *maddr;
169 ret = get_user_pages(current, mm, addr, 1,
170 write, 1, &page, &vma);
171 if (ret <= 0)
172 break;
174 bytes = len;
175 offset = addr & (PAGE_SIZE-1);
176 if (bytes > PAGE_SIZE-offset)
177 bytes = PAGE_SIZE-offset;
179 flush_cache_page(vma, addr);
181 maddr = kmap(page);
182 if (write) {
183 memcpy(maddr + offset, buf, bytes);
184 flush_page_to_ram(page);
185 flush_icache_user_range(vma, page, addr, bytes);
186 } else {
187 memcpy(buf, maddr + offset, bytes);
188 flush_page_to_ram(page);
190 kunmap(page);
191 page_cache_release(page);
192 len -= bytes;
193 buf += bytes;
194 addr += bytes;
196 up_read(&mm->mmap_sem);
197 mmput(mm);
199 return buf - old_buf;
202 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
204 int copied = 0;
206 while (len > 0) {
207 char buf[128];
208 int this_len, retval;
210 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
211 retval = access_process_vm(tsk, src, buf, this_len, 0);
212 if (!retval) {
213 if (copied)
214 break;
215 return -EIO;
217 if (copy_to_user(dst, buf, retval))
218 return -EFAULT;
219 copied += retval;
220 src += retval;
221 dst += retval;
222 len -= retval;
224 return copied;
227 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
229 int copied = 0;
231 while (len > 0) {
232 char buf[128];
233 int this_len, retval;
235 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
236 if (copy_from_user(buf, src, this_len))
237 return -EFAULT;
238 retval = access_process_vm(tsk, dst, buf, this_len, 1);
239 if (!retval) {
240 if (copied)
241 break;
242 return -EIO;
244 copied += retval;
245 src += retval;
246 dst += retval;
247 len -= retval;
249 return copied;