diff options
| author | Roland McGrath <roland@redhat.com> | 2003-01-12 04:02:53 -0800 |
|---|---|---|
| committer | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2003-01-12 04:02:53 -0800 |
| commit | 0905db3912fff7d3b2656b1bd1ca4f1b0e4b27ca (patch) | |
| tree | 51d181958baf10244be635172604c29bd880d76e | |
| parent | bb8ffa8a08646e346057d5284d878829d0be80ea (diff) | |
[PATCH] PTRACE_GET_THREAD_AREA
Add ptrace support for getting and setting the THREAD_AREA of the
thread being debugged on x86.
| -rw-r--r-- | arch/i386/kernel/ptrace.c | 91 | ||||
| -rw-r--r-- | include/asm-i386/ptrace.h | 3 |
2 files changed, 94 insertions, 0 deletions
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index c471cfb27070..951717d62f17 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -21,6 +21,8 @@ #include <asm/processor.h> #include <asm/i387.h> #include <asm/debugreg.h> +#include <asm/ldt.h> +#include <asm/desc.h> /* * does not yet catch signals sent when the child dies. @@ -148,6 +150,85 @@ void ptrace_disable(struct task_struct *child) put_stack_long(child, EFL_OFFSET, tmp); } +/* + * Perform get_thread_area on behalf of the traced child. + */ +static int +ptrace_get_thread_area(struct task_struct *child, + int idx, struct user_desc *user_desc) +{ + struct user_desc info; + struct desc_struct *desc; + +/* + * Get the current Thread-Local Storage area: + */ + +#define GET_BASE(desc) ( \ + (((desc)->a >> 16) & 0x0000ffff) | \ + (((desc)->b << 16) & 0x00ff0000) | \ + ( (desc)->b & 0xff000000) ) + +#define GET_LIMIT(desc) ( \ + ((desc)->a & 0x0ffff) | \ + ((desc)->b & 0xf0000) ) + +#define GET_32BIT(desc) (((desc)->b >> 23) & 1) +#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) +#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) +#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) +#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) +#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + + info.entry_number = idx; + info.base_addr = GET_BASE(desc); + info.limit = GET_LIMIT(desc); + info.seg_32bit = GET_32BIT(desc); + info.contents = GET_CONTENTS(desc); + info.read_exec_only = !GET_WRITABLE(desc); + info.limit_in_pages = GET_LIMIT_PAGES(desc); + info.seg_not_present = !GET_PRESENT(desc); + info.useable = GET_USEABLE(desc); + + if (copy_to_user(user_desc, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +/* + * Perform set_thread_area on behalf of the traced child. + */ +static int +ptrace_set_thread_area(struct task_struct *child, + int idx, struct user_desc *user_desc) +{ + struct user_desc info; + struct desc_struct *desc; + + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + if (LDT_empty(&info)) { + desc->a = 0; + desc->b = 0; + } else { + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + + return 0; +} + asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -416,6 +497,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; } + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, + addr, (struct user_desc *) data); + break; + + case PTRACE_SET_THREAD_AREA: + ret = ptrace_set_thread_area(child, + addr, (struct user_desc *) data); + break; + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h index e6d24421aa63..d80fd6557d05 100644 --- a/include/asm-i386/ptrace.h +++ b/include/asm-i386/ptrace.h @@ -51,6 +51,9 @@ struct pt_regs { #define PTRACE_OLDSETOPTIONS 21 +#define PTRACE_GET_THREAD_AREA 25 +#define PTRACE_SET_THREAD_AREA 26 + #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) |
