Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
c273498e
Commit
c273498e
authored
Dec 29, 2006
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Implement process control using Mach primitives for Mac OS.
With help from Ken Thomases.
parent
150b5dca
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
473 additions
and
0 deletions
+473
-0
server.c
dlls/ntdll/server.c
+47
-0
Makefile.in
server/Makefile.in
+1
-0
mach.c
server/mach.c
+414
-0
process.h
server/process.h
+7
-0
ptrace.c
server/ptrace.c
+4
-0
No files found.
dlls/ntdll/server.c
View file @
c273498e
...
...
@@ -919,6 +919,49 @@ static void create_config_dir(void)
}
#ifdef __APPLE__
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
/* send our task port to the server */
static
void
send_server_task_port
(
void
)
{
mach_port_t
bootstrap_port
,
wineserver_port
;
kern_return_t
kret
;
struct
{
mach_msg_header_t
header
;
mach_msg_body_t
body
;
mach_msg_port_descriptor_t
task_port
;
}
msg
;
if
(
task_get_bootstrap_port
(
mach_task_self
(),
&
bootstrap_port
)
!=
KERN_SUCCESS
)
return
;
kret
=
bootstrap_look_up
(
bootstrap_port
,
(
char
*
)
wine_get_server_dir
(),
&
wineserver_port
);
if
(
kret
!=
KERN_SUCCESS
)
fatal_error
(
"cannot find the server port: 0x%08x
\n
"
,
kret
);
mach_port_deallocate
(
mach_task_self
(),
bootstrap_port
);
msg
.
header
.
msgh_bits
=
MACH_MSGH_BITS
(
MACH_MSG_TYPE_COPY_SEND
,
0
)
|
MACH_MSGH_BITS_COMPLEX
;
msg
.
header
.
msgh_size
=
sizeof
(
msg
);
msg
.
header
.
msgh_remote_port
=
wineserver_port
;
msg
.
header
.
msgh_local_port
=
MACH_PORT_NULL
;
msg
.
body
.
msgh_descriptor_count
=
1
;
msg
.
task_port
.
name
=
mach_task_self
();
msg
.
task_port
.
disposition
=
MACH_MSG_TYPE_COPY_SEND
;
msg
.
task_port
.
type
=
MACH_MSG_PORT_DESCRIPTOR
;
kret
=
mach_msg_send
(
&
msg
.
header
);
if
(
kret
!=
KERN_SUCCESS
)
server_protocol_error
(
"mach_msg_send failed: 0x%08x
\n
"
,
kret
);
mach_port_deallocate
(
mach_task_self
(),
wineserver_port
);
}
#endif
/* __APPLE__ */
/***********************************************************************
* server_init_process
*
...
...
@@ -962,6 +1005,10 @@ void server_init_process(void)
/* receive the first thread request fd on the main socket */
ntdll_get_thread_data
()
->
request_fd
=
receive_fd
(
&
dummy_handle
);
#ifdef __APPLE__
send_server_task_port
();
#endif
}
...
...
server/Makefile.in
View file @
c273498e
...
...
@@ -24,6 +24,7 @@ C_SRCS = \
file.c
\
handle.c
\
hook.c
\
mach.c
\
mailslot.c
\
main.c
\
mapping.c
\
...
...
server/mach.c
0 → 100644
View file @
c273498e
/*
* Server-side debugger support using Mach primitives
*
* Copyright (C) 1999, 2006 Alexandre Julliard
* Copyright (C) 2006 Ken Thomases for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
#include "file.h"
#include "process.h"
#include "thread.h"
#include "request.h"
#include "wine/library.h"
#ifdef USE_MACH
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/thread_act.h>
#include <servers/bootstrap.h>
extern
int
__pthread_kill
(
mach_port_t
,
int
);
static
mach_port_t
server_mach_port
;
void
sigchld_callback
(
void
)
{
assert
(
0
);
/* should never be called on MacOS */
}
static
void
mach_set_error
(
kern_return_t
mach_error
)
{
switch
(
mach_error
)
{
case
KERN_SUCCESS
:
break
;
case
KERN_INVALID_ARGUMENT
:
set_error
(
STATUS_INVALID_PARAMETER
);
break
;
case
KERN_NO_SPACE
:
set_error
(
STATUS_NO_MEMORY
);
break
;
case
KERN_PROTECTION_FAILURE
:
set_error
(
STATUS_ACCESS_DENIED
);
break
;
case
KERN_INVALID_ADDRESS
:
set_error
(
STATUS_ACCESS_VIOLATION
);
break
;
default:
set_error
(
STATUS_UNSUCCESSFUL
);
break
;
}
}
static
mach_port_t
get_process_port
(
struct
process
*
process
)
{
return
process
->
trace_data
;
}
/* initialize the process control mechanism */
void
init_tracing_mechanism
(
void
)
{
mach_port_t
bp
;
if
(
task_get_bootstrap_port
(
mach_task_self
(),
&
bp
)
!=
KERN_SUCCESS
)
fatal_error
(
"Can't find bootstrap port
\n
"
);
if
(
mach_port_allocate
(
mach_task_self
(),
MACH_PORT_RIGHT_RECEIVE
,
&
server_mach_port
)
!=
KERN_SUCCESS
)
fatal_error
(
"Can't allocate port
\n
"
);
if
(
mach_port_insert_right
(
mach_task_self
(),
server_mach_port
,
server_mach_port
,
MACH_MSG_TYPE_MAKE_SEND
)
!=
KERN_SUCCESS
)
fatal_error
(
"Error inserting rights
\n
"
);
if
(
bootstrap_register
(
bp
,
(
char
*
)
wine_get_server_dir
(),
server_mach_port
)
!=
KERN_SUCCESS
)
fatal_error
(
"Can't check in server_mach_port
\n
"
);
mach_port_deallocate
(
mach_task_self
(),
bp
);
}
/* initialize the per-process tracing mechanism */
void
init_process_tracing
(
struct
process
*
process
)
{
int
pid
,
ret
;
struct
{
mach_msg_header_t
header
;
mach_msg_body_t
body
;
mach_msg_port_descriptor_t
task_port
;
mach_msg_trailer_t
trailer
;
/* only present on receive */
}
msg
;
for
(;;)
{
ret
=
mach_msg
(
&
msg
.
header
,
MACH_RCV_MSG
|
MACH_RCV_TIMEOUT
,
0
,
sizeof
(
msg
),
server_mach_port
,
0
,
0
);
if
(
ret
)
{
if
(
ret
!=
MACH_RCV_TIMED_OUT
&&
debug_level
)
fprintf
(
stderr
,
"warning: mach port receive failed with %x
\n
"
,
ret
);
return
;
}
/* if anything in the message is invalid, ignore it */
if
(
msg
.
header
.
msgh_size
!=
offsetof
(
typeof
(
msg
),
trailer
))
continue
;
if
(
msg
.
body
.
msgh_descriptor_count
!=
1
)
continue
;
if
(
msg
.
task_port
.
type
!=
MACH_MSG_PORT_DESCRIPTOR
)
continue
;
if
(
msg
.
task_port
.
disposition
!=
MACH_MSG_TYPE_PORT_SEND
)
continue
;
if
(
msg
.
task_port
.
name
==
MACH_PORT_NULL
)
continue
;
if
(
msg
.
task_port
.
name
==
MACH_PORT_DEAD
)
continue
;
if
(
!
pid_for_task
(
msg
.
task_port
.
name
,
&
pid
))
{
struct
thread
*
thread
=
get_thread_from_pid
(
pid
);
if
(
thread
&&
!
thread
->
process
->
trace_data
)
thread
->
process
->
trace_data
=
msg
.
task_port
.
name
;
else
mach_port_deallocate
(
mach_task_self
(),
msg
.
task_port
.
name
);
}
}
}
/* terminate the per-process tracing mechanism */
void
finish_process_tracing
(
struct
process
*
process
)
{
if
(
process
->
trace_data
)
{
mach_port_deallocate
(
mach_task_self
(),
process
->
trace_data
);
process
->
trace_data
=
0
;
}
}
/* retrieve the thread x86 registers */
void
get_thread_context
(
struct
thread
*
thread
,
CONTEXT
*
context
,
unsigned
int
flags
)
{
struct
x86_debug_state32
state
;
mach_msg_type_number_t
count
=
sizeof
(
state
)
/
sizeof
(
int
);
mach_msg_type_name_t
type
;
mach_port_t
port
,
process_port
=
get_process_port
(
thread
->
process
);
/* all other regs are handled on the client side */
assert
(
(
flags
|
CONTEXT_i386
)
==
CONTEXT_DEBUG_REGISTERS
);
if
(
thread
->
unix_pid
==
-
1
||
!
process_port
||
mach_port_extract_right
(
process_port
,
thread
->
unix_tid
,
MACH_MSG_TYPE_COPY_SEND
,
&
port
,
&
type
))
{
set_error
(
STATUS_ACCESS_DENIED
);
return
;
}
if
(
!
thread_get_state
(
port
,
x86_DEBUG_STATE32
,
(
thread_state_t
)
&
state
,
&
count
))
{
context
->
Dr0
=
state
.
dr0
;
context
->
Dr1
=
state
.
dr1
;
context
->
Dr2
=
state
.
dr2
;
context
->
Dr3
=
state
.
dr3
;
context
->
Dr6
=
state
.
dr6
;
context
->
Dr7
=
state
.
dr7
;
context
->
ContextFlags
|=
CONTEXT_DEBUG_REGISTERS
;
}
mach_port_deallocate
(
mach_task_self
(),
port
);
}
/* set the thread x86 registers */
void
set_thread_context
(
struct
thread
*
thread
,
const
CONTEXT
*
context
,
unsigned
int
flags
)
{
struct
x86_debug_state32
state
;
mach_msg_type_number_t
count
=
sizeof
(
state
)
/
sizeof
(
int
);
mach_msg_type_name_t
type
;
mach_port_t
port
,
process_port
=
get_process_port
(
thread
->
process
);
/* all other regs are handled on the client side */
assert
(
(
flags
|
CONTEXT_i386
)
==
CONTEXT_DEBUG_REGISTERS
);
if
(
thread
->
unix_pid
==
-
1
||
!
process_port
||
mach_port_extract_right
(
process_port
,
thread
->
unix_tid
,
MACH_MSG_TYPE_COPY_SEND
,
&
port
,
&
type
))
{
set_error
(
STATUS_ACCESS_DENIED
);
return
;
}
state
.
dr0
=
context
->
Dr0
;
state
.
dr1
=
context
->
Dr1
;
state
.
dr2
=
context
->
Dr2
;
state
.
dr3
=
context
->
Dr3
;
state
.
dr4
=
0
;
state
.
dr5
=
0
;
state
.
dr6
=
context
->
Dr6
;
state
.
dr7
=
context
->
Dr7
;
if
(
!
thread_set_state
(
port
,
x86_DEBUG_STATE32
,
(
thread_state_t
)
&
state
,
count
))
{
if
(
thread
->
context
)
/* update the cached values */
{
thread
->
context
->
Dr0
=
context
->
Dr0
;
thread
->
context
->
Dr1
=
context
->
Dr1
;
thread
->
context
->
Dr2
=
context
->
Dr2
;
thread
->
context
->
Dr3
=
context
->
Dr3
;
thread
->
context
->
Dr6
=
context
->
Dr6
;
thread
->
context
->
Dr7
=
context
->
Dr7
;
}
}
mach_port_deallocate
(
mach_task_self
(),
port
);
}
int
send_thread_signal
(
struct
thread
*
thread
,
int
sig
)
{
int
ret
=
-
1
;
mach_port_t
process_port
=
get_process_port
(
thread
->
process
);
if
(
thread
->
unix_pid
!=
-
1
&&
process_port
)
{
mach_msg_type_name_t
type
;
mach_port_t
port
;
if
(
!
mach_port_extract_right
(
process_port
,
thread
->
unix_tid
,
MACH_MSG_TYPE_COPY_SEND
,
&
port
,
&
type
))
{
ret
=
__pthread_kill
(
port
,
sig
);
mach_port_deallocate
(
mach_task_self
(),
port
);
}
else
errno
=
ESRCH
;
if
(
ret
==
-
1
&&
errno
==
ESRCH
)
/* thread got killed */
{
thread
->
unix_pid
=
-
1
;
thread
->
unix_tid
=
-
1
;
}
}
return
(
ret
!=
-
1
);
}
/* read data from a process memory space */
int
read_process_memory
(
struct
process
*
process
,
const
void
*
ptr
,
data_size_t
size
,
char
*
dest
)
{
kern_return_t
ret
;
mach_msg_type_number_t
bytes_read
;
vm_offset_t
offset
,
data
;
vm_address_t
aligned_address
;
vm_size_t
aligned_size
;
unsigned
int
page_size
=
get_page_size
();
mach_port_t
process_port
=
get_process_port
(
process
);
if
(
!
process_port
)
{
set_error
(
STATUS_ACCESS_DENIED
);
return
0
;
}
if
((
ret
=
task_suspend
(
process_port
))
!=
KERN_SUCCESS
)
{
mach_set_error
(
ret
);
return
0
;
}
offset
=
(
unsigned
long
)
ptr
%
page_size
;
aligned_address
=
(
vm_address_t
)((
char
*
)
ptr
-
offset
);
aligned_size
=
(
size
+
offset
+
page_size
-
1
)
/
page_size
*
page_size
;
ret
=
vm_read
(
process_port
,
aligned_address
,
aligned_size
,
&
data
,
&
bytes_read
);
if
(
ret
!=
KERN_SUCCESS
)
mach_set_error
(
ret
);
else
{
memcpy
(
dest
,
(
char
*
)
data
+
offset
,
size
);
vm_deallocate
(
mach_task_self
(),
data
,
bytes_read
);
}
task_resume
(
process_port
);
return
(
ret
==
KERN_SUCCESS
);
}
/* write data to a process memory space */
int
write_process_memory
(
struct
process
*
process
,
void
*
ptr
,
data_size_t
size
,
const
char
*
src
)
{
kern_return_t
ret
;
vm_address_t
aligned_address
,
region_address
;
vm_size_t
aligned_size
,
region_size
;
mach_msg_type_number_t
info_size
,
bytes_read
;
vm_offset_t
offset
,
task_mem
=
0
;
struct
vm_region_basic_info
info
;
mach_port_t
dummy
;
unsigned
int
page_size
=
get_page_size
();
mach_port_t
process_port
=
get_process_port
(
process
);
if
(
!
process_port
)
{
set_error
(
STATUS_ACCESS_DENIED
);
return
0
;
}
offset
=
(
unsigned
long
)
ptr
%
page_size
;
aligned_address
=
(
vm_address_t
)((
char
*
)
ptr
-
offset
);
aligned_size
=
(
size
+
offset
+
page_size
-
1
)
/
page_size
*
page_size
;
if
((
ret
=
task_suspend
(
process_port
))
!=
KERN_SUCCESS
)
{
mach_set_error
(
ret
);
return
0
;
}
ret
=
vm_read
(
process_port
,
aligned_address
,
aligned_size
,
&
task_mem
,
&
bytes_read
);
if
(
ret
!=
KERN_SUCCESS
)
{
mach_set_error
(
ret
);
goto
failed
;
}
region_address
=
aligned_address
;
info_size
=
sizeof
(
info
);
ret
=
vm_region
(
process_port
,
&
region_address
,
&
region_size
,
VM_REGION_BASIC_INFO
,
(
vm_region_info_t
)
&
info
,
&
info_size
,
&
dummy
);
if
(
ret
!=
KERN_SUCCESS
)
{
mach_set_error
(
ret
);
goto
failed
;
}
if
(
region_address
>
aligned_address
||
region_address
+
region_size
<
aligned_address
+
aligned_size
)
{
/* FIXME: should support multiple regions */
set_error
(
ERROR_ACCESS_DENIED
);
goto
failed
;
}
ret
=
vm_protect
(
process_port
,
aligned_address
,
aligned_size
,
0
,
VM_PROT_READ
|
VM_PROT_WRITE
);
if
(
ret
!=
KERN_SUCCESS
)
{
mach_set_error
(
ret
);
goto
failed
;
}
/* FIXME: there's an optimization that can be made: check first and last */
/* pages for writability; read first and last pages; write interior */
/* pages to task without ever reading&modifying them; if that succeeds, */
/* modify first and last pages and write them. */
memcpy
(
(
char
*
)
task_mem
+
offset
,
src
,
size
);
ret
=
vm_write
(
process_port
,
aligned_address
,
task_mem
,
bytes_read
);
if
(
ret
!=
KERN_SUCCESS
)
mach_set_error
(
ret
);
else
{
vm_deallocate
(
mach_task_self
(),
task_mem
,
bytes_read
);
/* restore protection */
vm_protect
(
process_port
,
aligned_address
,
aligned_size
,
0
,
info
.
protection
);
task_resume
(
process_port
);
return
1
;
}
failed:
if
(
task_mem
)
vm_deallocate
(
mach_task_self
(),
task_mem
,
bytes_read
);
task_resume
(
process_port
);
return
0
;
}
/* retrieve an LDT selector entry */
void
get_selector_entry
(
struct
thread
*
thread
,
int
entry
,
unsigned
int
*
base
,
unsigned
int
*
limit
,
unsigned
char
*
flags
)
{
const
unsigned
int
total_size
=
(
2
*
sizeof
(
int
)
+
1
)
*
8192
;
struct
process
*
process
=
thread
->
process
;
unsigned
int
page_size
=
get_page_size
();
vm_offset_t
data
;
kern_return_t
ret
;
mach_msg_type_number_t
bytes_read
;
mach_port_t
process_port
=
get_process_port
(
thread
->
process
);
if
(
!
process
->
ldt_copy
||
!
process_port
)
{
set_error
(
STATUS_ACCESS_DENIED
);
return
;
}
if
(
entry
>=
8192
)
{
set_error
(
STATUS_INVALID_PARAMETER
);
/* FIXME */
return
;
}
if
((
ret
=
task_suspend
(
process_port
))
==
KERN_SUCCESS
)
{
void
*
ptr
=
process
->
ldt_copy
;
vm_offset_t
offset
=
(
unsigned
long
)
ptr
%
page_size
;
vm_address_t
aligned_address
=
(
vm_address_t
)((
char
*
)
ptr
-
offset
);
vm_size_t
aligned_size
=
(
total_size
+
offset
+
page_size
-
1
)
/
page_size
*
page_size
;
ret
=
vm_read
(
process_port
,
aligned_address
,
aligned_size
,
&
data
,
&
bytes_read
);
if
(
ret
!=
KERN_SUCCESS
)
mach_set_error
(
ret
);
else
{
const
int
*
ldt
=
(
const
int
*
)((
char
*
)
data
+
offset
);
memcpy
(
base
,
ldt
+
entry
,
sizeof
(
int
)
);
memcpy
(
limit
,
ldt
+
entry
+
8192
,
sizeof
(
int
)
);
memcpy
(
flags
,
(
char
*
)(
ldt
+
2
*
8192
)
+
entry
,
1
);
vm_deallocate
(
mach_task_self
(),
data
,
bytes_read
);
}
task_resume
(
process_port
);
}
else
mach_set_error
(
ret
);
}
#endif
/* USE_MACH */
server/process.h
View file @
c273498e
...
...
@@ -130,6 +130,13 @@ extern struct process_snapshot *process_snap( int *count );
extern
struct
module_snapshot
*
module_snap
(
struct
process
*
process
,
int
*
count
);
extern
void
enum_processes
(
int
(
*
cb
)(
struct
process
*
,
void
*
),
void
*
user
);
/* process tracing mechanism to use */
#ifdef __APPLE__
#define USE_MACH
#else
#define USE_PTRACE
#endif
extern
void
init_tracing_mechanism
(
void
);
extern
void
init_process_tracing
(
struct
process
*
process
);
extern
void
finish_process_tracing
(
struct
process
*
process
);
...
...
server/ptrace.c
View file @
c273498e
...
...
@@ -45,6 +45,8 @@
#include "process.h"
#include "thread.h"
#ifdef USE_PTRACE
#ifndef PTRACE_CONT
#define PTRACE_CONT PT_CONTINUE
#endif
...
...
@@ -653,3 +655,5 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
}
#endif
/* linux || __FreeBSD__ */
#endif
/* USE_PTRACE */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment