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
308bd357
Commit
308bd357
authored
Apr 27, 2021
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Store a machine ID instead of a CPU in the context structure.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
94d19eff
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
53 additions
and
46 deletions
+53
-46
signal_arm.c
dlls/ntdll/unix/signal_arm.c
+2
-2
signal_arm64.c
dlls/ntdll/unix/signal_arm64.c
+2
-2
signal_i386.c
dlls/ntdll/unix/signal_i386.c
+2
-2
signal_x86_64.c
dlls/ntdll/unix/signal_x86_64.c
+3
-3
thread.c
dlls/ntdll/unix/thread.c
+2
-2
server_protocol.h
include/wine/server_protocol.h
+2
-2
protocol.def
server/protocol.def
+1
-1
ptrace.c
server/ptrace.c
+6
-6
thread.c
server/thread.c
+21
-19
trace.c
server/trace.c
+12
-7
No files found.
dlls/ntdll/unix/signal_arm.c
View file @
308bd357
...
...
@@ -370,7 +370,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
DWORD
i
,
flags
=
from
->
ContextFlags
&
~
CONTEXT_ARM
;
/* get rid of CPU id */
memset
(
to
,
0
,
sizeof
(
*
to
)
);
to
->
cpu
=
CPU_ARM
;
to
->
machine
=
IMAGE_FILE_MACHINE_ARMNT
;
if
(
flags
&
CONTEXT_CONTROL
)
{
...
...
@@ -424,7 +424,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
{
DWORD
i
;
if
(
from
->
cpu
!=
CPU_ARM
)
return
STATUS_INVALID_PARAMETER
;
if
(
from
->
machine
!=
IMAGE_FILE_MACHINE_ARMNT
)
return
STATUS_INVALID_PARAMETER
;
to
->
ContextFlags
=
CONTEXT_ARM
;
if
(
from
->
flags
&
SERVER_CTX_CONTROL
)
...
...
dlls/ntdll/unix/signal_arm64.c
View file @
308bd357
...
...
@@ -444,7 +444,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
DWORD
i
,
flags
=
from
->
ContextFlags
&
~
CONTEXT_ARM64
;
/* get rid of CPU id */
memset
(
to
,
0
,
sizeof
(
*
to
)
);
to
->
cpu
=
CPU
_ARM64
;
to
->
machine
=
IMAGE_FILE_MACHINE
_ARM64
;
if
(
flags
&
CONTEXT_CONTROL
)
{
...
...
@@ -492,7 +492,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
{
DWORD
i
;
if
(
from
->
cpu
!=
CPU
_ARM64
)
return
STATUS_INVALID_PARAMETER
;
if
(
from
->
machine
!=
IMAGE_FILE_MACHINE
_ARM64
)
return
STATUS_INVALID_PARAMETER
;
to
->
ContextFlags
=
CONTEXT_ARM64
;
if
(
from
->
flags
&
SERVER_CTX_CONTROL
)
...
...
dlls/ntdll/unix/signal_i386.c
View file @
308bd357
...
...
@@ -1022,7 +1022,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
DWORD
flags
=
from
->
ContextFlags
&
~
CONTEXT_i386
;
/* get rid of CPU id */
memset
(
to
,
0
,
sizeof
(
*
to
)
);
to
->
cpu
=
CPU_x
86
;
to
->
machine
=
IMAGE_FILE_MACHINE_I3
86
;
if
(
flags
&
CONTEXT_CONTROL
)
{
...
...
@@ -1092,7 +1092,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
*/
NTSTATUS
context_from_server
(
CONTEXT
*
to
,
const
context_t
*
from
)
{
if
(
from
->
cpu
!=
CPU_x
86
)
return
STATUS_INVALID_PARAMETER
;
if
(
from
->
machine
!=
IMAGE_FILE_MACHINE_I3
86
)
return
STATUS_INVALID_PARAMETER
;
to
->
ContextFlags
=
CONTEXT_i386
|
(
to
->
ContextFlags
&
0x40
);
if
(
from
->
flags
&
SERVER_CTX_CONTROL
)
...
...
dlls/ntdll/unix/signal_x86_64.c
View file @
308bd357
...
...
@@ -1642,7 +1642,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
DWORD
flags
=
from
->
ContextFlags
&
~
CONTEXT_AMD64
;
/* get rid of CPU id */
memset
(
to
,
0
,
sizeof
(
*
to
)
);
to
->
cpu
=
CPU_x86_
64
;
to
->
machine
=
IMAGE_FILE_MACHINE_AMD
64
;
if
(
flags
&
CONTEXT_CONTROL
)
{
...
...
@@ -1707,7 +1707,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
*/
NTSTATUS
context_from_server
(
CONTEXT
*
to
,
const
context_t
*
from
)
{
if
(
from
->
cpu
==
CPU_x
86
)
if
(
from
->
machine
==
IMAGE_FILE_MACHINE_I3
86
)
{
/* convert the WoW64 context */
to
->
ContextFlags
=
CONTEXT_AMD64
;
...
...
@@ -1766,7 +1766,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
return
STATUS_SUCCESS
;
}
if
(
from
->
cpu
!=
CPU_x86_
64
)
return
STATUS_INVALID_PARAMETER
;
if
(
from
->
machine
!=
IMAGE_FILE_MACHINE_AMD
64
)
return
STATUS_INVALID_PARAMETER
;
to
->
ContextFlags
=
CONTEXT_AMD64
|
(
to
->
ContextFlags
&
0x40
);
if
(
from
->
flags
&
SERVER_CTX_CONTROL
)
...
...
dlls/ntdll/unix/thread.c
View file @
308bd357
...
...
@@ -666,7 +666,7 @@ static unsigned int wow64_get_server_context_flags( DWORD flags )
*/
static
NTSTATUS
wow64_context_from_server
(
WOW64_CONTEXT
*
to
,
const
context_t
*
from
)
{
if
(
from
->
cpu
!=
CPU_x
86
)
return
STATUS_INVALID_PARAMETER
;
if
(
from
->
machine
!=
IMAGE_FILE_MACHINE_I3
86
)
return
STATUS_INVALID_PARAMETER
;
to
->
ContextFlags
=
WOW64_CONTEXT_i386
|
(
to
->
ContextFlags
&
0x40
);
if
(
from
->
flags
&
SERVER_CTX_CONTROL
)
...
...
@@ -742,7 +742,7 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from )
DWORD
flags
=
from
->
ContextFlags
&
~
WOW64_CONTEXT_i386
;
/* get rid of CPU id */
memset
(
to
,
0
,
sizeof
(
*
to
)
);
to
->
cpu
=
CPU_x
86
;
to
->
machine
=
IMAGE_FILE_MACHINE_I3
86
;
if
(
flags
&
WOW64_CONTEXT_CONTROL
)
{
...
...
include/wine/server_protocol.h
View file @
308bd357
...
...
@@ -119,7 +119,7 @@ typedef int client_cpu_t;
typedef
struct
{
client_cpu_t
cpu
;
unsigned
int
machine
;
unsigned
int
flags
;
union
{
...
...
@@ -6219,7 +6219,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 69
4
#define SERVER_PROTOCOL_VERSION 69
5
/* ### protocol_version end ### */
...
...
server/protocol.def
View file @
308bd357
...
...
@@ -135,7 +135,7 @@ typedef int client_cpu_t;
/* context data */
typedef struct
{
client_cpu_t cpu; /* cpu
type */
unsigned int machine; /* machine
type */
unsigned int flags; /* SERVER_CTX_* flags */
union
{
...
...
server/ptrace.c
View file @
308bd357
...
...
@@ -591,9 +591,9 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
goto
done
;
}
}
switch
(
context
->
cpu
)
switch
(
context
->
machine
)
{
case
CPU_x
86
:
case
IMAGE_FILE_MACHINE_I3
86
:
context
->
debug
.
i386_regs
.
dr0
=
data
[
0
];
context
->
debug
.
i386_regs
.
dr1
=
data
[
1
];
context
->
debug
.
i386_regs
.
dr2
=
data
[
2
];
...
...
@@ -601,7 +601,7 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
context
->
debug
.
i386_regs
.
dr6
=
data
[
6
];
context
->
debug
.
i386_regs
.
dr7
=
data
[
7
];
break
;
case
CPU_x86_
64
:
case
IMAGE_FILE_MACHINE_AMD
64
:
context
->
debug
.
x86_64_regs
.
dr0
=
data
[
0
];
context
->
debug
.
x86_64_regs
.
dr1
=
data
[
1
];
context
->
debug
.
x86_64_regs
.
dr2
=
data
[
2
];
...
...
@@ -631,9 +631,9 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
/* force all breakpoint lengths to 1, workaround for kernel bug 200965 */
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
7
),
0x11110055
);
switch
(
context
->
cpu
)
switch
(
context
->
machine
)
{
case
CPU_x
86
:
case
IMAGE_FILE_MACHINE_I3
86
:
/* Linux 2.6.33+ does DR0-DR3 alignment validation, so it has to know LEN bits first */
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
7
),
context
->
debug
.
i386_regs
.
dr7
&
0xffff0000
)
==
-
1
)
goto
error
;
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
0
),
context
->
debug
.
i386_regs
.
dr0
)
==
-
1
)
goto
error
;
...
...
@@ -646,7 +646,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
7
),
context
->
debug
.
i386_regs
.
dr7
)
==
-
1
)
goto
error
;
thread
->
system_regs
|=
SERVER_CTX_DEBUG_REGISTERS
;
break
;
case
CPU_x86_
64
:
case
IMAGE_FILE_MACHINE_AMD
64
:
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
7
),
context
->
debug
.
x86_64_regs
.
dr7
&
0xffff0000
)
==
-
1
)
goto
error
;
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
0
),
context
->
debug
.
x86_64_regs
.
dr0
)
==
-
1
)
goto
error
;
if
(
ptrace
(
PTRACE_POKEUSER
,
pid
,
DR_OFFSET
(
1
),
context
->
debug
.
x86_64_regs
.
dr1
)
==
-
1
)
goto
error
;
...
...
server/thread.c
View file @
308bd357
...
...
@@ -296,7 +296,7 @@ static struct context *create_thread_context( struct thread *thread )
if
(
!
(
context
=
alloc_object
(
&
context_ops
)))
return
NULL
;
context
->
status
=
STATUS_PENDING
;
memset
(
&
context
->
regs
,
0
,
sizeof
(
context
->
regs
)
);
context
->
regs
.
cpu
=
thread
->
process
->
cpu
;
context
->
regs
.
machine
=
thread
->
process
->
machine
;
return
context
;
}
...
...
@@ -1293,7 +1293,7 @@ void kill_thread( struct thread *thread, int violent_death )
/* copy parts of a context structure */
static
void
copy_context
(
context_t
*
to
,
const
context_t
*
from
,
unsigned
int
flags
)
{
assert
(
to
->
cpu
==
from
->
cpu
);
assert
(
to
->
machine
==
from
->
machine
);
if
(
flags
&
SERVER_CTX_CONTROL
)
to
->
ctl
=
from
->
ctl
;
if
(
flags
&
SERVER_CTX_INTEGER
)
to
->
integer
=
from
->
integer
;
if
(
flags
&
SERVER_CTX_SEGMENTS
)
to
->
seg
=
from
->
seg
;
...
...
@@ -1305,14 +1305,14 @@ static void copy_context( context_t *to, const context_t *from, unsigned int fla
/* return the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
static
unsigned
int
get_context_system_regs
(
enum
cpu_type
cpu
)
static
unsigned
int
get_context_system_regs
(
unsigned
short
machine
)
{
switch
(
cpu
)
switch
(
machine
)
{
case
CPU_x86
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
CPU_x86_64
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
CPU_ARM
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
CPU_ARM64
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
IMAGE_FILE_MACHINE_I386
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
IMAGE_FILE_MACHINE_AMD64
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
IMAGE_FILE_MACHINE_ARMNT
:
return
SERVER_CTX_DEBUG_REGISTERS
;
case
IMAGE_FILE_MACHINE_ARM64
:
return
SERVER_CTX_DEBUG_REGISTERS
;
}
return
0
;
}
...
...
@@ -1619,7 +1619,8 @@ DECL_HANDLER(select)
if
(
get_req_data_size
()
-
sizeof
(
*
result
)
-
req
->
size
==
sizeof
(
context_t
))
{
const
context_t
*
context
=
(
const
context_t
*
)((
const
char
*
)(
result
+
1
)
+
req
->
size
);
if
((
current
->
context
&&
current
->
context
->
status
!=
STATUS_PENDING
)
||
context
->
cpu
!=
current
->
process
->
cpu
)
if
((
current
->
context
&&
current
->
context
->
status
!=
STATUS_PENDING
)
||
context
->
machine
!=
current
->
process
->
machine
)
{
set_error
(
STATUS_INVALID_PARAMETER
);
return
;
...
...
@@ -1627,7 +1628,7 @@ DECL_HANDLER(select)
if
(
!
current
->
context
&&
!
(
current
->
context
=
create_thread_context
(
current
)))
return
;
copy_context
(
&
current
->
context
->
regs
,
context
,
context
->
flags
&
~
(
current
->
context
->
regs
.
flags
|
get_context_system_regs
(
current
->
process
->
cpu
))
);
context
->
flags
&
~
(
current
->
context
->
regs
.
flags
|
get_context_system_regs
(
current
->
process
->
machine
))
);
current
->
context
->
status
=
STATUS_SUCCESS
;
current
->
suspend_cookie
=
req
->
cookie
;
wake_up
(
&
current
->
context
->
obj
,
0
);
...
...
@@ -1701,7 +1702,7 @@ DECL_HANDLER(select)
{
if
(
current
->
context
->
regs
.
flags
)
{
unsigned
int
system_flags
=
get_context_system_regs
(
current
->
process
->
cpu
)
&
unsigned
int
system_flags
=
get_context_system_regs
(
current
->
process
->
machine
)
&
current
->
context
->
regs
.
flags
;
if
(
system_flags
)
set_thread_context
(
current
,
&
current
->
context
->
regs
,
system_flags
);
set_reply_data
(
&
current
->
context
->
regs
,
sizeof
(
context_t
)
);
...
...
@@ -1841,12 +1842,12 @@ DECL_HANDLER(get_thread_context)
if
((
thread_context
=
(
struct
context
*
)
get_handle_obj
(
current
->
process
,
req
->
handle
,
0
,
&
context_ops
)))
{
close_handle
(
current
->
process
,
req
->
handle
);
/* avoid extra server call */
system_flags
=
get_context_system_regs
(
thread_context
->
regs
.
cpu
);
system_flags
=
get_context_system_regs
(
thread_context
->
regs
.
machine
);
}
else
if
((
thread
=
get_thread_from_handle
(
req
->
handle
,
THREAD_GET_CONTEXT
)))
{
clear_error
();
system_flags
=
get_context_system_regs
(
thread
->
process
->
cpu
);
system_flags
=
get_context_system_regs
(
thread
->
process
->
machine
);
if
(
thread
->
state
==
RUNNING
)
{
reply
->
self
=
(
thread
==
current
);
...
...
@@ -1862,7 +1863,7 @@ DECL_HANDLER(get_thread_context)
{
assert
(
reply
->
self
);
memset
(
context
,
0
,
sizeof
(
context_t
)
);
context
->
cpu
=
thread
->
process
->
cpu
;
context
->
machine
=
thread
->
process
->
machine
;
if
(
req
->
flags
&
system_flags
)
{
get_thread_context
(
thread
,
context
,
req
->
flags
&
system_flags
);
...
...
@@ -1879,7 +1880,7 @@ DECL_HANDLER(get_thread_context)
if
(
!
thread_context
->
status
&&
(
context
=
set_reply_data_size
(
sizeof
(
context_t
)
)))
{
memset
(
context
,
0
,
sizeof
(
context_t
)
);
context
->
cpu
=
thread_context
->
regs
.
cpu
;
context
->
machine
=
thread_context
->
regs
.
machine
;
copy_context
(
context
,
&
thread_context
->
regs
,
req
->
flags
);
context
->
flags
=
req
->
flags
;
}
...
...
@@ -1906,9 +1907,9 @@ DECL_HANDLER(set_thread_context)
reply
->
self
=
(
thread
==
current
);
if
(
thread
->
state
==
TERMINATED
)
set_error
(
STATUS_UNSUCCESSFUL
);
else
if
(
context
->
cpu
==
thread
->
process
->
cpu
)
else
if
(
context
->
machine
==
thread
->
process
->
machine
)
{
unsigned
int
system_flags
=
get_context_system_regs
(
context
->
cpu
)
&
context
->
flags
;
unsigned
int
system_flags
=
get_context_system_regs
(
context
->
machine
)
&
context
->
flags
;
if
(
thread
!=
current
)
stop_thread
(
thread
);
else
if
(
system_flags
)
set_thread_context
(
thread
,
context
,
system_flags
);
...
...
@@ -1918,10 +1919,11 @@ DECL_HANDLER(set_thread_context)
thread
->
context
->
regs
.
flags
|=
context
->
flags
;
}
}
else
if
(
context
->
cpu
==
CPU_x86_64
&&
thread
->
process
->
cpu
==
CPU_x86
)
else
if
(
context
->
machine
==
IMAGE_FILE_MACHINE_AMD64
&&
thread
->
process
->
machine
==
IMAGE_FILE_MACHINE_I386
)
{
/* convert the WoW64 context */
unsigned
int
system_flags
=
get_context_system_regs
(
context
->
cpu
)
&
context
->
flags
;
unsigned
int
system_flags
=
get_context_system_regs
(
context
->
machine
)
&
context
->
flags
;
if
(
system_flags
)
{
set_thread_context
(
thread
,
context
,
system_flags
);
...
...
server/trace.c
View file @
308bd357
...
...
@@ -616,11 +616,10 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
memset
(
&
ctx
,
0
,
sizeof
(
ctx
)
);
memcpy
(
&
ctx
,
context
,
size
);
fprintf
(
stderr
,
"%s{"
,
prefix
);
dump_client_cpu
(
"cpu="
,
&
ctx
.
cpu
);
switch
(
ctx
.
cpu
)
switch
(
ctx
.
machine
)
{
case
CPU_x86
:
case
IMAGE_FILE_MACHINE_I386
:
fprintf
(
stderr
,
"%s{machine=i386"
,
prefix
);
if
(
ctx
.
flags
&
SERVER_CTX_CONTROL
)
fprintf
(
stderr
,
",eip=%08x,esp=%08x,ebp=%08x,eflags=%08x,cs=%04x,ss=%04x"
,
ctx
.
ctl
.
i386_regs
.
eip
,
ctx
.
ctl
.
i386_regs
.
esp
,
ctx
.
ctl
.
i386_regs
.
ebp
,
...
...
@@ -658,7 +657,8 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
dump_uints
(
",ymm_high="
,
(
const
unsigned
int
*
)
ctx
.
ymm
.
ymm_high_regs
.
ymm_high
,
sizeof
(
ctx
.
ymm
.
ymm_high_regs
)
/
sizeof
(
int
)
);
break
;
case
CPU_x86_64
:
case
IMAGE_FILE_MACHINE_AMD64
:
fprintf
(
stderr
,
"%s{machine=x86_64"
,
prefix
);
if
(
ctx
.
flags
&
SERVER_CTX_CONTROL
)
{
dump_uint64
(
",rip="
,
&
ctx
.
ctl
.
x86_64_regs
.
rip
);
...
...
@@ -710,7 +710,8 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
dump_uints
(
",ymm_high="
,
(
const
unsigned
int
*
)
ctx
.
ymm
.
ymm_high_regs
.
ymm_high
,
sizeof
(
ctx
.
ymm
.
ymm_high_regs
)
/
sizeof
(
int
)
);
break
;
case
CPU_ARM
:
case
IMAGE_FILE_MACHINE_ARMNT
:
fprintf
(
stderr
,
"%s{machine=arm"
,
prefix
);
if
(
ctx
.
flags
&
SERVER_CTX_CONTROL
)
fprintf
(
stderr
,
",sp=%08x,lr=%08x,pc=%08x,cpsr=%08x"
,
ctx
.
ctl
.
arm_regs
.
sp
,
ctx
.
ctl
.
arm_regs
.
lr
,
...
...
@@ -735,7 +736,8 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
fprintf
(
stderr
,
",fpscr=%08x"
,
ctx
.
fp
.
arm_regs
.
fpscr
);
}
break
;
case
CPU_ARM64
:
case
IMAGE_FILE_MACHINE_ARM64
:
fprintf
(
stderr
,
"%s{machine=arm64"
,
prefix
);
if
(
ctx
.
flags
&
SERVER_CTX_CONTROL
)
{
dump_uint64
(
",sp="
,
&
ctx
.
ctl
.
arm64_regs
.
sp
);
...
...
@@ -774,6 +776,9 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
fprintf
(
stderr
,
",fpcr=%08x,fpsr=%08x"
,
ctx
.
fp
.
arm64_regs
.
fpcr
,
ctx
.
fp
.
arm64_regs
.
fpsr
);
}
break
;
default:
fprintf
(
stderr
,
"%s{machine=%04x"
,
prefix
,
ctx
.
machine
);
break
;
}
fputc
(
'}'
,
stderr
);
remove_data
(
size
);
...
...
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