lkml.org 
[lkml]   [2001]   [Dec]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] i386 extended ptrace
Hey,

This patch extends the ptrace system call by providing new requests
to trace memory differences made by system calls in a much cleaner way
than just to scan the entire user process memory area.
I think it's safe to merge with 2.4.17 because, when you don't enable it
in the config it won't compile into the kernel image. It would save me a
lot of time not to continually have to patch it against the latest
kernel my own; I've got other things to do.

Feedback is very welcome,
Frank.
diff -Nur linux-2.4.17/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.4.17/arch/i386/config.in Sat Dec 22 09:35:39 2001
+++ linux/arch/i386/config.in Tue Dec 25 18:36:25 2001
@@ -254,6 +254,9 @@
"ELF CONFIG_KCORE_ELF \
A.OUT CONFIG_KCORE_AOUT" ELF
fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Extended ptrace support (EXPERIMENTAL)' CONFIG_EXPTRACE
+fi
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
diff -Nur linux-2.4.17/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.17/Documentation/Configure.help Sat Dec 22 09:35:56 2001
+++ linux/Documentation/Configure.help Tue Dec 25 18:36:25 2001
@@ -3668,6 +3668,18 @@
Not necessary unless you're using a very out-of-date binutils
version. You probably want KCORE_ELF.

+Extended ptrace support
+CONFIG_EXPTRACE
+ This adds extra functionality to the ptrace system call in order
+ to be able to trace memory differences caused by system calls
+ much better. (i386 architecture only)
+ This causes little overhead on write accesses to the user memory
+ space since recording only takes place when tracing a process.
+ Note that enabling this option will enlarge the kernel image
+ with about 10 KB.
+
+ If in doubt, say N.
+
Kernel support for ELF binaries
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
diff -Nur linux-2.4.17/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- linux-2.4.17/include/asm-i386/processor.h Sat Dec 22 09:35:17 2001
+++ linux/include/asm-i386/processor.h Tue Dec 25 19:15:02 2001
@@ -362,6 +362,16 @@
unsigned long __cacheline_filler[5];
};

+/*
+ * We have to declare list_head here (again) because GCC
+ * only allows us to use a pointer to list_head here 'cause
+ * of cross-compilation between list.h and processor.h, and
+ * I really want a list_head struct, not a pointer to one.
+ */
+struct _list_head {
+ struct list_head *next, *prev;
+};
+
struct thread_struct {
unsigned long esp0;
unsigned long eip;
@@ -381,6 +391,12 @@
/* IO permissions */
int ioperm;
unsigned long io_bitmap[IO_BITMAP_SIZE+1];
+/* extended ptrace memdiff data */
+#if defined(CONFIG_EXPTRACE)
+ struct _list_head memdiff_list;
+ struct memdiff_struct *memdiff_nlist;
+ int memdiff_error;
+#endif
};

#define INIT_THREAD { \
diff -Nur linux-2.4.17/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h
--- linux-2.4.17/include/asm-i386/ptrace.h Sat Dec 22 09:35:17 2001
+++ linux/include/asm-i386/ptrace.h Tue Dec 25 23:52:34 2001
@@ -1,6 +1,8 @@
#ifndef _I386_PTRACE_H
#define _I386_PTRACE_H

+#include <linux/config.h>
+
#define EBX 0
#define ECX 1
#define EDX 2
@@ -51,13 +53,54 @@

#define PTRACE_SETOPTIONS 21

+#define PTRACE_RAWMEMDIFF 50
+#define PTRACE_DIFFMEM 51
+#define PTRACE_PATCHMEM 52
+
/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001

+#define MEMDIFF_ID__ANONYMOUS 0
+#define MEMDIFF_ID__PUT_USER_U64 1
+#define MEMDIFF_ID__PUT_USER_ASM 2
+#define MEMDIFF_ID__COPY_USER 3
+#define MEMDIFF_ID__CONSTANT_COPY_USER 4
+#define MEMDIFF_ID__DO_CLEAR_USER 5
+
+#if defined(CONFIG_EXPTRACE)
+extern void __record_memdiff(void *ptr, unsigned long size,
+ unsigned long id);
+#define record_memdiff(ptr, size, id) \
+do { \
+ if (current->ptrace & PT_PTRACED) \
+ __record_memdiff((ptr), (size), (id)); \
+} while (0)
+#else
+#define record_memdiff(ptr, size, id) do { } while (0)
+#endif
+
#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip)
extern void show_regs(struct pt_regs *);
-#endif
+
+#include <linux/list.h>
+
+struct memdiff_struct {
+ struct list_head list;
+ unsigned long begin_addr;
+ unsigned long size;
+ unsigned long id;
+};
+
+#if defined(CONFIG_EXPTRACE)
+void init_memdiff_lists(struct task_struct *task);
+void clear_memdiff_lists(struct task_struct *task);
+#else
+#define init_memdiff_lists(task) do { } while (0)
+#define clear_memdiff_lists(task) do { } while (0)
+#endif /* CONFIG_EXPTRACE */
+
+#endif /* __KERNEL__ */

#endif
diff -Nur linux-2.4.17/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- linux-2.4.17/arch/i386/kernel/ptrace.c Sat Dec 22 09:35:40 2001
+++ linux/arch/i386/kernel/ptrace.c Wed Dec 26 20:49:14 2001
@@ -3,6 +3,8 @@
/*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
+ * Extended ptrace support
+ * Frank Cornelis <Frank.Cornelis@elis.rug.ac.be>, December 2001
*/

#include <linux/kernel.h>
@@ -13,6 +15,8 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
+#include <linux/slab.h>
+#include <linux/config.h>

#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -21,6 +25,18 @@
#include <asm/i387.h>
#include <asm/debugreg.h>

+#undef PTRACE_DEBUG
+
+#ifdef PTRACE_DEBUG
+#define DEBUG(stuff...) do { \
+printk(KERN_DEBUG "ptrace_debug: current->pid = %d (%s)\n", \
+ current->pid, current->comm); \
+printk(KERN_DEBUG stuff); \
+} while (0)
+#else
+#define DEBUG(stuff...) do { } while (0)
+#endif
+
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
@@ -38,6 +54,251 @@
*/
#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))

+#if defined(CONFIG_EXPTRACE)
+static kmem_cache_t *memdiff_cachep;
+
+static int __init memdiff_cache_init(void)
+{
+ memdiff_cachep = kmem_cache_create("memdiff_cache",
+ sizeof(struct memdiff_struct),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!memdiff_cachep)
+ panic("memdiff_cache: Couldn't alloc memory.");
+ return 0;
+}
+__initcall(memdiff_cache_init);
+
+static inline struct memdiff_struct *memdiff_alloc(struct task_struct *task)
+{
+ struct memdiff_struct *memdiff;
+ memdiff = kmem_cache_alloc(memdiff_cachep, SLAB_KERNEL);
+ if (!memdiff) {
+ printk(KERN_CRIT "memdiff_cache: out of memory\n");
+ task->thread.memdiff_error = -ENOMEM;
+ }
+ return memdiff;
+}
+
+static inline void copy_memdiff_record(struct memdiff_struct *dest,
+ struct memdiff_struct *src)
+{
+ if (!dest || !src)
+ return;
+ dest->begin_addr = src->begin_addr;
+ dest->size = src->size;
+ dest->id = src->id;
+}
+
+/*
+ * Builds the memdiff record and adds it to the memdiff_list of
+ * the current process.
+ */
+void __record_memdiff(void *ptr, unsigned long size,
+ unsigned long id)
+{
+ struct memdiff_struct *memdiff;
+ memdiff = memdiff_alloc(current);
+ if (!memdiff)
+ return;
+ memdiff->begin_addr = (unsigned long)ptr;
+ memdiff->size = size;
+ memdiff->id = id;
+ list_add_tail(&memdiff->list,
+ (struct list_head *)&current->thread.memdiff_list);
+}
+
+/*
+ * Next code also gets invoked by process.c:copy_thread
+ */
+void init_memdiff_lists(struct task_struct *task)
+{
+ DEBUG("init_memdiff_lists called\n");
+ INIT_LIST_HEAD((struct list_head *)&task->thread.memdiff_list);
+ task->thread.memdiff_nlist = NULL;
+ task->thread.memdiff_error = 0;
+}
+
+/*
+ * Clears the memdiff lists (the raw and normalized one) of the
+ * given process.
+ * Next code also gets invoked by process.c:exit_thread
+ */
+void clear_memdiff_lists(struct task_struct *task)
+{
+ struct list_head *cache_obj, *head;
+ /* clear the raw memdiff list */
+ head = (struct list_head *)&task->thread.memdiff_list;
+ cache_obj = head->next;
+ while (cache_obj != head) {
+ struct list_head *kill_me;
+ kill_me = cache_obj;
+ cache_obj = cache_obj->next;
+ kmem_cache_free(memdiff_cachep, kill_me);
+ }
+ /* clear the (double linked) normalized memdiff list */
+ head = &task->thread.memdiff_nlist->list;
+ if (head)
+ cache_obj = head->next;
+ else
+ cache_obj = NULL;
+ while (cache_obj != head) {
+ struct list_head *kill_me;
+ kill_me = cache_obj;
+ cache_obj = cache_obj->next;
+ kmem_cache_free(memdiff_cachep, kill_me);
+ }
+ if (head)
+ kmem_cache_free(memdiff_cachep, head);
+ init_memdiff_lists(task);
+}
+
+/*
+ * Next function constructs the normalized memdiff list
+ * using the information from the raw memdiff list.
+ */
+static void normalize(struct task_struct *task)
+{
+ struct memdiff_struct *nlist, *curr_entry, *next_entry;
+ struct list_head *tmp, *curr, *next;
+ if (task->thread.memdiff_nlist)
+ return; /* already normalized */
+ if (!(nlist = memdiff_alloc(task)))
+ return;
+ /* first 'insertion sort' the raw memdiffs into the normalized list */
+ INIT_LIST_HEAD(&nlist->list);
+ list_for_each(tmp, (struct list_head *)&task->thread.memdiff_list) {
+ struct memdiff_struct *raw_entry;
+ struct list_head *ntmp;
+ raw_entry = list_entry(tmp, struct memdiff_struct, list);
+ list_for_each_prev(ntmp, &nlist->list) {
+ struct memdiff_struct *n_entry;
+ n_entry = list_entry(ntmp, struct memdiff_struct, list);
+ if (n_entry->begin_addr < raw_entry->begin_addr) {
+ struct memdiff_struct *new;
+ if (!(new = memdiff_alloc(task)))
+ return;
+ copy_memdiff_record(new, raw_entry);
+ raw_entry = NULL;
+ list_add(&new->list, &n_entry->list);
+ break;
+ }
+ }
+ if (raw_entry) {
+ struct memdiff_struct *new;
+ if (!(new = memdiff_alloc(task)))
+ return;
+ copy_memdiff_record(new, raw_entry);
+ list_add(&new->list, &nlist->list);
+ }
+ }
+ /* now normalize the already sorted nlist */
+ curr = nlist->list.next;
+ next = curr->next;
+ while (next != &nlist->list) {
+ curr_entry = list_entry(curr, struct memdiff_struct, list);
+ next_entry = list_entry(next, struct memdiff_struct, list);
+ if (curr_entry->begin_addr + curr_entry->size >= next_entry->begin_addr) {
+ curr_entry->size = next_entry->begin_addr + next_entry->size
+ - curr_entry->begin_addr;
+ list_del(next);
+ kmem_cache_free(memdiff_cachep, next);
+ next = curr->next;
+ continue;
+ }
+ curr = curr->next;
+ next = curr->next;
+ }
+ task->thread.memdiff_nlist = nlist;
+}
+
+static inline int count_memdiffs(struct list_head *list)
+{
+ int count = 0;
+ struct list_head *tmp;
+ list_for_each(tmp, list)
+ count++;
+ return count;
+}
+
+static int count_raw_writes(struct task_struct *task)
+{
+ return count_memdiffs((struct list_head *)&task->thread.memdiff_list);
+}
+
+static int count_normalized_writes(struct task_struct *task)
+{
+ if (!task->thread.memdiff_nlist)
+ return 0;
+ return count_memdiffs((struct list_head *)&task->thread.memdiff_nlist->list);
+}
+
+static unsigned long get_raw_record_size(struct task_struct *task)
+{
+ unsigned long size = 0;
+ struct list_head *list, *tmp;
+ list = (struct list_head *)&task->thread.memdiff_list;
+ size += sizeof(unsigned long);
+ list_for_each(tmp, list) {
+ size += 3 * sizeof(unsigned long);
+ size += list_entry(tmp, struct memdiff_struct, list)->size;
+ }
+ return size;
+}
+
+static void write_raw_record(struct task_struct *task, long ptr)
+{
+ struct list_head *list, *tmp;
+ __put_user(count_raw_writes(task), ((unsigned long *)ptr)++);
+ list = (struct list_head *)&task->thread.memdiff_list;
+ list_for_each(tmp, list) {
+ struct memdiff_struct *memdiff;
+ memdiff = list_entry(tmp, struct memdiff_struct, list);
+ __put_user(memdiff->begin_addr, ((unsigned long *)ptr)++);
+ __put_user(memdiff->id, ((unsigned long *)ptr)++);
+ __put_user(memdiff->size, ((unsigned long *)ptr)++);
+ if (ptrace_readdata(task, memdiff->begin_addr,
+ (char *)ptr, memdiff->size) < 0)
+ printk(KERN_CRIT "write_raw_record: readdata error\n");
+ ptr += memdiff->size;
+ }
+}
+
+static unsigned long get_normalized_record_size(struct task_struct *task)
+{
+ unsigned long size = 0;
+ struct list_head *list, *tmp;
+ if (!task->thread.memdiff_nlist)
+ return 0;
+ list = (struct list_head *)&task->thread.memdiff_nlist->list;
+ size += sizeof(unsigned long);
+ list_for_each(tmp, list) {
+ size += 2 * sizeof(unsigned long);
+ size += list_entry(tmp, struct memdiff_struct, list)->size;
+ }
+ return size;
+}
+
+static void write_normalized_record(struct task_struct *task, long ptr)
+{
+ struct list_head *list, *tmp;
+ __put_user(count_normalized_writes(task), ((unsigned long *)ptr)++);
+ if (!task->thread.memdiff_nlist)
+ return;
+ list = (struct list_head *)&task->thread.memdiff_nlist->list;
+ list_for_each(tmp, list) {
+ struct memdiff_struct *memdiff;
+ memdiff = list_entry(tmp, struct memdiff_struct, list);
+ __put_user(memdiff->begin_addr, ((unsigned long *)ptr)++);
+ __put_user(memdiff->size, ((unsigned long *)ptr)++);
+ if (ptrace_readdata(task, memdiff->begin_addr,
+ (char *)ptr, memdiff->size) < 0)
+ printk(KERN_CRIT "write_normalized_record: readdata error\n");
+ ptr += memdiff->size;
+ }
+}
+#endif /* CONFIG_EXPTRACE */
+
/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the TSS.
@@ -161,6 +422,7 @@
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
+ clear_memdiff_lists(current);
ret = 0;
goto out;
}
@@ -179,6 +441,7 @@

if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child);
+ clear_memdiff_lists(child);
goto out_tsk;
}

@@ -282,7 +545,8 @@
else
child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
- /* make sure the single step bit is not set. */
+ clear_memdiff_lists(child);
+ /* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET,tmp);
wake_up_process(child);
@@ -305,6 +569,7 @@
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
+ clear_memdiff_lists(child);
wake_up_process(child);
break;
}
@@ -323,6 +588,7 @@
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
child->exit_code = data;
+ clear_memdiff_lists(child);
/* give it a chance to run. */
wake_up_process(child);
ret = 0;
@@ -331,6 +597,7 @@

case PTRACE_DETACH:
/* detach a process that was attached. */
+ clear_memdiff_lists(child);
ret = ptrace_detach(child, data);
break;

@@ -428,6 +695,91 @@
break;
}

+#if defined(CONFIG_EXPTRACE)
+ /*
+ * RAWMEMDIFF: Returns the number of raw writes.
+ * When addr!=NULL it writes the size of the
+ * raw memdiff record to addr.
+ * When data!=NULL it writes the raw memdiff
+ * record to data.
+ */
+ case PTRACE_RAWMEMDIFF: {
+ unsigned long record_size;
+ ret = -EIO;
+ if (child->thread.memdiff_error)
+ break;
+ if (addr && !access_ok(VERIFY_WRITE, (unsigned *)addr, sizeof(unsigned long)))
+ break;
+ record_size = get_raw_record_size(child);
+ if (data && !access_ok(VERIFY_WRITE, (unsigned *)data, record_size))
+ break;
+ if (addr)
+ __put_user(record_size, (unsigned long *)addr);
+ if (data)
+ write_raw_record(child, data);
+ ret = count_raw_writes(child);
+ break;
+ }
+
+ /*
+ * DIFFMEM: Returns the number of normalized writes.
+ * When addr!=NULL it writes the size of the normalized
+ * memdiff record to addr.
+ * When data!=NULL it writes the normalized memdiff
+ * record to data.
+ */
+ case PTRACE_DIFFMEM: {
+ unsigned long record_size;
+ ret = -EIO;
+ normalize(child);
+ if (child->thread.memdiff_error)
+ break;
+ if (addr && !access_ok(VERIFY_WRITE, (unsigned *)addr, sizeof(unsigned long)))
+ break;
+ record_size = get_normalized_record_size(child);
+ if (data && !access_ok(VERIFY_WRITE, (unsigned *)data, record_size))
+ break;
+ if (addr)
+ __put_user(record_size, (unsigned long *)addr);
+ if (data)
+ write_normalized_record(child, data);
+ ret = count_normalized_writes(child);
+ break;
+ }
+
+ /*
+ * PATCHMEM: Applies a (normalized) memdiff record
+ * given by addr to the child memory space.
+ * Return the number of bytes written to the child
+ * memory.
+ */
+ case PTRACE_PATCHMEM: {
+ unsigned long nrecords, nwritten = 0;
+ ret = -EIO;
+ if (!addr)
+ break;
+ if (!access_ok(VERIFY_READ, (unsigned *)addr, sizeof(unsigned long)))
+ break;
+ __get_user(nrecords, ((unsigned long *)addr)++);
+ while (nrecords) {
+ unsigned long begin_addr, size;
+ if (!access_ok(VERIFY_READ, addr, 2 * sizeof(unsigned long)))
+ goto out_tsk;
+ __get_user(begin_addr, ((unsigned long *)addr)++);
+ __get_user(size, ((unsigned long *)addr)++);
+ if (!access_ok(VERIFY_READ, addr, size))
+ goto out_tsk;
+ if (ptrace_writedata(child, (char *)addr, begin_addr, size) < 0)
+ goto out_tsk;
+ nwritten += size;
+ addr += size;
+ nrecords--;
+ }
+ ret = nwritten;
+ break;
+ }
+#endif /* CONFIG_EXPTRACE */
+
default:
ret = -EIO;
break;
diff -Nur linux-2.4.17/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux-2.4.17/arch/i386/kernel/process.c Sat Dec 22 09:35:40 2001
+++ linux/arch/i386/kernel/process.c Wed Dec 26 20:55:01 2001
@@ -515,7 +515,7 @@
*/
void exit_thread(void)
{
- /* nothing to do ... */
+ clear_memdiff_lists(current);
}

void flush_thread(void)
@@ -597,6 +597,8 @@
unlazy_fpu(current);
struct_cpy(&p->thread.i387, &current->thread.i387);

+ init_memdiff_lists(p);
+
return 0;
}

diff -Nur linux-2.4.17/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- linux-2.4.17/include/asm-i386/uaccess.h Sat Dec 22 09:35:17 2001
+++ linux/include/asm-i386/uaccess.h Wed Dec 26 20:53:23 2001
@@ -8,6 +8,7 @@
#include <linux/sched.h>
#include <linux/prefetch.h>
#include <asm/page.h>
+#include <asm/ptrace.h>

#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -157,6 +158,10 @@
})

#define __put_user_u64(x, addr, err) \
+do { \
+ __typeof__(*(addr)) *__puu64_addr = (addr); \
+ record_memdiff(__puu64_addr, 8, \
+ MEMDIFF_ID__PUT_USER_U64); \
__asm__ __volatile__( \
"1: movl %%eax,0(%2)\n" \
"2: movl %%edx,4(%2)\n" \
@@ -171,7 +176,8 @@
" .long 2b,4b\n" \
".previous" \
: "=r"(err) \
- : "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
+ : "A" (x), "r" (__puu64_addr), "i"(-EFAULT), "0"(err)); \
+} while (0)

#define __put_user_size(x,ptr,size,retval) \
do { \
@@ -194,6 +200,10 @@
* aliasing issues.
*/
#define __put_user_asm(x, addr, err, itype, rtype, ltype) \
+do { \
+ __typeof__(*(addr)) *__pua_addr = (addr); \
+ record_memdiff(__pua_addr, sizeof(*__pua_addr), \
+ MEMDIFF_ID__PUT_USER_ASM); \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
@@ -206,7 +216,8 @@
" .long 1b,3b\n" \
".previous" \
: "=r"(err) \
- : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+ : ltype (x), "m"(__m(__pua_addr)), "i"(-EFAULT), "0"(err)); \
+} while (0)


#define __get_user_nocheck(x,ptr,size) \
@@ -255,6 +266,7 @@
#define __copy_user(to,from,size) \
do { \
int __d0, __d1; \
+ record_memdiff((to), (size), MEMDIFF_ID__COPY_USER); \
__asm__ __volatile__( \
"0: rep; movsl\n" \
" movl %3,%0\n" \
@@ -324,6 +336,8 @@
#define __constant_copy_user(to, from, size) \
do { \
int __d0, __d1; \
+ record_memdiff((to), (size), \
+ MEMDIFF_ID__CONSTANT_COPY_USER); \
switch (size & 3) { \
default: \
__asm__ __volatile__( \
diff -Nur linux-2.4.17/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c
--- linux-2.4.17/arch/i386/lib/usercopy.c Sat Dec 22 09:35:40 2001
+++ linux/arch/i386/lib/usercopy.c Tue Dec 25 18:36:25 2001
@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <asm/uaccess.h>
#include <asm/mmx.h>
+#include <asm/ptrace.h>

#ifdef CONFIG_X86_USE_3DNOW_AND_WORKS

@@ -120,6 +121,7 @@
#define __do_clear_user(addr,size) \
do { \
int __d0; \
+ record_memdiff((addr), (size), MEMDIFF_ID__DO_CLEAR_USER); \
__asm__ __volatile__( \
"0: rep; stosl\n" \
" movl %2,%0\n" \
diff -Nur linux-2.4.17/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.17/arch/i386/kernel/i386_ksyms.c Sat Dec 22 09:35:40 2001
+++ linux/arch/i386/kernel/i386_ksyms.c Tue Dec 25 18:36:25 2001
@@ -28,6 +28,7 @@
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/ptrace.h>

extern void dump_thread(struct pt_regs *, struct user *);
extern spinlock_t rtc_lock;
@@ -173,3 +174,7 @@

extern int is_sony_vaio_laptop;
EXPORT_SYMBOL(is_sony_vaio_laptop);
+
+#if defined(CONFIG_EXPTRACE)
+EXPORT_SYMBOL_NOVERS(__record_memdiff);
+#endif
\
 
 \ /
  Last update: 2005-03-22 13:14    [W:0.057 / U:0.156 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site