blob: 455fc8352d52fe387c94e024fef8e088500cde7c [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2013-2014 Google, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* kernel32.dll and kernelbase.dll process and thread redirection routines */
#include "kernel32_redir.h" /* must be included first */
#include "../../globals.h"
#include "instrument.h"
#include "drwinapi_private.h"
#include "ntdll_redir.h"
/* FIXME i#1063: add the rest of the routines in kernel32_redir.h under
* Processes and Threads
*/
#define FLS_MAX_COUNT 128
void
kernel32_redir_init_proc(void)
{
PEB *peb = get_own_peb();
ASSERT(get_os_version() < WINDOWS_VERSION_2003 ||
peb->FlsBitmap->SizeOfBitMap == FLS_MAX_COUNT);
#ifdef CLIENT_INTERFACE
/* We rely on -private_peb for FLS isolation. Otherwise we'd have to
* put back in place all the code to handle mixing private and app FLS
* callbacks, and we'd have to tweak our FLS redirection.
*/
ASSERT(INTERNAL_OPTION(private_peb));
#endif
}
void
kernel32_redir_exit_proc(void)
{
}
void
kernel32_redir_onload_proc(privmod_t *mod, strhash_table_t *kernel32_table)
{
if (get_proc_address_ex(mod->base, "FlsAlloc", NULL) == NULL) {
/* i#1385: msvc110+ calls GetProcAddress on FlsAlloc and we want it to
* return NULL if there is no underlying FlsAlloc.
*/
IF_DEBUG(bool found =)
strhash_hash_remove(GLOBAL_DCONTEXT, kernel32_table, "FlsAlloc");
ASSERT(found);
}
}
/***************************************************************************
* PROCESSES
*/
HANDLE
WINAPI
redirect_GetCurrentProcess(
VOID
)
{
return NT_CURRENT_PROCESS;
}
DWORD
WINAPI
redirect_GetCurrentProcessId(
VOID
)
{
return (DWORD) get_process_id();
}
DECLSPEC_NORETURN
VOID
WINAPI
redirect_ExitProcess(
__in UINT uExitCode
)
{
#ifdef CLIENT_INTERFACE
dr_exit_process(uExitCode);
#else
os_terminate_with_code(get_thread_private_dcontext(), /* dcontext is required */
TERMINATE_CLEANUP|TERMINATE_PROCESS, uExitCode);
#endif
ASSERT_NOT_REACHED();
}
/***************************************************************************
* THREADS
*/
HANDLE
WINAPI
redirect_GetCurrentThread(
VOID
)
{
return NT_CURRENT_THREAD;
}
DWORD
WINAPI
redirect_GetCurrentThreadId(
VOID
)
{
return (DWORD) get_thread_id();
}
/***************************************************************************
* FLS
*/
DWORD WINAPI
redirect_FlsAlloc(PFLS_CALLBACK_FUNCTION cb)
{
DWORD index;
NTSTATUS res = redirect_RtlFlsAlloc(cb, &index);
if (NT_SUCCESS(res))
return index;
else {
set_last_error(ntstatus_to_last_error(res));
return FLS_OUT_OF_INDEXES;
}
}
BOOL WINAPI
redirect_FlsFree(DWORD index)
{
NTSTATUS res = redirect_RtlFlsFree(index);
if (NT_SUCCESS(res))
return TRUE;
else {
set_last_error(ntstatus_to_last_error(res));
return FALSE;
}
}
PVOID WINAPI
redirect_FlsGetValue(DWORD index)
{
TEB *teb = get_own_teb();
if (index >= FLS_MAX_COUNT || teb->FlsData == NULL) {
set_last_error(ERROR_INVALID_PARAMETER);
return NULL;
} else {
return teb->FlsData[index + TEB_FLS_DATA_OFFS];
}
}
BOOL WINAPI
redirect_FlsSetValue(DWORD index, PVOID value)
{
TEB *teb = get_own_teb();
if (index >= FLS_MAX_COUNT) {
set_last_error(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (teb->FlsData == NULL) {
NTSTATUS res = redirect_RtlProcessFlsData(0);
if (!NT_SUCCESS(res)) {
set_last_error(ntstatus_to_last_error(res));
return FALSE;
}
}
teb->FlsData[index + TEB_FLS_DATA_OFFS] = value;
return TRUE;
}
/***************************************************************************
* TESTS
*/
#ifdef STANDALONE_UNIT_TEST
void
unit_test_drwinapi_kernel32_proc(void)
{
print_file(STDERR, "testing drwinapi kernel32 control-related routines\n");
EXPECT(redirect_GetCurrentProcess() == GetCurrentProcess(), true);
EXPECT(redirect_GetCurrentProcessId() == GetCurrentProcessId(), true);
EXPECT(redirect_GetCurrentThread() == GetCurrentThread(), true);
EXPECT(redirect_GetCurrentThreadId() == GetCurrentThreadId(), true);
}
#endif