Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
wine
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Package registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jacob Pfeiffer
wine
Commits
578c1009
Commit
578c1009
authored
25 years ago
by
Alexandre Julliard
Browse files
Options
Downloads
Patches
Plain Diff
Moved ptrace support to ptrace.c. Tried to improve portability.
parent
3b832225
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
server/Makefile.in
+1
-0
1 addition, 0 deletions
server/Makefile.in
server/process.c
+8
-34
8 additions, 34 deletions
server/process.c
server/ptrace.c
+164
-0
164 additions, 0 deletions
server/ptrace.c
server/thread.c
+8
-112
8 additions, 112 deletions
server/thread.c
server/thread.h
+11
-3
11 additions, 3 deletions
server/thread.h
with
192 additions
and
149 deletions
server/Makefile.in
+
1
−
0
View file @
578c1009
...
...
@@ -18,6 +18,7 @@ C_SRCS = \
object.c
\
pipe.c
\
process.c
\
ptrace.c
\
request.c
\
snapshot.c
\
select
.c
\
...
...
This diff is collapsed.
Click to expand it.
server/process.c
+
8
−
34
View file @
578c1009
...
...
@@ -316,30 +316,6 @@ static void set_process_info( struct process *process,
}
}
/* wrapper for reading an int with ptrace */
static
inline
int
read_word
(
int
pid
,
const
int
*
addr
,
int
*
data
)
{
if
(((
*
data
=
ptrace
(
PT_READ_D
,
pid
,
addr
))
==
-
1
)
&&
errno
)
{
file_set_error
();
return
-
1
;
}
return
0
;
}
/* wrapper for writing an int with ptrace */
static
inline
int
write_word
(
int
pid
,
int
*
addr
,
int
data
,
unsigned
int
mask
)
{
int
res
;
if
(
mask
!=
~
0
)
{
if
(
read_word
(
pid
,
addr
,
&
res
)
==
-
1
)
return
-
1
;
data
=
(
data
&
mask
)
|
(
res
&
~
mask
);
}
if
((
res
=
ptrace
(
PT_WRITE_D
,
pid
,
addr
,
data
))
==
-
1
)
file_set_error
();
return
res
;
}
/* read data from a process memory space */
/* len is the total size (in ints), max is the size we can actually store in the output buffer */
/* we read the total size in all cases to check for permissions */
...
...
@@ -347,7 +323,6 @@ static void read_process_memory( struct process *process, const int *addr,
size_t
len
,
size_t
max
,
int
*
dest
)
{
struct
thread
*
thread
=
process
->
thread_list
;
int
pid
=
thread
->
unix_pid
;
if
((
unsigned
int
)
addr
%
sizeof
(
int
))
/* address must be aligned */
{
...
...
@@ -359,7 +334,7 @@ static void read_process_memory( struct process *process, const int *addr,
{
while
(
len
>
0
&&
max
)
{
if
(
read_
word
(
pi
d
,
addr
++
,
dest
++
)
==
-
1
)
goto
done
;
if
(
read_
thread_int
(
threa
d
,
addr
++
,
dest
++
)
==
-
1
)
goto
done
;
max
--
;
len
--
;
}
...
...
@@ -371,9 +346,9 @@ static void read_process_memory( struct process *process, const int *addr,
{
addr
+=
page
;
len
-=
page
;
if
(
read_
word
(
pi
d
,
addr
-
1
,
&
dummy
)
==
-
1
)
goto
done
;
if
(
read_
thread_int
(
threa
d
,
addr
-
1
,
&
dummy
)
==
-
1
)
goto
done
;
}
if
(
len
&&
(
read_
word
(
pi
d
,
addr
+
len
-
1
,
&
dummy
)
==
-
1
))
goto
done
;
if
(
len
&&
(
read_
thread_int
(
threa
d
,
addr
+
len
-
1
,
&
dummy
)
==
-
1
))
goto
done
;
}
}
else
set_error
(
ERROR_ACCESS_DENIED
);
...
...
@@ -389,7 +364,6 @@ static void write_process_memory( struct process *process, int *addr, size_t len
unsigned
int
last_mask
,
const
int
*
src
)
{
struct
thread
*
thread
=
process
->
thread_list
;
int
pid
=
thread
->
unix_pid
;
if
(
!
len
||
((
unsigned
int
)
addr
%
sizeof
(
int
)))
/* address must be aligned */
{
...
...
@@ -402,7 +376,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
/* first word is special */
if
(
len
>
1
)
{
if
(
write_
word
(
pi
d
,
addr
++
,
*
src
++
,
first_mask
)
==
-
1
)
goto
done
;
if
(
write_
thread_int
(
threa
d
,
addr
++
,
*
src
++
,
first_mask
)
==
-
1
)
goto
done
;
len
--
;
max
--
;
}
...
...
@@ -410,7 +384,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
while
(
len
>
1
&&
max
)
{
if
(
write_
word
(
pi
d
,
addr
++
,
*
src
++
,
~
0
)
==
-
1
)
goto
done
;
if
(
write_
thread_int
(
threa
d
,
addr
++
,
*
src
++
,
~
0
)
==
-
1
)
goto
done
;
max
--
;
len
--
;
}
...
...
@@ -418,7 +392,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
if
(
max
)
{
/* last word is special too */
if
(
write_
word
(
pi
d
,
addr
,
*
src
,
last_mask
)
==
-
1
)
goto
done
;
if
(
write_
thread_int
(
threa
d
,
addr
,
*
src
,
last_mask
)
==
-
1
)
goto
done
;
}
else
{
...
...
@@ -428,9 +402,9 @@ static void write_process_memory( struct process *process, int *addr, size_t len
{
addr
+=
page
;
len
-=
page
;
if
(
write_
word
(
pi
d
,
addr
-
1
,
0
,
0
)
==
-
1
)
goto
done
;
if
(
write_
thread_int
(
threa
d
,
addr
-
1
,
0
,
0
)
==
-
1
)
goto
done
;
}
if
(
len
&&
(
write_
word
(
pi
d
,
addr
+
len
-
1
,
0
,
0
)
==
-
1
))
goto
done
;
if
(
len
&&
(
write_
thread_int
(
threa
d
,
addr
+
len
-
1
,
0
,
0
)
==
-
1
))
goto
done
;
}
}
else
set_error
(
ERROR_ACCESS_DENIED
);
...
...
This diff is collapsed.
Click to expand it.
server/ptrace.c
0 → 100644
+
164
−
0
View file @
578c1009
/*
* Server-side ptrace support
*
* Copyright (C) 1999 Alexandre Julliard
*/
#include
"config.h"
#include
<assert.h>
#include
<errno.h>
#include
<stdio.h>
#include
<signal.h>
#include
<sys/ptrace.h>
#ifdef HAVE_SYS_WAIT_H
#include
<sys/wait.h>
#endif
#include
<unistd.h>
#include
"process.h"
#include
"thread.h"
#ifndef PTRACE_CONT
#define PTRACE_CONT PT_CONTINUE
#endif
#ifndef PTRACE_ATTACH
#define PTRACE_ATTACH PT_ATTACH
#endif
#ifndef PTRACE_DETACH
#define PTRACE_DETACH PT_DETACH
#endif
#ifndef PTRACE_PEEKDATA
#define PTRACE_PEEKDATA PT_READ_D
#endif
#ifndef PTRACE_POKEDATA
#define PTRACE_POKEDATA PT_WRITE_D
#endif
static
const
int
use_ptrace
=
1
;
/* set to 0 to disable ptrace */
/* wait for a ptraced child to get a certain signal */
/* if the signal is 0, we simply check if anything is pending and return at once */
void
wait4_thread
(
struct
thread
*
thread
,
int
signal
)
{
int
status
;
int
pid
;
restart:
pid
=
thread
?
thread
->
unix_pid
:
-
1
;
if
((
pid
=
wait4
(
pid
,
&
status
,
WUNTRACED
|
(
signal
?
0
:
WNOHANG
),
NULL
))
==
-
1
)
{
perror
(
"wait4"
);
return
;
}
if
(
WIFSTOPPED
(
status
))
{
int
sig
=
WSTOPSIG
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d got sig %d
\n
"
,
pid
,
sig
);
switch
(
sig
)
{
case
SIGSTOP
:
/* continue at once if not suspended */
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
break
;
if
(
!
(
thread
->
process
->
suspend
+
thread
->
suspend
))
ptrace
(
PTRACE_CONT
,
pid
,
0
,
sig
);
break
;
default:
/* ignore other signals for now */
ptrace
(
PTRACE_CONT
,
pid
,
0
,
sig
);
break
;
}
if
(
signal
&&
sig
!=
signal
)
goto
restart
;
}
else
if
(
WIFSIGNALED
(
status
))
{
int
exit_code
=
WTERMSIG
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d killed by sig %d
\n
"
,
pid
,
exit_code
);
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
return
;
if
(
thread
->
client
)
remove_client
(
thread
->
client
,
exit_code
);
}
else
if
(
WIFEXITED
(
status
))
{
int
exit_code
=
WEXITSTATUS
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d exited with status %d
\n
"
,
pid
,
exit_code
);
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
return
;
if
(
thread
->
client
)
remove_client
(
thread
->
client
,
exit_code
);
}
else
fprintf
(
stderr
,
"wait4: pid %d unknown status %x
\n
"
,
pid
,
status
);
}
/* attach to a Unix thread */
static
int
attach_thread
(
struct
thread
*
thread
)
{
/* this may fail if the client is already being debugged */
if
(
!
use_ptrace
||
(
ptrace
(
PTRACE_ATTACH
,
thread
->
unix_pid
,
0
,
0
)
==
-
1
))
return
0
;
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: attached to pid %d
\n
"
,
thread
->
unix_pid
);
thread
->
attached
=
1
;
wait4_thread
(
thread
,
SIGSTOP
);
return
1
;
}
/* detach from a Unix thread and kill it */
void
detach_thread
(
struct
thread
*
thread
)
{
if
(
!
thread
->
unix_pid
)
return
;
kill
(
thread
->
unix_pid
,
SIGTERM
);
if
(
thread
->
suspend
+
thread
->
process
->
suspend
)
continue_thread
(
thread
);
if
(
thread
->
attached
)
{
wait4_thread
(
thread
,
SIGTERM
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: detaching from %d
\n
"
,
thread
->
unix_pid
);
ptrace
(
PTRACE_DETACH
,
thread
->
unix_pid
,
0
,
SIGTERM
);
thread
->
attached
=
0
;
}
}
/* stop a thread (at the Unix level) */
void
stop_thread
(
struct
thread
*
thread
)
{
/* can't stop a thread while initialisation is in progress */
if
(
!
thread
->
unix_pid
||
thread
->
process
->
init_event
)
return
;
/* first try to attach to it */
if
(
!
thread
->
attached
)
if
(
attach_thread
(
thread
))
return
;
/* this will have stopped it */
/* attached already, or attach failed -> send a signal */
kill
(
thread
->
unix_pid
,
SIGSTOP
);
if
(
thread
->
attached
)
wait4_thread
(
thread
,
SIGSTOP
);
}
/* make a thread continue (at the Unix level) */
void
continue_thread
(
struct
thread
*
thread
)
{
if
(
!
thread
->
unix_pid
)
return
;
if
(
!
thread
->
attached
)
kill
(
thread
->
unix_pid
,
SIGCONT
);
else
ptrace
(
PTRACE_CONT
,
thread
->
unix_pid
,
0
,
SIGSTOP
);
}
/* read an int from a thread address space */
int
read_thread_int
(
struct
thread
*
thread
,
const
int
*
addr
,
int
*
data
)
{
if
(((
*
data
=
ptrace
(
PTRACE_PEEKDATA
,
thread
->
unix_pid
,
addr
))
==
-
1
)
&&
errno
)
{
file_set_error
();
return
-
1
;
}
return
0
;
}
/* write an int to a thread address space */
int
write_thread_int
(
struct
thread
*
thread
,
int
*
addr
,
int
data
,
unsigned
int
mask
)
{
int
res
;
if
(
mask
!=
~
0
)
{
if
(
read_thread_int
(
thread
,
addr
,
&
res
)
==
-
1
)
return
-
1
;
data
=
(
data
&
mask
)
|
(
res
&
~
mask
);
}
if
((
res
=
ptrace
(
PTRACE_POKEDATA
,
thread
->
unix_pid
,
addr
,
data
))
==
-
1
)
file_set_error
();
return
res
;
}
This diff is collapsed.
Click to expand it.
server/thread.c
+
8
−
112
View file @
578c1009
...
...
@@ -15,10 +15,8 @@
#ifdef HAVE_SYS_MMAN_H
#include
<sys/mman.h>
#endif
#include
<sys/ptrace.h>
#include
<sys/types.h>
#include
<sys/uio.h>
#include
<sys/wait.h>
#include
<unistd.h>
#include
<stdarg.h>
...
...
@@ -82,7 +80,6 @@ static const struct object_ops thread_ops =
destroy_thread
};
static
const
int
use_ptrace
=
1
;
/* set to 0 to disable ptrace */
static
struct
thread
*
first_thread
;
/* allocate the buffer for the communication with the client */
...
...
@@ -214,6 +211,14 @@ struct thread *get_thread_from_handle( int handle, unsigned int access )
access
,
&
thread_ops
);
}
/* find a thread from a Unix pid */
struct
thread
*
get_thread_from_pid
(
int
pid
)
{
struct
thread
*
t
=
first_thread
;
while
(
t
&&
(
t
->
unix_pid
!=
pid
))
t
=
t
->
next
;
return
t
;
}
/* set all information about a thread */
static
void
set_thread_info
(
struct
thread
*
thread
,
struct
set_thread_info_request
*
req
)
...
...
@@ -227,115 +232,6 @@ static void set_thread_info( struct thread *thread,
}
}
/* find a thread from a Unix pid */
static
struct
thread
*
get_thread_from_pid
(
int
pid
)
{
struct
thread
*
t
=
first_thread
;
while
(
t
&&
(
t
->
unix_pid
!=
pid
))
t
=
t
->
next
;
return
t
;
}
/* wait for a ptraced child to get a certain signal */
/* if the signal is 0, we simply check if anything is pending and return at once */
void
wait4_thread
(
struct
thread
*
thread
,
int
signal
)
{
int
status
;
int
pid
;
restart:
pid
=
thread
?
thread
->
unix_pid
:
-
1
;
if
((
pid
=
wait4
(
pid
,
&
status
,
WUNTRACED
|
(
signal
?
0
:
WNOHANG
),
NULL
))
==
-
1
)
{
perror
(
"wait4"
);
return
;
}
if
(
WIFSTOPPED
(
status
))
{
int
sig
=
WSTOPSIG
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d got sig %d
\n
"
,
pid
,
sig
);
switch
(
sig
)
{
case
SIGSTOP
:
/* continue at once if not suspended */
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
break
;
if
(
!
(
thread
->
process
->
suspend
+
thread
->
suspend
))
ptrace
(
PT_CONTINUE
,
pid
,
0
,
sig
);
break
;
default:
/* ignore other signals for now */
ptrace
(
PT_CONTINUE
,
pid
,
0
,
sig
);
break
;
}
if
(
signal
&&
sig
!=
signal
)
goto
restart
;
}
else
if
(
WIFSIGNALED
(
status
))
{
int
exit_code
=
WTERMSIG
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d killed by sig %d
\n
"
,
pid
,
exit_code
);
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
return
;
if
(
thread
->
client
)
remove_client
(
thread
->
client
,
exit_code
);
}
else
if
(
WIFEXITED
(
status
))
{
int
exit_code
=
WEXITSTATUS
(
status
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: pid %d exited with status %d
\n
"
,
pid
,
exit_code
);
if
(
!
thread
)
if
(
!
(
thread
=
get_thread_from_pid
(
pid
)))
return
;
if
(
thread
->
client
)
remove_client
(
thread
->
client
,
exit_code
);
}
else
fprintf
(
stderr
,
"wait4: pid %d unknown status %x
\n
"
,
pid
,
status
);
}
/* attach to a Unix thread */
static
int
attach_thread
(
struct
thread
*
thread
)
{
/* this may fail if the client is already being debugged */
if
(
!
use_ptrace
||
(
ptrace
(
PT_ATTACH
,
thread
->
unix_pid
,
0
,
0
)
==
-
1
))
return
0
;
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: attached to pid %d
\n
"
,
thread
->
unix_pid
);
thread
->
attached
=
1
;
wait4_thread
(
thread
,
SIGSTOP
);
return
1
;
}
/* detach from a Unix thread and kill it */
static
void
detach_thread
(
struct
thread
*
thread
)
{
if
(
!
thread
->
unix_pid
)
return
;
kill
(
thread
->
unix_pid
,
SIGTERM
);
if
(
thread
->
suspend
+
thread
->
process
->
suspend
)
continue_thread
(
thread
);
if
(
thread
->
attached
)
{
wait4_thread
(
thread
,
SIGTERM
);
if
(
debug_level
)
fprintf
(
stderr
,
"ptrace: detaching from %d
\n
"
,
thread
->
unix_pid
);
ptrace
(
PT_DETACH
,
thread
->
unix_pid
,
0
,
SIGTERM
);
thread
->
attached
=
0
;
}
}
/* stop a thread (at the Unix level) */
void
stop_thread
(
struct
thread
*
thread
)
{
/* can't stop a thread while initialisation is in progress */
if
(
!
thread
->
unix_pid
||
thread
->
process
->
init_event
)
return
;
/* first try to attach to it */
if
(
!
thread
->
attached
)
if
(
attach_thread
(
thread
))
return
;
/* this will have stopped it */
/* attached already, or attach failed -> send a signal */
kill
(
thread
->
unix_pid
,
SIGSTOP
);
if
(
thread
->
attached
)
wait4_thread
(
thread
,
SIGSTOP
);
}
/* make a thread continue (at the Unix level) */
void
continue_thread
(
struct
thread
*
thread
)
{
if
(
!
thread
->
unix_pid
)
return
;
if
(
!
thread
->
attached
)
kill
(
thread
->
unix_pid
,
SIGCONT
);
else
ptrace
(
PT_CONTINUE
,
thread
->
unix_pid
,
0
,
SIGSTOP
);
}
/* suspend a thread */
int
suspend_thread
(
struct
thread
*
thread
,
int
check_limit
)
{
...
...
This diff is collapsed.
Click to expand it.
server/thread.h
+
11
−
3
View file @
578c1009
...
...
@@ -66,9 +66,7 @@ extern struct thread *current;
extern
void
create_initial_thread
(
int
fd
);
extern
struct
thread
*
get_thread_from_id
(
void
*
id
);
extern
struct
thread
*
get_thread_from_handle
(
int
handle
,
unsigned
int
access
);
extern
void
wait4_thread
(
struct
thread
*
thread
,
int
wait
);
extern
void
stop_thread
(
struct
thread
*
thread
);
extern
void
continue_thread
(
struct
thread
*
thread
);
extern
struct
thread
*
get_thread_from_pid
(
int
pid
);
extern
int
suspend_thread
(
struct
thread
*
thread
,
int
check_limit
);
extern
int
resume_thread
(
struct
thread
*
thread
);
extern
void
suspend_all_threads
(
void
);
...
...
@@ -80,6 +78,16 @@ extern void thread_killed( struct thread *thread, int exit_code );
extern
void
thread_timeout
(
void
);
extern
void
wake_up
(
struct
object
*
obj
,
int
max
);
/* ptrace functions */
extern
void
wait4_thread
(
struct
thread
*
thread
,
int
wait
);
extern
void
stop_thread
(
struct
thread
*
thread
);
extern
void
continue_thread
(
struct
thread
*
thread
);
extern
void
detach_thread
(
struct
thread
*
thread
);
extern
int
read_thread_int
(
struct
thread
*
thread
,
const
int
*
addr
,
int
*
data
);
extern
int
write_thread_int
(
struct
thread
*
thread
,
int
*
addr
,
int
data
,
unsigned
int
mask
);
static
inline
int
get_error
(
void
)
{
return
current
->
error
;
}
static
inline
void
set_error
(
int
err
)
{
current
->
error
=
err
;
}
static
inline
void
clear_error
(
void
)
{
set_error
(
0
);
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment