Attaching the debugger to a running process should work again
(reported by Eric Pouech). Misc cleanups.
This commit is contained in:
parent
cb816d2c3f
commit
baf0a064db
|
@ -114,7 +114,7 @@ static inline int get_debug_reg( int pid, int num, DWORD *data )
|
||||||
/* retrieve a thread context */
|
/* retrieve a thread context */
|
||||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct kernel_user_regs_struct regs;
|
struct kernel_user_regs_struct regs;
|
||||||
|
@ -170,7 +170,7 @@ static void get_thread_context( struct thread *thread, unsigned int flags, CONTE
|
||||||
/* set a thread context */
|
/* set a thread context */
|
||||||
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct kernel_user_regs_struct regs;
|
struct kernel_user_regs_struct regs;
|
||||||
|
@ -230,7 +230,7 @@ static void set_thread_context( struct thread *thread, unsigned int flags, const
|
||||||
/* retrieve a thread context */
|
/* retrieve a thread context */
|
||||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct regs regs;
|
struct regs regs;
|
||||||
|
@ -281,7 +281,7 @@ static void get_thread_context( struct thread *thread, unsigned int flags, CONTE
|
||||||
/* set a thread context */
|
/* set a thread context */
|
||||||
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct regs regs;
|
struct regs regs;
|
||||||
|
@ -338,7 +338,7 @@ static void set_thread_context( struct thread *thread, unsigned int flags, const
|
||||||
/* retrieve a thread context */
|
/* retrieve a thread context */
|
||||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct reg regs;
|
struct reg regs;
|
||||||
|
@ -410,7 +410,7 @@ static void get_thread_context( struct thread *thread, unsigned int flags, CONTE
|
||||||
/* set a thread context */
|
/* set a thread context */
|
||||||
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct reg regs;
|
struct reg regs;
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
/* retrieve a thread context */
|
/* retrieve a thread context */
|
||||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
if (flags & CONTEXT_INTEGER)
|
if (flags & CONTEXT_INTEGER)
|
||||||
|
@ -117,7 +117,7 @@ static void get_thread_context( struct thread *thread, unsigned int flags, CONTE
|
||||||
/* set a thread context */
|
/* set a thread context */
|
||||||
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
if (flags & CONTEXT_INTEGER)
|
if (flags & CONTEXT_INTEGER)
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
/* retrieve a thread context */
|
/* retrieve a thread context */
|
||||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||||
{
|
{
|
||||||
int pid = thread->unix_pid;
|
int pid = get_ptrace_pid(thread);
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
struct regs regs;
|
struct regs regs;
|
||||||
|
|
|
@ -429,20 +429,13 @@ static int debugger_attach( struct process *process, struct thread *debugger )
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
suspend_process( process );
|
suspend_process( process );
|
||||||
|
if (!attach_process( process ) || !set_process_debugger( process, debugger ))
|
||||||
/* we must have been able to attach all threads */
|
|
||||||
if (!process->thread_list) goto error2;
|
|
||||||
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
|
||||||
{
|
{
|
||||||
if (!thread->attached) goto error2;
|
resume_process( process );
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (set_process_debugger( process, debugger )) return 1;
|
|
||||||
resume_process( process );
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error2:
|
|
||||||
resume_process( process );
|
|
||||||
error:
|
error:
|
||||||
set_error( STATUS_ACCESS_DENIED );
|
set_error( STATUS_ACCESS_DENIED );
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -452,7 +445,6 @@ static int debugger_attach( struct process *process, struct thread *debugger )
|
||||||
/* detach a process from a debugger thread (and resume it ?) */
|
/* detach a process from a debugger thread (and resume it ?) */
|
||||||
int debugger_detach( struct process *process, struct thread *debugger )
|
int debugger_detach( struct process *process, struct thread *debugger )
|
||||||
{
|
{
|
||||||
struct thread *thread;
|
|
||||||
struct debug_event *event;
|
struct debug_event *event;
|
||||||
struct debug_ctx *debug_ctx;
|
struct debug_ctx *debug_ctx;
|
||||||
|
|
||||||
|
@ -488,15 +480,7 @@ int debugger_detach( struct process *process, struct thread *debugger )
|
||||||
process->debugger = NULL;
|
process->debugger = NULL;
|
||||||
release_object( debugger->debug_ctx );
|
release_object( debugger->debug_ctx );
|
||||||
debugger->debug_ctx = NULL;
|
debugger->debug_ctx = NULL;
|
||||||
|
detach_process( process );
|
||||||
/* now detach all the threads */
|
|
||||||
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
|
||||||
{
|
|
||||||
if (thread->attached)
|
|
||||||
{
|
|
||||||
detach_thread( thread, 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* from this function */
|
/* from this function */
|
||||||
resume_process( process );
|
resume_process( process );
|
||||||
|
|
|
@ -85,7 +85,7 @@ struct startup_info
|
||||||
int inherit_all; /* inherit all handles from parent */
|
int inherit_all; /* inherit all handles from parent */
|
||||||
int use_handles; /* use stdio handles */
|
int use_handles; /* use stdio handles */
|
||||||
int create_flags; /* creation flags */
|
int create_flags; /* creation flags */
|
||||||
pid_t unix_pid; /* Unix pid of new process */
|
int unix_pid; /* Unix pid of new process */
|
||||||
obj_handle_t hstdin; /* handle for stdin */
|
obj_handle_t hstdin; /* handle for stdin */
|
||||||
obj_handle_t hstdout; /* handle for stdout */
|
obj_handle_t hstdout; /* handle for stdout */
|
||||||
obj_handle_t hstderr; /* handle for stderr */
|
obj_handle_t hstderr; /* handle for stderr */
|
||||||
|
@ -331,7 +331,7 @@ struct thread *create_process( int fd )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the startup info for a given Unix process */
|
/* find the startup info for a given Unix process */
|
||||||
inline static struct startup_info *find_startup_info( pid_t unix_pid )
|
inline static struct startup_info *find_startup_info( int unix_pid )
|
||||||
{
|
{
|
||||||
struct list *ptr;
|
struct list *ptr;
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ static void wait4_thread( struct thread *thread, int signal )
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
|
if ((res = wait4( get_ptrace_pid(thread), &status, WUNTRACED, NULL )) == -1)
|
||||||
{
|
{
|
||||||
if (errno == ECHILD) /* must have died */
|
if (errno == ECHILD) /* must have died */
|
||||||
{
|
{
|
||||||
|
@ -137,6 +137,12 @@ static void wait4_thread( struct thread *thread, int signal )
|
||||||
} while (res && res != signal);
|
} while (res && res != signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* return the Unix pid to use in ptrace calls for a given thread */
|
||||||
|
int get_ptrace_pid( struct thread *thread )
|
||||||
|
{
|
||||||
|
return thread->unix_pid;
|
||||||
|
}
|
||||||
|
|
||||||
/* send a Unix signal to a specific thread */
|
/* send a Unix signal to a specific thread */
|
||||||
int send_thread_signal( struct thread *thread, int sig )
|
int send_thread_signal( struct thread *thread, int sig )
|
||||||
{
|
{
|
||||||
|
@ -159,7 +165,7 @@ static int attach_thread( struct thread *thread )
|
||||||
{
|
{
|
||||||
/* this may fail if the client is already being debugged */
|
/* this may fail if the client is already being debugged */
|
||||||
if (!use_ptrace) return 0;
|
if (!use_ptrace) return 0;
|
||||||
if (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)
|
if (ptrace( PTRACE_ATTACH, get_ptrace_pid(thread), 0, 0 ) == -1)
|
||||||
{
|
{
|
||||||
if (errno == ESRCH) thread->unix_pid = -1; /* thread got killed */
|
if (errno == ESRCH) thread->unix_pid = -1; /* thread got killed */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -181,12 +187,43 @@ void detach_thread( struct thread *thread, int sig )
|
||||||
if (sig) send_thread_signal( thread, sig );
|
if (sig) send_thread_signal( thread, sig );
|
||||||
if (thread->unix_pid == -1) return;
|
if (thread->unix_pid == -1) return;
|
||||||
if (debug_level) fprintf( stderr, "%04x: *detached*\n", thread->id );
|
if (debug_level) fprintf( stderr, "%04x: *detached*\n", thread->id );
|
||||||
ptrace( PTRACE_DETACH, thread->unix_pid, (caddr_t)1, sig );
|
ptrace( PTRACE_DETACH, get_ptrace_pid(thread), (caddr_t)1, sig );
|
||||||
thread->attached = 0;
|
thread->attached = 0;
|
||||||
}
|
}
|
||||||
else if (sig) send_thread_signal( thread, sig );
|
else if (sig) send_thread_signal( thread, sig );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* attach to a Unix process with ptrace */
|
||||||
|
int attach_process( struct process *process )
|
||||||
|
{
|
||||||
|
struct thread *thread;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if (!process->thread_list) /* need at least one running thread */
|
||||||
|
{
|
||||||
|
set_error( STATUS_ACCESS_DENIED );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
||||||
|
{
|
||||||
|
if (thread->attached) continue;
|
||||||
|
if (suspend_for_ptrace( thread )) resume_after_ptrace( thread );
|
||||||
|
else ret = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* detach from a ptraced Unix process */
|
||||||
|
void detach_process( struct process *process )
|
||||||
|
{
|
||||||
|
struct thread *thread;
|
||||||
|
|
||||||
|
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
||||||
|
{
|
||||||
|
if (thread->attached) detach_thread( thread, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* suspend a thread to allow using ptrace on it */
|
/* suspend a thread to allow using ptrace on it */
|
||||||
/* you must do a resume_after_ptrace when finished with the thread */
|
/* you must do a resume_after_ptrace when finished with the thread */
|
||||||
int suspend_for_ptrace( struct thread *thread )
|
int suspend_for_ptrace( struct thread *thread )
|
||||||
|
@ -212,14 +249,14 @@ void resume_after_ptrace( struct thread *thread )
|
||||||
if (thread->unix_pid == -1) return;
|
if (thread->unix_pid == -1) return;
|
||||||
assert( thread->attached );
|
assert( thread->attached );
|
||||||
ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
|
ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
|
||||||
thread->unix_pid, (caddr_t)1, 0 /* cancel the SIGSTOP */ );
|
get_ptrace_pid(thread), (caddr_t)1, 0 /* cancel the SIGSTOP */ );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read an int from a thread address space */
|
/* read an int from a thread address space */
|
||||||
int read_thread_int( struct thread *thread, const int *addr, int *data )
|
int read_thread_int( struct thread *thread, const int *addr, int *data )
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
*data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, (caddr_t)addr, 0 );
|
*data = ptrace( PTRACE_PEEKDATA, get_ptrace_pid(thread), (caddr_t)addr, 0 );
|
||||||
if ( *data == -1 && errno)
|
if ( *data == -1 && errno)
|
||||||
{
|
{
|
||||||
file_set_error();
|
file_set_error();
|
||||||
|
@ -237,7 +274,7 @@ int write_thread_int( struct thread *thread, int *addr, int data, unsigned int m
|
||||||
if (read_thread_int( thread, addr, &res ) == -1) return -1;
|
if (read_thread_int( thread, addr, &res ) == -1) return -1;
|
||||||
data = (data & mask) | (res & ~mask);
|
data = (data & mask) | (res & ~mask);
|
||||||
}
|
}
|
||||||
if ((res = ptrace( PTRACE_POKEDATA, thread->unix_pid, (caddr_t)addr, data )) == -1)
|
if ((res = ptrace( PTRACE_POKEDATA, get_ptrace_pid(thread), (caddr_t)addr, data )) == -1)
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,10 @@ extern struct thread_snapshot *thread_snap( int *count );
|
||||||
/* ptrace functions */
|
/* ptrace functions */
|
||||||
|
|
||||||
extern void sigchld_handler();
|
extern void sigchld_handler();
|
||||||
|
extern int get_ptrace_pid( struct thread *thread );
|
||||||
extern void detach_thread( struct thread *thread, int sig );
|
extern void detach_thread( struct thread *thread, int sig );
|
||||||
|
extern int attach_process( struct process *process );
|
||||||
|
extern void detach_process( struct process *process );
|
||||||
extern int suspend_for_ptrace( struct thread *thread );
|
extern int suspend_for_ptrace( struct thread *thread );
|
||||||
extern void resume_after_ptrace( struct thread *thread );
|
extern void resume_after_ptrace( struct thread *thread );
|
||||||
extern int read_thread_int( struct thread *thread, const int *addr, int *data );
|
extern int read_thread_int( struct thread *thread, const int *addr, int *data );
|
||||||
|
|
Loading…
Reference in New Issue