4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <sys/types.h>
32 #define WIN32_NO_STATUS
33 #include "wine/debug.h"
36 #include "ntdll_misc.h"
37 #include "wine/exception.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(process
);
42 /******************************************************************************
43 * RtlGetCurrentPeb [NTDLL.@]
46 PEB
* WINAPI
RtlGetCurrentPeb(void)
48 return NtCurrentTeb()->Peb
;
52 /******************************************************************
53 * RtlWow64EnableFsRedirection (NTDLL.@)
55 NTSTATUS WINAPI
RtlWow64EnableFsRedirection( BOOLEAN enable
)
57 if (!NtCurrentTeb64()) return STATUS_NOT_IMPLEMENTED
;
58 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = !enable
;
59 return STATUS_SUCCESS
;
63 /******************************************************************
64 * RtlWow64EnableFsRedirectionEx (NTDLL.@)
66 NTSTATUS WINAPI
RtlWow64EnableFsRedirectionEx( ULONG disable
, ULONG
*old_value
)
68 if (!NtCurrentTeb64()) return STATUS_NOT_IMPLEMENTED
;
72 *old_value
= NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
];
76 return STATUS_ACCESS_VIOLATION
;
80 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = disable
;
81 return STATUS_SUCCESS
;
85 /**********************************************************************
86 * RtlWow64GetCurrentMachine (NTDLL.@)
88 USHORT WINAPI
RtlWow64GetCurrentMachine(void)
90 USHORT current
, native
;
92 RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t
, &native
);
93 return current
? current
: native
;
97 /**********************************************************************
98 * RtlWow64GetProcessMachines (NTDLL.@)
100 NTSTATUS WINAPI
RtlWow64GetProcessMachines( HANDLE process
, USHORT
*current_ret
, USHORT
*native_ret
)
102 ULONG i
, machines
[8];
103 USHORT current
= 0, native
= 0;
106 status
= NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures
, &process
, sizeof(process
),
107 machines
, sizeof(machines
), NULL
);
108 if (status
) return status
;
109 for (i
= 0; machines
[i
]; i
++)
111 USHORT flags
= HIWORD(machines
[i
]);
112 USHORT machine
= LOWORD(machines
[i
]);
113 if (flags
& 4 /* native machine */) native
= machine
;
114 else if (flags
& 8 /* current machine */) current
= machine
;
116 if (current_ret
) *current_ret
= current
;
117 if (native_ret
) *native_ret
= native
;
122 /**********************************************************************
123 * RtlWow64IsWowGuestMachineSupported (NTDLL.@)
125 NTSTATUS WINAPI
RtlWow64IsWowGuestMachineSupported( USHORT machine
, BOOLEAN
*supported
)
127 ULONG i
, machines
[8];
131 status
= NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures
, &process
, sizeof(process
),
132 machines
, sizeof(machines
), NULL
);
133 if (status
) return status
;
135 for (i
= 0; machines
[i
]; i
++)
137 if (HIWORD(machines
[i
]) & 4 /* native machine */) continue;
138 if (machine
== LOWORD(machines
[i
])) *supported
= TRUE
;
146 /**********************************************************************
147 * RtlWow64GetCpuAreaInfo (NTDLL.@)
149 NTSTATUS WINAPI
RtlWow64GetCpuAreaInfo( WOW64_CPURESERVED
*cpu
, ULONG reserved
, WOW64_CPU_AREA_INFO
*info
)
151 static const struct { ULONG machine
, align
, size
, offset
, flag
; } data
[] =
153 #define ENTRY(machine,type,flag) { machine, TYPE_ALIGNMENT(type), sizeof(type), offsetof(type,ContextFlags), flag },
154 ENTRY( IMAGE_FILE_MACHINE_I386
, I386_CONTEXT
, CONTEXT_i386
)
155 ENTRY( IMAGE_FILE_MACHINE_AMD64
, AMD64_CONTEXT
, CONTEXT_AMD64
)
156 ENTRY( IMAGE_FILE_MACHINE_ARMNT
, ARM_CONTEXT
, CONTEXT_ARM
)
157 ENTRY( IMAGE_FILE_MACHINE_ARM64
, ARM64_NT_CONTEXT
, CONTEXT_ARM64
)
162 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
164 #define ALIGN(ptr,align) ((void *)(((ULONG_PTR)(ptr) + (align) - 1) & ~((ULONG_PTR)(align) - 1)))
165 if (data
[i
].machine
!= cpu
->Machine
) continue;
166 info
->Context
= ALIGN( cpu
+ 1, data
[i
].align
);
167 info
->ContextEx
= ALIGN( (char *)info
->Context
+ data
[i
].size
, sizeof(void *) );
168 info
->ContextFlagsLocation
= (char *)info
->Context
+ data
[i
].offset
;
169 info
->ContextFlag
= data
[i
].flag
;
170 info
->CpuReserved
= cpu
;
171 info
->Machine
= data
[i
].machine
;
172 return STATUS_SUCCESS
;
175 return STATUS_INVALID_PARAMETER
;
179 /**********************************************************************
180 * RtlWow64GetCurrentCpuArea (NTDLL.@)
182 NTSTATUS WINAPI
RtlWow64GetCurrentCpuArea( USHORT
*machine
, void **context
, void **context_ex
)
184 WOW64_CPU_AREA_INFO info
;
187 if (!(status
= RtlWow64GetCpuAreaInfo( NtCurrentTeb()->TlsSlots
[WOW64_TLS_CPURESERVED
], 0, &info
)))
189 if (machine
) *machine
= info
.Machine
;
190 if (context
) *context
= info
.Context
;
191 if (context_ex
) *context_ex
= *(void **)info
.ContextEx
;
197 /******************************************************************************
198 * RtlWow64GetThreadContext (NTDLL.@)
200 NTSTATUS WINAPI
RtlWow64GetThreadContext( HANDLE handle
, WOW64_CONTEXT
*context
)
202 return NtQueryInformationThread( handle
, ThreadWow64Context
, context
, sizeof(*context
), NULL
);
206 /******************************************************************************
207 * RtlWow64SetThreadContext (NTDLL.@)
209 NTSTATUS WINAPI
RtlWow64SetThreadContext( HANDLE handle
, const WOW64_CONTEXT
*context
)
211 return NtSetInformationThread( handle
, ThreadWow64Context
, context
, sizeof(*context
) );
214 /******************************************************************************
215 * RtlWow64GetThreadSelectorEntry (NTDLL.@)
217 NTSTATUS WINAPI
RtlWow64GetThreadSelectorEntry( HANDLE handle
, THREAD_DESCRIPTOR_INFORMATION
*info
,
218 ULONG size
, ULONG
*retlen
)
221 WOW64_CONTEXT context
= { WOW64_CONTEXT_CONTROL
| WOW64_CONTEXT_SEGMENTS
};
222 LDT_ENTRY entry
= { 0 };
224 if (size
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
225 if (RtlWow64GetThreadContext( handle
, &context
))
227 /* hardcoded values */
228 context
.SegCs
= 0x23;
230 __asm__( "movw %%fs,%0" : "=m" (context
.SegFs
) );
231 __asm__( "movw %%ss,%0" : "=m" (context
.SegSs
) );
233 context
.SegSs
= 0x2b;
234 context
.SegFs
= 0x53;
238 sel
= info
->Selector
| 3;
239 if (sel
== 0x03) goto done
; /* null selector */
241 /* set common data */
242 entry
.HighWord
.Bits
.Dpl
= 3;
243 entry
.HighWord
.Bits
.Pres
= 1;
244 entry
.HighWord
.Bits
.Default_Big
= 1;
245 if (sel
== context
.SegCs
) /* code selector */
247 entry
.LimitLow
= 0xffff;
248 entry
.HighWord
.Bits
.LimitHi
= 0xf;
249 entry
.HighWord
.Bits
.Type
= 0x1b; /* code */
250 entry
.HighWord
.Bits
.Granularity
= 1;
252 else if (sel
== context
.SegSs
) /* data selector */
254 entry
.LimitLow
= 0xffff;
255 entry
.HighWord
.Bits
.LimitHi
= 0xf;
256 entry
.HighWord
.Bits
.Type
= 0x13; /* data */
257 entry
.HighWord
.Bits
.Granularity
= 1;
259 else if (sel
== context
.SegFs
) /* TEB selector */
261 THREAD_BASIC_INFORMATION tbi
;
263 entry
.LimitLow
= 0xfff;
264 entry
.HighWord
.Bits
.Type
= 0x13; /* data */
265 if (!NtQueryInformationThread( handle
, ThreadBasicInformation
, &tbi
, sizeof(tbi
), NULL
))
267 ULONG addr
= (ULONG_PTR
)tbi
.TebBaseAddress
+ 0x2000; /* 32-bit teb offset */
268 entry
.BaseLow
= addr
;
269 entry
.HighWord
.Bytes
.BaseMid
= addr
>> 16;
270 entry
.HighWord
.Bytes
.BaseHi
= addr
>> 24;
273 else return STATUS_UNSUCCESSFUL
;
277 if (retlen
) *retlen
= sizeof(entry
);
278 return STATUS_SUCCESS
;
283 /**********************************************************************
284 * RtlCreateUserProcess (NTDLL.@)
286 NTSTATUS WINAPI
RtlCreateUserProcess( UNICODE_STRING
*path
, ULONG attributes
,
287 RTL_USER_PROCESS_PARAMETERS
*params
,
288 SECURITY_DESCRIPTOR
*process_descr
,
289 SECURITY_DESCRIPTOR
*thread_descr
,
290 HANDLE parent
, BOOLEAN inherit
, HANDLE debug
, HANDLE token
,
291 RTL_USER_PROCESS_INFORMATION
*info
)
293 OBJECT_ATTRIBUTES process_attr
, thread_attr
;
294 PS_CREATE_INFO create_info
;
295 ULONG_PTR buffer
[offsetof( PS_ATTRIBUTE_LIST
, Attributes
[6] ) / sizeof(ULONG_PTR
)];
296 PS_ATTRIBUTE_LIST
*attr
= (PS_ATTRIBUTE_LIST
*)buffer
;
299 RtlNormalizeProcessParams( params
);
301 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_IMAGE_NAME
;
302 attr
->Attributes
[pos
].Size
= path
->Length
;
303 attr
->Attributes
[pos
].ValuePtr
= path
->Buffer
;
304 attr
->Attributes
[pos
].ReturnLength
= NULL
;
306 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_CLIENT_ID
;
307 attr
->Attributes
[pos
].Size
= sizeof(info
->ClientId
);
308 attr
->Attributes
[pos
].ValuePtr
= &info
->ClientId
;
309 attr
->Attributes
[pos
].ReturnLength
= NULL
;
311 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_IMAGE_INFO
;
312 attr
->Attributes
[pos
].Size
= sizeof(info
->ImageInformation
);
313 attr
->Attributes
[pos
].ValuePtr
= &info
->ImageInformation
;
314 attr
->Attributes
[pos
].ReturnLength
= NULL
;
318 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_PARENT_PROCESS
;
319 attr
->Attributes
[pos
].Size
= sizeof(parent
);
320 attr
->Attributes
[pos
].ValuePtr
= parent
;
321 attr
->Attributes
[pos
].ReturnLength
= NULL
;
326 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_DEBUG_PORT
;
327 attr
->Attributes
[pos
].Size
= sizeof(debug
);
328 attr
->Attributes
[pos
].ValuePtr
= debug
;
329 attr
->Attributes
[pos
].ReturnLength
= NULL
;
334 attr
->Attributes
[pos
].Attribute
= PS_ATTRIBUTE_TOKEN
;
335 attr
->Attributes
[pos
].Size
= sizeof(token
);
336 attr
->Attributes
[pos
].ValuePtr
= token
;
337 attr
->Attributes
[pos
].ReturnLength
= NULL
;
340 attr
->TotalLength
= offsetof( PS_ATTRIBUTE_LIST
, Attributes
[pos
] );
342 InitializeObjectAttributes( &process_attr
, NULL
, 0, NULL
, process_descr
);
343 InitializeObjectAttributes( &thread_attr
, NULL
, 0, NULL
, thread_descr
);
345 return NtCreateUserProcess( &info
->Process
, &info
->Thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
346 &process_attr
, &thread_attr
,
347 inherit
? PROCESS_CREATE_FLAGS_INHERIT_HANDLES
: 0,
348 THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, params
,
349 &create_info
, attr
);
352 /***********************************************************************
353 * DbgUiGetThreadDebugObject (NTDLL.@)
355 HANDLE WINAPI
DbgUiGetThreadDebugObject(void)
357 return NtCurrentTeb()->DbgSsReserved
[1];
360 /***********************************************************************
361 * DbgUiSetThreadDebugObject (NTDLL.@)
363 void WINAPI
DbgUiSetThreadDebugObject( HANDLE handle
)
365 NtCurrentTeb()->DbgSsReserved
[1] = handle
;
368 /***********************************************************************
369 * DbgUiConnectToDbg (NTDLL.@)
371 NTSTATUS WINAPI
DbgUiConnectToDbg(void)
375 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
377 if (DbgUiGetThreadDebugObject()) return STATUS_SUCCESS
; /* already connected */
379 status
= NtCreateDebugObject( &handle
, DEBUG_ALL_ACCESS
, &attr
, DEBUG_KILL_ON_CLOSE
);
380 if (!status
) DbgUiSetThreadDebugObject( handle
);
384 /***********************************************************************
385 * DbgUiDebugActiveProcess (NTDLL.@)
387 NTSTATUS WINAPI
DbgUiDebugActiveProcess( HANDLE process
)
391 if ((status
= NtDebugActiveProcess( process
, DbgUiGetThreadDebugObject() ))) return status
;
392 if ((status
= DbgUiIssueRemoteBreakin( process
))) DbgUiStopDebugging( process
);
396 /***********************************************************************
397 * DbgUiStopDebugging (NTDLL.@)
399 NTSTATUS WINAPI
DbgUiStopDebugging( HANDLE process
)
401 return NtRemoveProcessDebug( process
, DbgUiGetThreadDebugObject() );
404 /***********************************************************************
405 * DbgUiContinue (NTDLL.@)
407 NTSTATUS WINAPI
DbgUiContinue( CLIENT_ID
*client
, NTSTATUS status
)
409 return NtDebugContinue( DbgUiGetThreadDebugObject(), client
, status
);
412 /***********************************************************************
413 * DbgUiWaitStateChange (NTDLL.@)
415 NTSTATUS WINAPI
DbgUiWaitStateChange( DBGUI_WAIT_STATE_CHANGE
*state
, LARGE_INTEGER
*timeout
)
417 return NtWaitForDebugEvent( DbgUiGetThreadDebugObject(), TRUE
, timeout
, state
);
420 /* helper for DbgUiConvertStateChangeStructure */
421 static inline void *get_thread_teb( HANDLE thread
)
423 THREAD_BASIC_INFORMATION info
;
425 if (NtQueryInformationThread( thread
, ThreadBasicInformation
, &info
, sizeof(info
), NULL
)) return NULL
;
426 return info
.TebBaseAddress
;
429 /***********************************************************************
430 * DbgUiConvertStateChangeStructure (NTDLL.@)
432 NTSTATUS WINAPI
DbgUiConvertStateChangeStructure( DBGUI_WAIT_STATE_CHANGE
*state
, DEBUG_EVENT
*event
)
434 event
->dwProcessId
= HandleToULong( state
->AppClientId
.UniqueProcess
);
435 event
->dwThreadId
= HandleToULong( state
->AppClientId
.UniqueThread
);
436 switch (state
->NewState
)
438 case DbgCreateThreadStateChange
:
440 DBGUI_CREATE_THREAD
*info
= &state
->StateInfo
.CreateThread
;
441 event
->dwDebugEventCode
= CREATE_THREAD_DEBUG_EVENT
;
442 event
->u
.CreateThread
.hThread
= info
->HandleToThread
;
443 event
->u
.CreateThread
.lpThreadLocalBase
= get_thread_teb( info
->HandleToThread
);
444 event
->u
.CreateThread
.lpStartAddress
= info
->NewThread
.StartAddress
;
447 case DbgCreateProcessStateChange
:
449 DBGUI_CREATE_PROCESS
*info
= &state
->StateInfo
.CreateProcessInfo
;
450 event
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
451 event
->u
.CreateProcessInfo
.hFile
= info
->NewProcess
.FileHandle
;
452 event
->u
.CreateProcessInfo
.hProcess
= info
->HandleToProcess
;
453 event
->u
.CreateProcessInfo
.hThread
= info
->HandleToThread
;
454 event
->u
.CreateProcessInfo
.lpBaseOfImage
= info
->NewProcess
.BaseOfImage
;
455 event
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
= info
->NewProcess
.DebugInfoFileOffset
;
456 event
->u
.CreateProcessInfo
.nDebugInfoSize
= info
->NewProcess
.DebugInfoSize
;
457 event
->u
.CreateProcessInfo
.lpThreadLocalBase
= get_thread_teb( info
->HandleToThread
);
458 event
->u
.CreateProcessInfo
.lpStartAddress
= info
->NewProcess
.InitialThread
.StartAddress
;
459 event
->u
.CreateProcessInfo
.lpImageName
= NULL
;
460 event
->u
.CreateProcessInfo
.fUnicode
= TRUE
;
463 case DbgExitThreadStateChange
:
465 DBGKM_EXIT_THREAD
*info
= &state
->StateInfo
.ExitThread
;
466 event
->dwDebugEventCode
= EXIT_THREAD_DEBUG_EVENT
;
467 event
->u
.ExitThread
.dwExitCode
= info
->ExitStatus
;
470 case DbgExitProcessStateChange
:
472 DBGKM_EXIT_PROCESS
*info
= &state
->StateInfo
.ExitProcess
;
473 event
->dwDebugEventCode
= EXIT_PROCESS_DEBUG_EVENT
;
474 event
->u
.ExitProcess
.dwExitCode
= info
->ExitStatus
;
477 case DbgExceptionStateChange
:
478 case DbgBreakpointStateChange
:
479 case DbgSingleStepStateChange
:
481 DBGKM_EXCEPTION
*info
= &state
->StateInfo
.Exception
;
482 DWORD code
= info
->ExceptionRecord
.ExceptionCode
;
483 if (code
== DBG_PRINTEXCEPTION_C
&& info
->ExceptionRecord
.NumberParameters
>= 2)
485 event
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
486 event
->u
.DebugString
.lpDebugStringData
= (void *)info
->ExceptionRecord
.ExceptionInformation
[1];
487 event
->u
.DebugString
.fUnicode
= FALSE
;
488 event
->u
.DebugString
.nDebugStringLength
= info
->ExceptionRecord
.ExceptionInformation
[0];
490 else if (code
== DBG_RIPEXCEPTION
&& info
->ExceptionRecord
.NumberParameters
>= 2)
492 event
->dwDebugEventCode
= RIP_EVENT
;
493 event
->u
.RipInfo
.dwError
= info
->ExceptionRecord
.ExceptionInformation
[0];
494 event
->u
.RipInfo
.dwType
= info
->ExceptionRecord
.ExceptionInformation
[1];
498 event
->dwDebugEventCode
= EXCEPTION_DEBUG_EVENT
;
499 event
->u
.Exception
.ExceptionRecord
= info
->ExceptionRecord
;
500 event
->u
.Exception
.dwFirstChance
= info
->FirstChance
;
504 case DbgLoadDllStateChange
:
506 DBGKM_LOAD_DLL
*info
= &state
->StateInfo
.LoadDll
;
507 event
->dwDebugEventCode
= LOAD_DLL_DEBUG_EVENT
;
508 event
->u
.LoadDll
.hFile
= info
->FileHandle
;
509 event
->u
.LoadDll
.lpBaseOfDll
= info
->BaseOfDll
;
510 event
->u
.LoadDll
.dwDebugInfoFileOffset
= info
->DebugInfoFileOffset
;
511 event
->u
.LoadDll
.nDebugInfoSize
= info
->DebugInfoSize
;
512 event
->u
.LoadDll
.lpImageName
= info
->NamePointer
;
513 event
->u
.LoadDll
.fUnicode
= TRUE
;
516 case DbgUnloadDllStateChange
:
518 DBGKM_UNLOAD_DLL
*info
= &state
->StateInfo
.UnloadDll
;
519 event
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
520 event
->u
.UnloadDll
.lpBaseOfDll
= info
->BaseAddress
;
524 return STATUS_UNSUCCESSFUL
;
526 return STATUS_SUCCESS
;
529 /***********************************************************************
530 * DbgUiRemoteBreakin (NTDLL.@)
532 void WINAPI
DbgUiRemoteBreakin( void *arg
)
535 if (NtCurrentTeb()->Peb
->BeingDebugged
)
547 RtlExitUserThread( STATUS_SUCCESS
);
550 /***********************************************************************
551 * DbgUiIssueRemoteBreakin (NTDLL.@)
553 NTSTATUS WINAPI
DbgUiIssueRemoteBreakin( HANDLE process
)
557 OBJECT_ATTRIBUTES attr
= { sizeof(attr
) };
559 status
= NtCreateThreadEx( &handle
, THREAD_ALL_ACCESS
, &attr
, process
,
560 DbgUiRemoteBreakin
, NULL
, 0, 0, 0, 0, NULL
);
562 /* FIXME: hack for debugging 32-bit wow64 process without a 64-bit ntdll */
563 if (status
== STATUS_INVALID_PARAMETER
)
566 if (!NtQueryInformationProcess( process
, ProcessWow64Information
, &wow
, sizeof(wow
), NULL
) && wow
)
567 status
= NtCreateThreadEx( &handle
, THREAD_ALL_ACCESS
, &attr
, process
,
568 (void *)0x7ffe1000, NULL
, 0, 0, 0, 0, NULL
);
571 if (!status
) NtClose( handle
);