#include "stdafx.h"
+#ifndef FEATURE_PAL
#ifndef _TARGET_X86_
//
#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO
+
BOOL ReadMemory(PVOID pUserContext, LPCVOID lpBaseAddress, PVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead)
{
HANDLE hProcess = (HANDLE)pUserContext;
return STATUS_UNSUCCESSFUL;
}
-
-
#endif // !_TARGET_X86_
+#endif // !FEATURE_PAL
\ No newline at end of file
{
if (m_pDacPrimitives != NULL)
{
- STRESS_LOG1(LF_CORDB, LL_INFO1000, "Flush() - old counter: %d", m_flushCounter);
+ STRESS_LOG1(LF_CORDB, LL_INFO1000, "Flush() - old counter: %d\n", m_flushCounter);
m_flushCounter++;
HRESULT hr = S_OK;
EX_TRY
#ifndef RIGHT_SIDE_COMPILE
-#ifdef FEATURE_PAL
-__attribute__((noinline))
-__attribute__((optnone))
-static void
-ProbeMemory(__in_ecount(cbBuffer) volatile PBYTE pbBuffer, DWORD cbBuffer, bool fWriteAccess)
-{
- // Need an throw in this function to fool the C++ runtime into handling the
- // possible h/w exception below.
- if (pbBuffer == NULL)
- {
- throw PAL_SEHException();
- }
-
- // Simple one byte at a time probing
- while (cbBuffer > 0)
- {
- volatile BYTE read = *pbBuffer;
- if (fWriteAccess)
- {
- *pbBuffer = read;
- }
- ++pbBuffer;
- --cbBuffer;
- }
-}
-#endif // FEATURE_PAL
-
// Check read and optionally write memory access to the specified range of bytes. Used to check
// ReadProcessMemory and WriteProcessMemory requests.
HRESULT DbgTransportSession::CheckBufferAccess(__in_ecount(cbBuffer) PBYTE pbBuffer, DWORD cbBuffer, bool fWriteAccess)
}
while (cbBuffer > 0);
#else
- try
- {
- // Need to explicit h/w exception holder so to catch them in ProbeMemory
- CatchHardwareExceptionHolder __catchHardwareException;
-
- ProbeMemory(pbBuffer, cbBuffer, fWriteAccess);
- }
- catch(...)
+ if (!PAL_ProbeMemory(pbBuffer, cbBuffer, fWriteAccess))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_ADDRESS);
}
PAL_GetTransportPipeName
PAL_InitializeDLL
PAL_IsDebuggerPresent
+PAL_ProbeMemory
PAL_iswspace
PAL_memcpy
PAL_malloc
// Does not include IXClrData definitions.
#include <clrdata.h>
+#ifndef FEATURE_PAL
//---------------------------------------------------------------------------------------
//
CLRDATA_ADDRESS m_baseAddressOfEngine;
};
+#endif // FEATURE_PAL
#endif // _LIVEPROC_DATATARGET_H_
const wchar_t* Compiler::eeGetCPString(size_t strHandle)
{
+#ifdef FEATURE_PAL
+ return nullptr;
+#else
char buff[512 + sizeof(CORINFO_String)];
// make this bulletproof, so it works even if we are wrong.
}
return (asString->chars);
+#endif // FEATURE_PAL
}
#endif // DEBUG
#endif
+PALIMPORT
+BOOL
+PALAPI
+PAL_ProbeMemory(
+ PVOID pBuffer,
+ DWORD cbBuffer,
+ BOOL fWriteAccess);
/******************* winuser.h Entrypoints *******************************/
IN SIZE_T dwLength);
PALIMPORT
-BOOL
-PALAPI
-ReadProcessMemory(
- IN HANDLE hProcess,
- IN LPCVOID lpBaseAddress,
- OUT LPVOID lpBuffer,
- IN SIZE_T nSize,
- OUT SIZE_T * lpNumberOfBytesRead);
-
-PALIMPORT
VOID
PALAPI
RtlMoveMemory(
DWORD UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
-PALIMPORT
-BOOL
-PALAPI
-WriteProcessMemory(IN HANDLE hProcess,
- IN LPVOID lpBaseAddress,
- IN LPCVOID lpBuffer,
- IN SIZE_T nSize,
- OUT SIZE_T * lpNumberOfBytesWritten);
-
#define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
#define SYNCHRONIZE (0x00100000L)
#define READ_CONTROL (0x00020000L)
static const char PAL_RUN_ON_DEBUG_BREAK[] = "PAL_RUN_ON_DEBUG_BREAK";
#endif // ENABLE_RUN_ON_DEBUG_BREAK
-/* ------------------- Static function prototypes ----------------------------*/
-
-#if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
-static int
-DBGWriteProcMem_Int(DWORD processId, int *addr, int data);
-static int
-DBGWriteProcMem_IntWithMask(DWORD processId, int *addr, int data,
- unsigned int mask);
-#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
-
-#if !HAVE_VM_READ && !HAVE_PROCFS_CTL
-
-static BOOL
-DBGAttachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
-
-static BOOL
-DBGDetachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
-
-static int
-DBGSetProcessAttached(CPalThread *pThread, HANDLE hProcess, BOOL bAttach);
-
-#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
-
extern "C" {
/*++
return ret;
}
-#if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
-/*++
-Function:
- DBGWriteProcMem_Int
-
-Abstract
- write one int to a process memory address
-
-Parameter
- processId : process handle
- addr : memory address where the int should be written
- data : int to be written in addr
-
-Return
- Return 1 if it succeeds, or 0 if it's fails
---*/
-static
-int
-DBGWriteProcMem_Int(IN DWORD processId,
- IN int *addr,
- IN int data)
-{
- if (PAL_PTRACE( PAL_PT_WRITE_D, processId, addr, data ) == -1)
- {
- if (errno == EFAULT)
- {
- ERROR("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
- "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
- SetLastError(ERROR_INVALID_ADDRESS);
- }
- else
- {
- ASSERT("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
- "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- return 0;
- }
-
- return 1;
-}
-
-/*++
-Function:
- DBGWriteProcMem_IntWithMask
-
-Abstract
- write one int to a process memory address space using mask
-
-Parameter
- processId : process ID
- addr : memory address where the int should be written
- data : int to be written in addr
- mask : the mask used to write only a parts of data
-
-Return
- Return 1 if it succeeds, or 0 if it's fails
---*/
-static
-int
-DBGWriteProcMem_IntWithMask(IN DWORD processId,
- IN int *addr,
- IN int data,
- IN unsigned int mask )
-{
- int readInt;
-
- if (mask != ~0)
- {
- errno = 0;
- if (((readInt = PAL_PTRACE( PAL_PT_READ_D, processId, addr, 0 )) == -1)
- && errno)
- {
- if (errno == EFAULT)
- {
- ERROR("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
- "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
- SetLastError(ERROR_INVALID_ADDRESS);
- }
- else
- {
- ASSERT("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
- "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
-
- return 0;
- }
- data = (data & mask) | (readInt & ~mask);
- }
- return DBGWriteProcMem_Int(processId, addr, data);
-}
-#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
-
-#if !HAVE_VM_READ && !HAVE_PROCFS_CTL
-
-/*++
-Function:
- DBGAttachProcess
-
-Abstract
-
- Attach the indicated process to the current process.
-
- if the indicated process is already attached by the current process, then
- increment the number of attachment pending. if ot, attach it to the current
- process (with PT_ATTACH).
-
-Parameter
- hProcess : handle to process to attach to
- processId : process ID to attach
-Return
- Return true if it succeeds, or false if it's fails
---*/
-static
-BOOL
-DBGAttachProcess(
- CPalThread *pThread,
- HANDLE hProcess,
- DWORD processId
- )
-{
- int attchmentCount;
- int savedErrno;
-#if HAVE_PROCFS_CTL
- int fd = -1;
- char ctlPath[1024];
-#endif // HAVE_PROCFS_CTL
-
- attchmentCount =
- DBGSetProcessAttached(pThread, hProcess, DBG_ATTACH);
-
- if (attchmentCount == -1)
- {
- /* Failed to set the process as attached */
- goto EXIT;
- }
-
- if (attchmentCount == 1)
- {
-#if HAVE_PROCFS_CTL
- struct timespec waitTime;
-
- // FreeBSD has some trouble when a series of attach/detach sequences
- // occurs too close together. When this happens, we'll be able to
- // attach to the process, but waiting for the process to stop
- // (either via writing "wait" to /proc/<pid>/ctl or via waitpid)
- // will hang. If we pause for a very short amount of time before
- // trying to attach, we don't run into this situation.
- waitTime.tv_sec = 0;
- waitTime.tv_nsec = 50000000;
- nanosleep(&waitTime, NULL);
-
- sprintf_s(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
- fd = InternalOpen(ctlPath, O_WRONLY);
- if (fd == -1)
- {
- ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- goto DETACH1;
- }
-
- if (write(fd, CTL_ATTACH, sizeof(CTL_ATTACH)) < (int)sizeof(CTL_ATTACH))
- {
- ERROR("Failed to attach to %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- close(fd);
- goto DETACH1;
- }
-
- if (write(fd, CTL_WAIT, sizeof(CTL_WAIT)) < (int)sizeof(CTL_WAIT))
- {
- ERROR("Failed to wait for %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- goto DETACH2;
- }
-
- close(fd);
-#elif HAVE_TTRACE
- if (ttrace(TT_PROC_ATTACH, processId, 0, TT_DETACH_ON_EXIT, TT_VERSION, 0) == -1)
- {
- if (errno != ESRCH)
- {
- ASSERT("ttrace(TT_PROC_ATTACH, pid:%d) failed errno:%d (%s)\n",
- processId, errno, strerror(errno));
- }
- goto DETACH1;
- }
-#else // HAVE_TTRACE
- if (PAL_PTRACE( PAL_PT_ATTACH, processId, 0, 0 ) == -1)
- {
- if (errno != ESRCH)
- {
- ASSERT("ptrace(PT_ATTACH, pid:%d) failed errno:%d (%s)\n",
- processId, errno, strerror(errno));
- }
- goto DETACH1;
- }
-
- if (waitpid(processId, NULL, WUNTRACED) == -1)
- {
- if (errno != ESRCH)
- {
- ASSERT("waitpid(pid:%d, NULL, WUNTRACED) failed.errno:%d"
- " (%s)\n", processId, errno, strerror(errno));
- }
- goto DETACH2;
- }
-#endif // HAVE_PROCFS_CTL
- }
-
- return TRUE;
-
-#if HAVE_PROCFS_CTL
-DETACH2:
- if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
- {
- ASSERT("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- }
- close(fd);
-#elif !HAVE_TTRACE
-DETACH2:
- if (PAL_PTRACE(PAL_PT_DETACH, processId, 0, 0) == -1)
- {
- ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n", processId,
- errno, strerror(errno));
- }
-#endif // HAVE_PROCFS_CTL
-
-DETACH1:
- savedErrno = errno;
- DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);
- errno = savedErrno;
-EXIT:
- if (errno == ESRCH || errno == ENOENT || errno == EBADF)
- {
- ERROR("Invalid process ID:%d\n", processId);
- SetLastError(ERROR_INVALID_PARAMETER);
- }
- else
- {
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- return FALSE;
-}
-
-/*++
-Function:
- DBGDetachProcess
-
-Abstract
- Detach the indicated process from the current process.
-
- if the indicated process is already attached by the current process, then
- decrement the number of attachment pending and detach it from the current
- process (with PT_DETACH) if there's no more attachment left.
-
-Parameter
- hProcess : process handle
- processId : process ID
-
-Return
- Return true if it succeeds, or true if it's fails
---*/
-static
-BOOL
-DBGDetachProcess(
- CPalThread *pThread,
- HANDLE hProcess,
- DWORD processId
- )
-{
- int nbAttachLeft;
-#if HAVE_PROCFS_CTL
- int fd = -1;
- char ctlPath[1024];
-#endif // HAVE_PROCFS_CTL
-
- nbAttachLeft = DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);
-
- if (nbAttachLeft == -1)
- {
- /* Failed to set the process as detached */
- return FALSE;
- }
-
- /* check if there's no more attachment left on processId */
- if (nbAttachLeft == 0)
- {
-#if HAVE_PROCFS_CTL
- snprintf(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
- fd = InternalOpen(pThread, ctlPath, O_WRONLY);
- if (fd == -1)
- {
- if (errno == ENOENT)
- {
- ERROR("Invalid process ID: %d\n", processId);
- SetLastError(ERROR_INVALID_PARAMETER);
- }
- else
- {
- ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- return FALSE;
- }
-
- if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
- {
- ERROR("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
- errno, strerror(errno));
- close(fd);
- return FALSE;
- }
- close(fd);
-
-#elif HAVE_TTRACE
- if (ttrace(TT_PROC_DETACH, processId, 0, 0, 0, 0) == -1)
- {
- if (errno == ESRCH)
- {
- ERROR("Invalid process ID: %d\n", processId);
- SetLastError(ERROR_INVALID_PARAMETER);
- }
- else
- {
- ASSERT("ttrace(TT_PROC_DETACH, pid:%d) failed. errno:%d (%s)\n",
- processId, errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- return FALSE;
- }
-#else // HAVE_TTRACE
- if (PAL_PTRACE(PAL_PT_DETACH, processId, 1, 0) == -1)
- {
- if (errno == ESRCH)
- {
- ERROR("Invalid process ID: %d\n", processId);
- SetLastError(ERROR_INVALID_PARAMETER);
- }
- else
- {
- ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n",
- processId, errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- return FALSE;
- }
-#endif // HAVE_PROCFS_CTL
-
-#if !HAVE_TTRACE
- if (kill(processId, SIGCONT) == -1)
- {
- ERROR("Failed to continue the detached process:%d errno:%d (%s)\n",
- processId, errno, strerror(errno));
- return FALSE;
- }
-#endif // !HAVE_TTRACE
- }
- return TRUE;
-}
-
-/*++
-Function:
- DBGSetProcessAttached
-
-Abstract
- saves the current process Id in the attached process structure
-
-Parameter
- hProcess : process handle
- bAttach : true (false) to set the process as attached (as detached)
-Return
- returns the number of attachment left on attachedProcId, or -1 if it fails
---*/
-static int
-DBGSetProcessAttached(
- CPalThread *pThread,
- HANDLE hProcess,
- BOOL bAttach
- )
-{
- PAL_ERROR palError = NO_ERROR;
- IPalObject *pobjProcess = NULL;
- IDataLock *pDataLock = NULL;
- CProcProcessLocalData *pLocalData = NULL;
- int ret = -1;
- CAllowedObjectTypes aotProcess(otiProcess);
-
- palError = g_pObjectManager->ReferenceObjectByHandle(
- pThread,
- hProcess,
- &aotProcess,
- 0,
- &pobjProcess
- );
-
- if (NO_ERROR != palError)
- {
- goto DBGSetProcessAttachedExit;
- }
-
- palError = pobjProcess->GetProcessLocalData(
- pThread,
- WriteLock,
- &pDataLock,
- reinterpret_cast<void **>(&pLocalData)
- );
-
- if (NO_ERROR != palError)
- {
- goto DBGSetProcessAttachedExit;
- }
-
- if (bAttach)
- {
- pLocalData->lAttachCount += 1;
- }
- else
- {
- pLocalData->lAttachCount -= 1;
-
- if (pLocalData->lAttachCount < 0)
- {
- ASSERT("pLocalData->lAttachCount < 0 check for extra DBGDetachProcess calls\n");
- palError = ERROR_INTERNAL_ERROR;
- goto DBGSetProcessAttachedExit;
- }
- }
-
- ret = pLocalData->lAttachCount;
-
-DBGSetProcessAttachedExit:
-
- if (NULL != pDataLock)
- {
- pDataLock->ReleaseLock(pThread, TRUE);
- }
-
- if (NULL != pobjProcess)
- {
- pobjProcess->ReleaseReference(pThread);
- }
-
- return ret;
-}
-
-#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
-
/*++
Function:
PAL_CreateExecWatchpoint
return dwError;
}
-// We want to enable hardware exception handling for ReadProcessMemory
-// and WriteProcessMemory in all cases since it is acceptable if they
-// hit AVs, so redefine HardwareExceptionHolder for these two functions
-// (here to the end of the file).
-#undef HardwareExceptionHolder
-#define HardwareExceptionHolder CatchHardwareExceptionHolder __catchHardwareException;
-
-/*++
-Function:
- ReadProcessMemory
-
-See MSDN doc.
---*/
-BOOL
-PALAPI
-ReadProcessMemory(
- IN HANDLE hProcess,
- IN LPCVOID lpBaseAddress,
- IN LPVOID lpBuffer,
- IN SIZE_T nSize,
- OUT SIZE_T * lpNumberOfBytesRead
- )
+__attribute__((noinline))
+__attribute__((optnone))
+void
+ProbeMemory(volatile PBYTE pbBuffer, DWORD cbBuffer, bool fWriteAccess)
{
- CPalThread *pThread;
- DWORD processId;
- Volatile<BOOL> ret = FALSE;
- Volatile<SIZE_T> numberOfBytesRead = 0;
-#if HAVE_VM_READ
- kern_return_t result;
- vm_map_t task;
- LONG_PTR bytesToRead;
-#elif HAVE_PROCFS_CTL
- int fd = -1;
- char memPath[64];
- off_t offset;
-#elif !HAVE_TTRACE
- SIZE_T nbInts;
- int* ptrInt;
- int* lpTmpBuffer;
-#endif
-#if !HAVE_PROCFS_CTL && !HAVE_TTRACE
- int* lpBaseAddressAligned;
- SIZE_T offset;
-#endif // !HAVE_PROCFS_CTL && !HAVE_TTRACE
-
- PERF_ENTRY(ReadProcessMemory);
- ENTRY("ReadProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
- "nSize=%u, lpNumberOfBytesRead=%p)\n",hProcess,lpBaseAddress,
- lpBuffer, (unsigned int)nSize, lpNumberOfBytesRead);
-
- pThread = InternalGetCurrentThread();
-
- if (!(processId = PROCGetProcessIDFromHandle(hProcess)))
- {
- ERROR("Invalid process handler hProcess:%p.",hProcess);
- SetLastError(ERROR_INVALID_HANDLE);
- goto EXIT;
- }
-
- // Check if the read request is for the current process.
- // We don't need ptrace in that case.
- if (GetCurrentProcessId() == processId)
+ // Need an throw in this function to fool the C++ runtime into handling the
+ // possible h/w exception below.
+ if (pbBuffer == NULL)
{
- TRACE("We are in the same process, so ptrace is not needed\n");
-
- struct Param
- {
- LPCVOID lpBaseAddress;
- LPVOID lpBuffer;
- SIZE_T nSize;
- SIZE_T numberOfBytesRead;
- BOOL ret;
- } param;
- param.lpBaseAddress = lpBaseAddress;
- param.lpBuffer = lpBuffer;
- param.nSize = nSize;
- param.numberOfBytesRead = numberOfBytesRead;
- param.ret = ret;
-
- PAL_TRY(Param *, pParam, ¶m)
- {
- SIZE_T i;
-
- // Seg fault in memcpy can't be caught
- // so we simulate the memcpy here
-
- for (i = 0; i<pParam->nSize; i++)
- {
- *((char*)(pParam->lpBuffer)+i) = *((char*)(pParam->lpBaseAddress)+i);
- }
-
- pParam->numberOfBytesRead = pParam->nSize;
- pParam->ret = TRUE;
- }
- PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- SetLastError(ERROR_ACCESS_DENIED);
- }
- PAL_ENDTRY
-
- numberOfBytesRead = param.numberOfBytesRead;
- ret = param.ret;
- goto EXIT;
+ throw PAL_SEHException();
}
-#if HAVE_VM_READ
- result = task_for_pid(mach_task_self(), processId, &task);
- if (result != KERN_SUCCESS)
+ // Simple one byte at a time probing
+ while (cbBuffer > 0)
{
- ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
- SetLastError(ERROR_INVALID_HANDLE);
- goto EXIT;
- }
- // vm_read_overwrite usually requires that the address be page-aligned
- // and the size be a multiple of the page size. We can't differentiate
- // between the cases in which that's required and those in which it
- // isn't, so we do it all the time.
- lpBaseAddressAligned = (int*)((SIZE_T) lpBaseAddress & ~VIRTUAL_PAGE_MASK);
- offset = ((SIZE_T) lpBaseAddress & VIRTUAL_PAGE_MASK);
- char *data;
- data = (char*)alloca(VIRTUAL_PAGE_SIZE);
- while (nSize > 0)
- {
- vm_size_t bytesRead;
-
- bytesToRead = VIRTUAL_PAGE_SIZE - offset;
- if (bytesToRead > (LONG_PTR)nSize)
- {
- bytesToRead = nSize;
- }
- bytesRead = VIRTUAL_PAGE_SIZE;
- result = vm_read_overwrite(task, (vm_address_t) lpBaseAddressAligned,
- VIRTUAL_PAGE_SIZE, (vm_address_t) data, &bytesRead);
- if (result != KERN_SUCCESS || bytesRead != VIRTUAL_PAGE_SIZE)
+ volatile BYTE read = *pbBuffer;
+ if (fWriteAccess)
{
- ERROR("vm_read_overwrite failed for %d bytes from %p in %d: %d\n",
- VIRTUAL_PAGE_SIZE, (char *) lpBaseAddressAligned, task, result);
- if (result <= KERN_RETURN_MAX)
- {
- SetLastError(ERROR_INVALID_ACCESS);
- }
- else
- {
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- goto EXIT;
+ *pbBuffer = read;
}
- memcpy((LPSTR)lpBuffer + numberOfBytesRead, data + offset, bytesToRead);
- numberOfBytesRead.Store(numberOfBytesRead.Load() + bytesToRead);
- lpBaseAddressAligned = (int*)((char*)lpBaseAddressAligned + VIRTUAL_PAGE_SIZE);
- nSize -= bytesToRead;
- offset = 0;
+ ++pbBuffer;
+ --cbBuffer;
}
- ret = TRUE;
-#else // HAVE_VM_READ
-#if HAVE_PROCFS_CTL
- snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
- fd = InternalOpen(memPath, O_RDONLY);
- if (fd == -1)
- {
- ERROR("Failed to open %s\n", memPath);
- SetLastError(ERROR_INVALID_ACCESS);
- goto PROCFSCLEANUP;
- }
-
- //
- // off_t may be greater in size than void*, so first cast to
- // an unsigned type to ensure that no sign extension takes place
- //
-
- offset = (off_t) (UINT_PTR) lpBaseAddress;
-
- if (lseek(fd, offset, SEEK_SET) == -1)
- {
- ERROR("Failed to seek to base address\n");
- SetLastError(ERROR_INVALID_ACCESS);
- goto PROCFSCLEANUP;
- }
-
- numberOfBytesRead = read(fd, lpBuffer, nSize);
- ret = TRUE;
-
-#else // HAVE_PROCFS_CTL
- // Attach the process before calling ttrace/ptrace otherwise it fails.
- if (DBGAttachProcess(pThread, hProcess, processId))
- {
-#if HAVE_TTRACE
- if (ttrace(TT_PROC_RDDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
- {
- if (errno == EFAULT)
- {
- ERROR("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
- " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
- errno, strerror(errno));
-
- SetLastError(ERROR_ACCESS_DENIED);
- }
- else
- {
- ASSERT("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
- " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
- errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
-
- goto CLEANUP1;
- }
-
- numberOfBytesRead = nSize;
- ret = TRUE;
-
-#else // HAVE_TTRACE
-
- offset = (SIZE_T)lpBaseAddress % sizeof(int);
- lpBaseAddressAligned = (int*)((char*)lpBaseAddress - offset);
- nbInts = (nSize + offset)/sizeof(int) +
- ((nSize + offset)%sizeof(int) ? 1:0);
-
- /* before transferring any data to lpBuffer we should make sure that all
- data is accessible for read. so we need to use a temp buffer for that.*/
- if (!(lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))))
- {
- ERROR("Insufficient memory available !\n");
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- goto CLEANUP1;
- }
-
- for (ptrInt = lpTmpBuffer; nbInts; ptrInt++,
- lpBaseAddressAligned++, nbInts--)
- {
- errno = 0;
- *ptrInt =
- PAL_PTRACE(PAL_PT_READ_D, processId, lpBaseAddressAligned, 0);
- if (*ptrInt == -1 && errno)
- {
- if (errno == EFAULT)
- {
- ERROR("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
- " errno=%d (%s)\n", processId, lpBaseAddressAligned,
- errno, strerror(errno));
-
- SetLastError(ptrInt == lpTmpBuffer ? ERROR_ACCESS_DENIED :
- ERROR_PARTIAL_COPY);
- }
- else
- {
- ASSERT("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
- " errno=%d (%s)\n", processId, lpBaseAddressAligned,
- errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
-
- goto CLEANUP2;
- }
- }
-
- /* transfer data from temp buffer to lpBuffer */
- memcpy( (char *)lpBuffer, ((char*)lpTmpBuffer) + offset, nSize);
- numberOfBytesRead = nSize;
- ret = TRUE;
-#endif // HAVE_TTRACE
- }
- else
- {
- /* Failed to attach processId */
- goto EXIT;
- }
-#endif // HAVE_PROCFS_CTL
-
-#if HAVE_PROCFS_CTL
-PROCFSCLEANUP:
- if (fd != -1)
- {
- close(fd);
- }
-#elif !HAVE_TTRACE
-CLEANUP2:
- if (lpTmpBuffer)
- {
- free(lpTmpBuffer);
- }
-#endif // !HAVE_TTRACE
-
-#if !HAVE_PROCFS_CTL
-CLEANUP1:
- if (!DBGDetachProcess(pThread, hProcess, processId))
- {
- /* Failed to detach processId */
- ret = FALSE;
- }
-#endif // HAVE_PROCFS_CTL
-#endif // HAVE_VM_READ
-
-EXIT:
- if (lpNumberOfBytesRead)
- {
- *lpNumberOfBytesRead = numberOfBytesRead;
- }
- LOGEXIT("ReadProcessMemory returns BOOL %d\n", ret.Load());
- PERF_EXIT(ReadProcessMemory);
- return ret;
}
/*++
Function:
- WriteProcessMemory
+ PAL_ProbeMemory
-See MSDN doc.
+Abstract
+
+Parameter
+ pBuffer : address of memory to validate
+ cbBuffer : size of memory region to validate
+ fWriteAccess : if true, validate writable access, else just readable.
+
+Return
+ true if memory is valid, false if not.
--*/
BOOL
PALAPI
-WriteProcessMemory(
- IN HANDLE hProcess,
- IN LPVOID lpBaseAddress,
- IN LPCVOID lpBuffer,
- IN SIZE_T nSize,
- OUT SIZE_T * lpNumberOfBytesWritten
- )
-
+PAL_ProbeMemory(
+ PVOID pBuffer,
+ DWORD cbBuffer,
+ BOOL fWriteAccess)
{
- CPalThread *pThread;
- DWORD processId;
- Volatile<BOOL> ret = FALSE;
- Volatile<SIZE_T> numberOfBytesWritten = 0;
-#if HAVE_VM_READ
- kern_return_t result;
- vm_map_t task;
-#elif HAVE_PROCFS_CTL
- int fd = -1;
- char memPath[64];
- LONG_PTR bytesWritten;
- off_t offset;
-#elif !HAVE_TTRACE
- SIZE_T FirstIntOffset;
- SIZE_T LastIntOffset;
- unsigned int FirstIntMask;
- unsigned int LastIntMask;
- SIZE_T nbInts;
- int *lpTmpBuffer = 0, *lpInt;
- int* lpBaseAddressAligned;
-#endif
-
- PERF_ENTRY(WriteProcessMemory);
- ENTRY("WriteProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
- "nSize=%u, lpNumberOfBytesWritten=%p)\n",
- hProcess,lpBaseAddress, lpBuffer, (unsigned int)nSize, lpNumberOfBytesWritten);
-
- pThread = InternalGetCurrentThread();
-
- if (!(nSize && (processId = PROCGetProcessIDFromHandle(hProcess))))
- {
- ERROR("Invalid nSize:%u number or invalid process handler "
- "hProcess:%p\n", (unsigned int)nSize, hProcess);
- SetLastError(ERROR_INVALID_PARAMETER);
- goto EXIT;
- }
-
- // Check if the write request is for the current process.
- // In that case we don't need ptrace.
- if (GetCurrentProcessId() == processId)
- {
- TRACE("We are in the same process so we don't need ptrace\n");
-
- struct Param
- {
- LPVOID lpBaseAddress;
- LPCVOID lpBuffer;
- SIZE_T nSize;
- SIZE_T numberOfBytesWritten;
- BOOL ret;
- } param;
- param.lpBaseAddress = lpBaseAddress;
- param.lpBuffer = lpBuffer;
- param.nSize = nSize;
- param.numberOfBytesWritten = numberOfBytesWritten;
- param.ret = ret;
-
- PAL_TRY(Param *, pParam, ¶m)
- {
- SIZE_T i;
-
- // Seg fault in memcpy can't be caught
- // so we simulate the memcpy here
-
- for (i = 0; i<pParam->nSize; i++)
- {
- *((char*)(pParam->lpBaseAddress)+i) = *((char*)(pParam->lpBuffer)+i);
- }
-
- pParam->numberOfBytesWritten = pParam->nSize;
- pParam->ret = TRUE;
- }
- PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- SetLastError(ERROR_ACCESS_DENIED);
- }
- PAL_ENDTRY
-
- numberOfBytesWritten = param.numberOfBytesWritten;
- ret = param.ret;
- goto EXIT;
- }
-
-#if HAVE_VM_READ
- result = task_for_pid(mach_task_self(), processId, &task);
- if (result != KERN_SUCCESS)
- {
- ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
- SetLastError(ERROR_INVALID_HANDLE);
- goto EXIT;
- }
- result = vm_write(task, (vm_address_t) lpBaseAddress,
- (vm_address_t) lpBuffer, nSize);
- if (result != KERN_SUCCESS)
- {
- ERROR("vm_write failed for %d bytes from %p in %d: %d\n",
- (int)nSize, lpBaseAddress, task, result);
- if (result <= KERN_RETURN_MAX)
- {
- SetLastError(ERROR_ACCESS_DENIED);
- }
- else
- {
- SetLastError(ERROR_INTERNAL_ERROR);
- }
- goto EXIT;
- }
- numberOfBytesWritten = nSize;
- ret = TRUE;
-#else // HAVE_VM_READ
-#if HAVE_PROCFS_CTL
- snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
- fd = InternalOpen(memPath, O_WRONLY);
- if (fd == -1)
+ try
{
- ERROR("Failed to open %s\n", memPath);
- SetLastError(ERROR_INVALID_ACCESS);
- goto PROCFSCLEANUP;
- }
-
- //
- // off_t may be greater in size than void*, so first cast to
- // an unsigned type to ensure that no sign extension takes place
- //
-
- offset = (off_t) (UINT_PTR) lpBaseAddress;
+ // Need to explicit h/w exception holder so to catch them in ProbeMemory
+ CatchHardwareExceptionHolder __catchHardwareException;
- if (lseek(fd, offset, SEEK_SET) == -1)
- {
- ERROR("Failed to seek to base address\n");
- SetLastError(ERROR_INVALID_ACCESS);
- goto PROCFSCLEANUP;
+ ProbeMemory((PBYTE)pBuffer, cbBuffer, fWriteAccess);
}
-
- bytesWritten = write(fd, lpBuffer, nSize);
- if (bytesWritten < 0)
- {
- ERROR("Failed to write to %s\n", memPath);
- SetLastError(ERROR_INVALID_ACCESS);
- goto PROCFSCLEANUP;
- }
-
- numberOfBytesWritten = bytesWritten;
- ret = TRUE;
-
-#else // HAVE_PROCFS_CTL
- /* Attach the process before calling ptrace otherwise it fails */
- if (DBGAttachProcess(pThread, hProcess, processId))
+ catch(...)
{
-#if HAVE_TTRACE
- if (ttrace(TT_PROC_WRDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
- {
- if (errno == EFAULT)
- {
- ERROR("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
- " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
- errno, strerror(errno));
-
- SetLastError(ERROR_ACCESS_DENIED);
- }
- else
- {
- ASSERT("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
- " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
- errno, strerror(errno));
- SetLastError(ERROR_INTERNAL_ERROR);
- }
-
- goto CLEANUP1;
- }
-
- numberOfBytesWritten = nSize;
- ret = TRUE;
-
-#else // HAVE_TTRACE
-
- FirstIntOffset = (SIZE_T)lpBaseAddress % sizeof(int);
- FirstIntMask = -1;
- FirstIntMask <<= (FirstIntOffset * 8);
-
- nbInts = (nSize + FirstIntOffset) / sizeof(int) +
- (((nSize + FirstIntOffset)%sizeof(int)) ? 1:0);
- lpBaseAddressAligned = (int*)((char*)lpBaseAddress - FirstIntOffset);
-
- if ((lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))) == NULL)
- {
- ERROR("Insufficient memory available !\n");
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- goto CLEANUP1;
- }
-
- memcpy((char *)lpTmpBuffer + FirstIntOffset, (char *)lpBuffer, nSize);
- lpInt = lpTmpBuffer;
-
- LastIntOffset = (nSize + FirstIntOffset) % sizeof(int);
- LastIntMask = -1;
- LastIntMask >>= ((sizeof(int) - LastIntOffset) * 8);
-
- if (nbInts == 1)
- {
- if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned,
- *lpInt,
- LastIntMask & FirstIntMask)
- == 0)
- {
- goto CLEANUP2;
- }
- numberOfBytesWritten = nSize;
- ret = TRUE;
- goto CLEANUP2;
- }
-
- if (DBGWriteProcMem_IntWithMask(processId,
- lpBaseAddressAligned++,
- *lpInt++, FirstIntMask)
- == 0)
- {
- goto CLEANUP2;
- }
-
- while (--nbInts > 1)
- {
- if (DBGWriteProcMem_Int(processId, lpBaseAddressAligned++,
- *lpInt++) == 0)
- {
- goto CLEANUP2;
- }
- }
-
- if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned,
- *lpInt, LastIntMask ) == 0)
- {
- goto CLEANUP2;
- }
-
- numberOfBytesWritten = nSize;
- ret = TRUE;
-#endif // HAVE_TTRACE
- }
- else
- {
- /* Failed to attach processId */
- goto EXIT;
- }
-#endif // HAVE_PROCFS_CTL
-
-#if HAVE_PROCFS_CTL
-PROCFSCLEANUP:
- if (fd != -1)
- {
- close(fd);
- }
-#elif !HAVE_TTRACE
-CLEANUP2:
- if (lpTmpBuffer)
- {
- free(lpTmpBuffer);
- }
-#endif // !HAVE_TTRACE
-
-#if !HAVE_PROCFS_CTL
-CLEANUP1:
- if (!DBGDetachProcess(pThread, hProcess, processId))
- {
- /* Failed to detach processId */
- ret = FALSE;
- }
-#endif // !HAVE_PROCFS_CTL
-#endif // HAVE_VM_READ
-
-EXIT:
- if (lpNumberOfBytesWritten)
- {
- *lpNumberOfBytesWritten = numberOfBytesWritten;
+ return FALSE;
}
-
- LOGEXIT("WriteProcessMemory returns BOOL %d\n", ret.Load());
- PERF_EXIT(WriteProcessMemory);
- return ret;
+ return TRUE;
}
} // extern "C"
add_subdirectory(MapViewOfFile)
add_subdirectory(OpenFileMappingA)
add_subdirectory(OpenFileMappingW)
-add_subdirectory(ReadProcessMemory)
+add_subdirectory(ProbeMemory)
add_subdirectory(RtlMoveMemory)
add_subdirectory(UnlockFile)
add_subdirectory(UnmapViewOfFile)
cmake_minimum_required(VERSION 2.8.12.2)
-add_subdirectory(ReadProcessMemory_neg1)
+add_subdirectory(ProbeMemory_neg1)
add_subdirectory(test1)
-add_subdirectory(test2)
--- /dev/null
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ProbeMemory_neg.cpp
+)
+
+add_executable(paltest_probememory_probememory_neg1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_probememory_probememory_neg1 coreclrpal)
+
+target_link_libraries(paltest_probememory_probememory_neg1
+ pthread
+ m
+ coreclrpal
+)
{
int err;
BOOL bResult;
- HANDLE ProcessHandle;
- DWORD ProcessID;
LPVOID lpProcessAddress = NULL;
- char ProcessBuffer[REGIONSIZE];
- ULONG_PTR size = 0;
-
/*Initialize the PAL environment*/
err = PAL_Initialize(argc, argv);
return FAIL;
}
- /*retrieve the current process ID*/
- ProcessID = GetCurrentProcessId();
-
- /*retrieve the current process handle*/
- ProcessHandle = OpenProcess(
- PROCESS_ALL_ACCESS,
- FALSE, /*not inherited*/
- ProcessID);
-
- if(NULL == ProcessHandle)
- {
- Fail("\nFailed to call OpenProcess API to retrieve "
- "current process handle error code=%u\n",
- GetLastError());
- }
-
-
-
/*allocate the virtual memory*/
lpProcessAddress = VirtualAlloc(
NULL, /*system determine where to allocate the region*/
"virtual memory, error code=%u\n", GetLastError());
}
- /*zero the memory*/
- memset(ProcessBuffer, 0, REGIONSIZE);
- /*try to retrieve the unreadable memory area*/
- bResult = ReadProcessMemory(
- ProcessHandle, /*current process handle*/
+ /*try to probe the unreadable memory area*/
+ bResult = PAL_ProbeMemory(
lpProcessAddress, /*base of memory area*/
- (LPVOID)ProcessBuffer,
REGIONSIZE, /*buffer length in bytes*/
- &size);
-
+ FALSE); /*read access*/
/*check the return value*/
- if(0 != bResult)
+ if(bResult)
{
- Trace("\nFailed to call ReadProcessMemory API for a negative test, "
- "Try to read an unreadable memory area will cause fail "
- "but it successes\n");
-
- err = CloseHandle(ProcessHandle);
- if(0 == err)
- {
- Trace("\nFailed to call CloseHandle API, error code=%u\n",
- GetLastError());
- }
+ Trace("\nProbeMemory for read didn't FAILED\n");
/*decommit the specified region*/
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Trace("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
+
Fail("");
}
- err = CloseHandle(ProcessHandle);
- if(0 == err)
+ /*try to probe the unwriteable memory area*/
+ bResult = PAL_ProbeMemory(
+ lpProcessAddress, /*base of memory area*/
+ REGIONSIZE, /*buffer length in bytes*/
+ FALSE); /*write access */
+
+ /*check the return value*/
+ if(bResult)
{
- Trace("\nFailed to call CloseHandle API, error code = %u\n",
- GetLastError());
+ Trace("\nProbeMemory for write didn't FAILED\n");
+ /*decommit the specified region*/
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Trace("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
Fail("");
}
+
/*decommit the specified region*/
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Fail("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
PAL_Terminate();
Version = 1.0
Section = Filemapping_memmgt
-Function = ReadProcessMemory
-Name = Positive test for ReadProcessMemory API to read memory contents
+Function = PAL_ProbeMemory
+Name = Negative test PAL_ProbeMemory API to read unreadable memory area
TYPE = DEFAULT
-EXE1 = readprocessmemory
+EXE1 = probememory_neg
Description
-=Test the ReadProcessMemory to read the memory contents
+=Test the PAL_ProbeMemory to read unreadable memory area
--- /dev/null
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ProbeMemory.cpp
+)
+
+add_executable(paltest_probememory_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_probememory_test1 coreclrpal)
+
+target_link_libraries(paltest_probememory_test1
+ pthread
+ m
+ coreclrpal
+)
{
int err;
BOOL bResult;
- HANDLE ProcessHandle;
- DWORD ProcessID;
LPVOID lpProcessAddress = NULL;
- char ProcessBuffer[REGIONSIZE];
- ULONG_PTR size = 0;
-
/*Initialize the PAL environment*/
err = PAL_Initialize(argc, argv);
return FAIL;
}
- /*retrieve the current process ID*/
- ProcessID = GetCurrentProcessId();
-
- /*retrieve the current process handle*/
- ProcessHandle = OpenProcess(
- PROCESS_VM_READ,/*access flag*/
- FALSE, /*not inherited*/
- ProcessID);
-
- if(NULL == ProcessHandle)
- {
- Fail("\nFailed to call OpenProcess API to retrieve "
- "current process handle error code=%u\n",
- GetLastError());
- }
-
/*allocate the virtual memory*/
lpProcessAddress = VirtualAlloc(
NULL, /*system determine where to allocate the region*/
REGIONSIZE, /*specify the size*/
MEM_COMMIT, /*allocation type*/
- PAGE_READONLY); /*access protection*/
+ PAGE_READWRITE); /*access protection*/
if(NULL == lpProcessAddress)
{
"virtual memory, error code=%u!\n", GetLastError());
}
- /*zero the memory*/
- memset(ProcessBuffer, 0, REGIONSIZE);
-
- /*retrieve the memory contents*/
- bResult = ReadProcessMemory(
- ProcessHandle, /*current process handle*/
+ /*probe the memory for read*/
+ bResult = PAL_ProbeMemory(
lpProcessAddress, /*base of memory area*/
- (LPVOID)ProcessBuffer,
REGIONSIZE, /*buffer length in bytes*/
- &size);
+ FALSE); /*read access*/
- if(!bResult || REGIONSIZE != size)
+ if(!bResult)
{
- Trace("\nFailed to call ReadProcessMemory API "
- "to retrieve the memory contents, error code=%u\n",
- GetLastError());
-
- err = CloseHandle(ProcessHandle);
- if(0 == err)
- {
- Trace("\nFailed to call CloseHandle API, error code=%u\n",
- GetLastError());
- }
+ Trace("\nProbeMemory for read access FAILED\n");
/*decommit the specified region*/
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Trace("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
+
Fail("");
}
- err = CloseHandle(ProcessHandle);
- if(0 == err)
+ /*probe the memory for write */
+ bResult = PAL_ProbeMemory(
+ lpProcessAddress, /*base of memory area*/
+ REGIONSIZE, /*buffer length in bytes*/
+ TRUE); /*write access*/
+
+ if(!bResult)
{
- Trace("\nFailed to call CloseHandle API, error code = %u\n",
- GetLastError());
+ Trace("\nProbeMemory for write access FAILED\n");
+ /*decommit the specified region*/
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Trace("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
Fail("");
err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
if(0 == err)
{
- Fail("\nFailed to call VirtualFree API, error code=%u\n",
- GetLastError());
+ Fail("\nFailed to call VirtualFree API, error code=%u\n", GetLastError());
}
PAL_Terminate();
Version = 1.0
Section = Filemapping_memmgt
-Function = ReadProcessMemory
-Name = Negative test ReadProcessMemory API to read unreadable memory area
+Function = PAL_ProbeMemory
+Name = Positive test for PAL_ProbeMemory API to probe for read/write
TYPE = DEFAULT
-EXE1 = readprocessmemory_neg
+EXE1 = probememory
Description
-=Test the ReadProcessMemory to read unreadable memory area
+=Test the PAL_ProbeMemory to probe for read and write
+++ /dev/null
-cmake_minimum_required(VERSION 2.8.12.2)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(SOURCES
- ReadProcessMemory_neg.cpp
-)
-
-add_executable(paltest_readprocessmemory_readprocessmemory_neg1
- ${SOURCES}
-)
-
-add_dependencies(paltest_readprocessmemory_readprocessmemory_neg1 coreclrpal)
-
-target_link_libraries(paltest_readprocessmemory_readprocessmemory_neg1
- pthread
- m
- coreclrpal
-)
+++ /dev/null
-cmake_minimum_required(VERSION 2.8.12.2)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(SOURCES
- ReadProcessMemory.cpp
-)
-
-add_executable(paltest_readprocessmemory_test1
- ${SOURCES}
-)
-
-add_dependencies(paltest_readprocessmemory_test1 coreclrpal)
-
-target_link_libraries(paltest_readprocessmemory_test1
- pthread
- m
- coreclrpal
-)
+++ /dev/null
-cmake_minimum_required(VERSION 2.8.12.2)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(TESTSOURCES
- test2.cpp
-)
-
-add_executable(paltest_readprocessmemory_test2
- ${TESTSOURCES}
-)
-
-add_dependencies(paltest_readprocessmemory_test2 coreclrpal)
-
-target_link_libraries(paltest_readprocessmemory_test2
- pthread
- m
- coreclrpal
-)
-
-
-set(HELPERSOURCES
- helper.cpp
-)
-
-add_executable(paltest_readprocessmemory_test2_helper
- ${HELPERSOURCES}
-)
-
-add_dependencies(paltest_readprocessmemory_test2_helper coreclrpal)
-
-target_link_libraries(paltest_readprocessmemory_test2_helper
- pthread
- m
- coreclrpal
-)
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=============================================================
-**
-** Source: commonconsts.h
-**
-**
-**============================================================*/
-
-#ifndef _COMMONCONSTS_H_
-#define _COMMONCONSTS_H_
-
-#include <pal.h>
-#define REGIONSIZE 1024
-
-const int TIMEOUT = 40000;
-
-const WCHAR szcToHelperEvName[] = { 'T', 'o', '\0' };
-const WCHAR szcFromHelperEvName[] = { 'F', 'r', 'o', 'm', '\0' };
-
-const char initialValue = '-';
-const char nextValue = '|';
-const char guardValue = '*';
-const char *commsFileName = "AddrNLen.dat";
-
-
-/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any
- * zero return codes in a generic way. with little typing */
-#define PEDANTIC(function, parameters) \
-{ \
- if (! (function parameters) ) \
- { \
- Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
- __FILE__, #function, #parameters, GetLastError(), errno); \
- } \
-}
-#define PEDANTIC1(function, parameters) \
-{ \
- if ( (function parameters) ) \
- { \
- Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
- __FILE__, #function, #parameters, GetLastError(), errno); \
- } \
-}
-
-#endif
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=============================================================
-**
-** Source: helper.c
-**
-** Purpose: This helper process sets up a several blocks of memory,
-** then uses a file to tell its parent process where that memory is
-** So it can do a WriteProcessMemory on it. When the parent process is done
-** we check here that it was written properly.
-**
-**
-**============================================================*/
-
-#include "commonconsts.h"
-
-#include <palsuite.h>
-
-#if defined(BIT64) && defined(PLATFORM_UNIX)
-#define LLFORMAT "%I64u"
-#else
-#define LLFORMAT "%u"
-#endif
-
-struct allhandles_t
-{
- HANDLE hEvToHelper;
- HANDLE hEvFromHelper;
- char *valuesFileName;
-};
-
-
-/* function: wpmDoIt
- *
- * This is a general WriteProcessMemory testing function that sets up
- * the RAM pointed to and tells the companion process on the other end
- * of the handles in 'Comms' to attempt to alter 'lenDest' bytes at
- * '*pDest'.
- *
- * '*pBuffer'[0..'lenBuffer'] is expected to be a guard region
- * surrounding the '*pDest'[0..'lenDest'] region so that this function
- * can verify that only the proper bytes were altered.
- */
-
-int wpmDoIt(struct allhandles_t Comms,
- char * pBuffer, unsigned int lenBuffer,
- char * pDest, unsigned int lenDest,
- const char* storageDescription)
-{
- char *pCurr;
- FILE *commsFile;
- DWORD dwRet;
-
- if (pBuffer > pDest || lenDest > lenBuffer)
- {
- Trace("WriteProcessMemory::DoIt() test implementation: "
- "(pBuffer > pDest || lenDest > lenBuffer)\n");
- return FALSE;
- }
-
- /* set up the storage */
- memset(pBuffer, guardValue, lenBuffer);
- memset(pDest, initialValue, lenDest);
-
- /* tell the parent what RAM to adjust */
- if(!(commsFile = fopen(Comms.valuesFileName, "w")))
- {
- Trace("WriteProcessMemory: fopen of '%S' failed (%u). \n",
- Comms.valuesFileName, GetLastError());
- return FALSE;
- }
- if (!fprintf(commsFile, LLFORMAT " " LLFORMAT " '%s'\n",
- pDest, lenDest, storageDescription))
- {
- Trace("WriteProcessMemory: fprintf to '%S' failed (%u). \n",
- Comms.valuesFileName, GetLastError());
- return FALSE;
- }
- PEDANTIC1(fclose, (commsFile));
-
- /* Tell the parent the data is ready for it to adjust */
- PEDANTIC(ResetEvent, (Comms.hEvToHelper));
- PEDANTIC(SetEvent, (Comms.hEvFromHelper));
-
- dwRet = WaitForSingleObject(Comms.hEvToHelper, TIMEOUT); /* parent is done */
- if (dwRet != WAIT_OBJECT_0)
- {
- Trace("helper WaitForSingleObjectTest: WaitForSingleObject "
- "failed (%u)\n", GetLastError());
- return FALSE;
- }
-
- /* check the stuff that SHOULD have changed */
- for (pCurr = pDest; pCurr < (pDest + lenDest); pCurr++)
- {
- if ( *pCurr != nextValue)
- {
- Trace("When testing '%s': alteration test failed "
- "at " LLFORMAT " offset " LLFORMAT " Found '%c' instead of '%c'\n.",
- storageDescription, pDest, pCurr - pDest, *pCurr, nextValue);
- Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
- return FALSE;
- }
- }
- /* check the stuff that should NOT have changed */
- for (pCurr = pBuffer; pCurr < pDest; pCurr++ )
- {
- if ( *pCurr != guardValue)
- {
- Trace("When testing '%s': leading guard zone test failed "
- "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.",
- storageDescription, pDest, pCurr - pBuffer, *pCurr, guardValue);
- Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
- return FALSE;
- }
- }
- for (pCurr = pDest + lenDest; pCurr < (pBuffer + lenBuffer); pCurr++ )
- {
- if ( *pCurr != guardValue)
- {
- Trace("When testing '%s': trailing guard zone test failed "
- "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.",
- storageDescription, pDest + lenDest, pCurr - pBuffer, *pCurr, guardValue);
- Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-int __cdecl main(int argc, char *argv[])
-{
-
- BOOL success = TRUE; /* assume success */
- struct allhandles_t Comms = {0,0,0} ;
-
- /* variables to track storage to alter */
- char *pTarget = NULL;
- unsigned int sizeTarget;
-
- if(0 != (PAL_Initialize(argc, argv)))
- {
- return FAIL;
- }
-
- /* hook up with the events created by the parent */
- Comms.hEvToHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcToHelperEvName);
- if (!Comms.hEvToHelper)
- {
- Fail("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
- "(the event should already exist!)\n",
- szcToHelperEvName, GetLastError());
- }
- Comms.hEvFromHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcFromHelperEvName);
- if (!Comms.hEvToHelper)
- {
- Trace("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
- "(the event should already exist!)\n",
- szcFromHelperEvName, GetLastError());
- success = FALSE;
- goto EXIT;
- }
- Comms.valuesFileName = argv[1];
-
- {
- char autoAllocatedOnStack[51];
-
- /* Get the parent process to write to the local stack */
- success &= wpmDoIt(Comms, autoAllocatedOnStack,
- sizeof(autoAllocatedOnStack),
- autoAllocatedOnStack + sizeof(int),
- sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
- "const size array on stack with int sized guards");
- }
-
- /* Get the parent process to write to stuff on the heap */
- sizeTarget = 2 * sizeof(int) + 23 ; /* 23 is just a random prime > 16 */
- if (!(pTarget = (char*)malloc(sizeTarget)))
- {
- Trace("WriteProcessMemory helper: unable to allocate '%s'->%d bytes of memory"
- "(%u).\n",
- argv[3], sizeTarget, GetLastError());
- success = FALSE;
- goto EXIT;
-
- }
- success &= wpmDoIt(Comms, pTarget, sizeTarget,
- pTarget + sizeof(int),
- sizeTarget - 2 * sizeof(int),
- "array on heap with int sized guards");
-
- /* just to be nice try something 16 - 2 * sizeof(int) bytes long */
- {
- char autoAllocatedOnStack[16];
-
- /* Get the parent process to write to the local stack */
- success &= wpmDoIt(Comms, autoAllocatedOnStack,
- sizeof(autoAllocatedOnStack),
- autoAllocatedOnStack + sizeof(int),
- sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
- "another 16 byte array on stack with int sized guards inside");
- }
-
- /* NOTE: Don't try 0 bytes long. Win32 WriteProcessMemory claims
- * it writes 8 bytes in that case! */
-
- /* and 1 byte long... */
- {
- char autoAllocatedOnStack[1+ 2 * sizeof(int)];
-
- /* Get the parent process to write to the local stack */
- success &= wpmDoIt(Comms, autoAllocatedOnStack,
- sizeof(autoAllocatedOnStack),
- autoAllocatedOnStack + sizeof(int),
- 1,
- "no bytes with int sized guards outside on stack");
- }
-
-
-EXIT:
- /* Tell the parent that we are done */
- if (!DeleteFile(Comms.valuesFileName))
- {
- Trace("helper: DeleteFile failed so parent (test1) is unlikely "
- "to exit cleanly\n");
- }
- PEDANTIC(ResetEvent, (Comms.hEvToHelper));
- if (!SetEvent(Comms.hEvFromHelper))
- {
- Trace("helper: SetEvent failed so parent (test1) is unlikely "
- "to exit cleanly\n");
- }
-
- free(pTarget);
- PEDANTIC(CloseHandle, (Comms.hEvToHelper));
- PEDANTIC(CloseHandle, (Comms.hEvFromHelper));
-
- if (!success)
- {
- Fail("");
- }
-
- PAL_Terminate();
-
- return success ? PASS : FAIL;
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=============================================================
-**
-** Source: test2.c
-**
-** Purpose: Create a child process and some events for communications with it.
-** When the child gets back to us with a memory location and a length,
-** Call WriteProcessMemory on this location and check to see that it
-** writes successfully. Then call ReadProcessMemory to check if the
-** contents read are same as those written
-**
-**
-**============================================================*/
-
-#define UNICODE
-
-#include "commonconsts.h"
-
-#include <palsuite.h>
-
-#if defined(BIT64) && defined(PLATFORM_UNIX)
-#define LLFORMAT "%I64u"
-#else
-#define LLFORMAT "%u"
-#endif
-
-int __cdecl main(int argc, char *argv[])
-{
-
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
- HANDLE hEvToHelper;
- HANDLE hEvFromHelper;
- DWORD dwExitCode;
-
- DWORD dwRet;
- char cmdComposeBuf[MAX_PATH];
- PWCHAR uniString;
-
- if(0 != (PAL_Initialize(argc, argv)))
- {
- return FAIL;
- }
-
- /* Create the signals we need for cross process communication */
- hEvToHelper = CreateEvent(NULL, TRUE, FALSE, szcToHelperEvName);
- if (!hEvToHelper)
- {
- Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
- "GetLastError() returned %d.\n", szcToHelperEvName,
- GetLastError());
- }
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- {
- Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
- "(already exists!)\n", szcToHelperEvName);
- }
- hEvFromHelper = CreateEvent(NULL, TRUE, FALSE, szcFromHelperEvName);
- if (!hEvToHelper)
- {
- Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
- "GetLastError() returned %d.\n", szcFromHelperEvName,
- GetLastError());
- }
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- {
- Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
- "(already exists!)\n", szcFromHelperEvName);
- }
- ResetEvent(hEvFromHelper);
- ResetEvent(hEvToHelper);
-
- if (!sprintf_s(cmdComposeBuf, _countof(cmdComposeBuf), "helper %s", commsFileName))
- {
- Fail("Could not convert command line\n");
- }
- uniString = convert(cmdComposeBuf);
-
- ZeroMemory( &si, sizeof(si) );
- si.cb = sizeof(si);
- ZeroMemory( &pi, sizeof(pi) );
-
- /* Create a new process. This is the process that will ask for
- * memory munging */
- if(!CreateProcess( NULL, uniString, NULL, NULL,
- FALSE, 0, NULL, NULL, &si, &pi))
- {
- Trace("ERROR: CreateProcess failed to load executable '%S'. "
- "GetLastError() returned %u.\n",
- uniString, GetLastError());
- free(uniString);
- Fail("");
- }
- free(uniString);
-
-
- while(1)
- {
- FILE *commsFile;
- char* pSrcMemory;
- char* pDestMemory;
- SIZE_T Count;
- SIZE_T wpmCount;
- char incomingCMDBuffer[MAX_PATH + 1];
-
- int err;
- HANDLE readProcessHandle;
- DWORD readProcessID;
- char readProcessBuffer[REGIONSIZE]; // size 1024
- BOOL bResult;
- size_t size = 0;
-
- readProcessID = pi.dwProcessId;
-
- /* wait until the helper tells us that it has given us
- * something to do */
- dwRet = WaitForSingleObject(hEvFromHelper, TIMEOUT);
- if (dwRet != WAIT_OBJECT_0)
- {
- Trace("test1 WaitForSingleObjectTest: WaitForSingleObject "
- "failed (%u)\n", GetLastError());
- break; /* no more work incoming */
- }
-
- /* get the parameters to test WriteProcessMemory with */
- if (!(commsFile = fopen(commsFileName, "r")))
- {
- /* no file means there is no more work */
- break;
- }
- if ( NULL == fgets(incomingCMDBuffer, MAX_PATH, commsFile))
- {
- Fail ("unable to read from communication file %s "
- "for reasons %u & %u\n",
- errno, GetLastError());
- }
- PEDANTIC1(fclose,(commsFile));
- sscanf_s(incomingCMDBuffer, LLFORMAT " " LLFORMAT, &pDestMemory, &Count);
- if (argc > 1)
- {
- Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT "('%s')\n",
- Count, pDestMemory, incomingCMDBuffer);
- }
-
- /* compose some data to write to the client process */
- if (!(pSrcMemory = (char*)malloc(Count)))
- {
- Trace("could not dynamically allocate memory to copy from "
- "for reasons %u & %u\n",
- errno, GetLastError());
- goto doneIteration;
- }
- memset(pSrcMemory, nextValue, Count);
- Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')[%u]\n",
- Count, pDestMemory, incomingCMDBuffer, pSrcMemory);
-
- /* do the work */
- dwRet = WriteProcessMemory(pi.hProcess,
- pDestMemory,
- pSrcMemory,
- Count,
- &wpmCount);
-
- if (!dwRet)
- {
- Trace("%s: Problem: on a write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')\n",
- argv[0], Count, pDestMemory, incomingCMDBuffer);
- Trace("test1 WriteProcessMemory returned a (!=0) (GLE=%u)\n",
- GetLastError());
- }
- if(Count != wpmCount)
- {
- Trace("%s: Problem: on a write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')\n",
- argv[0], Count, pDestMemory, incomingCMDBuffer);
- Trace("The number of bytes written should have been "
- LLFORMAT ", but was reported as " LLFORMAT " \n", Count, wpmCount);
- }
-
- readProcessHandle = OpenProcess(
- PROCESS_VM_READ,
- FALSE,
- readProcessID);
-
- if(NULL == readProcessHandle)
- {
- Fail("\nFailed to call OpenProcess API to retrieve "
- "current process handle error code=%u\n",
- GetLastError());
- }
-
- /*zero the memory*/
- memset(readProcessBuffer, 0, size);
-
- /*retrieve the memory contents*/
- bResult = ReadProcessMemory(
- readProcessHandle, /*current process handle*/
- pDestMemory, /*base of memory area*/
- (LPVOID)readProcessBuffer,
- Count, /*buffer length in bytes*/
- &size);
-
-
- if( !bResult || (Count != size) )
- {
- Trace("\nFailed to call ReadProcessMemory API "
- "to retrieve the memory contents, error code=%u; Bresult[%u] Count[" LLFORMAT "], Size[%d]\n",
- GetLastError(), bResult, Count, size);
-
- err = CloseHandle(readProcessHandle);
-
- if(0 == err)
- {
- Trace("\nFailed to call CloseHandle API, error code=%u\n",
- GetLastError());
- }
- dwExitCode = FAIL;
- }
-
- if( !memcmp (pDestMemory, readProcessBuffer, Count ) )
- {
- Trace("Difference in memory contents, expected [%s], but received [%s]\n", pDestMemory, readProcessBuffer);
- dwExitCode = FAIL;
- }
-
- Trace("ReadProcessBuffer contains [%s]\n", readProcessBuffer);
- err = CloseHandle(readProcessHandle);
-
- free(pSrcMemory);
-
- doneIteration:
- PEDANTIC(ResetEvent, (hEvFromHelper));
- PEDANTIC(SetEvent, (hEvToHelper));
- }
-
- /* wait for the child process to complete */
- WaitForSingleObject ( pi.hProcess, TIMEOUT );
- /* this may return a failure code on a success path */
-
- /* check the exit code from the process */
- if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
- {
- Trace( "GetExitCodeProcess call failed with error code %u\n",
- GetLastError() );
- dwExitCode = FAIL;
- }
-
-
- PEDANTIC(CloseHandle, (hEvToHelper));
- PEDANTIC(CloseHandle, (hEvFromHelper));
- PEDANTIC(CloseHandle, (pi.hThread));
- PEDANTIC(CloseHandle, (pi.hProcess));
-
- PAL_TerminateEx(dwExitCode);
- return dwExitCode;
-}
+++ /dev/null
-# Licensed to the .NET Foundation under one or more agreements.
-# The .NET Foundation licenses this file to you under the MIT license.
-# See the LICENSE file in the project root for more information.
-
-Version = 1.0
-Section = Debug
-Function = ReadProcessMemory
-Name = Check that writing/reading text to/from process memory succeeds.
-TYPE = DEFAULT
-EXE1 = test2
-EXE2 = helper
-Description
-= Create a child process and attempt to write to its memory
-= at the places and lengths it specifies via a data file.
-= the child verifies that all the specified memory was altered
-= with no overruns. Parent then tries to read memory from child
-= and does memory compare to ensure it read memory contents
-= correctly
filemapping_memmgt/MapViewOfFile/test4/paltest_mapviewoffile_test4
filemapping_memmgt/MapViewOfFile/test5/paltest_mapviewoffile_test5
filemapping_memmgt/MapViewOfFile/test6/paltest_mapviewoffile_test6
+filemapping_memmgt/ProbeMemory/test1/paltest_probememory_test1
+filemapping_memmgt/ProbeMemory/ProbeMemory_neg1/paltest_probememory_probememory_neg1
filemapping_memmgt/RtlMoveMemory/test1/paltest_rtlmovememory_test1
filemapping_memmgt/RtlMoveMemory/test3/paltest_rtlmovememory_test3
filemapping_memmgt/RtlMoveMemory/test4/paltest_rtlmovememory_test4
add_subdirectory(test6)
add_subdirectory(test7)
add_subdirectory(test8)
-add_subdirectory(test9)
outstring.cpp
ilformatter.cpp
opinfo.cpp
- dacutil.cpp
sortversioning.cpp
corimage.cpp
format1.cpp
if(WIN32)
list(APPEND UTILCODE_COMMON_SOURCES
appxutil.cpp
+ dacutil.cpp
dlwrap.cpp
downlevel.cpp
loadrc.cpp
#include "common.h"
/*******************************************************************/
-/* The folowing routines used to exist in all builds so they could called from the
+/* The following routines used to exist in all builds so they could called from the
* debugger before we had strike.
- * Now most of them are only inclued in debug builds for diagnostics purposes.
+ * Now most of them are only included in debug builds for diagnostics purposes.
*/
/*******************************************************************/
}
CONTRACTL_END;
+#if !defined(DACCESS_COMPILE) && defined(FEATURE_PAL)
+
+ return PAL_ProbeMemory((PVOID)start, len, FALSE);
+
+#else // !DACCESS_COMPILE && FEATURE_PAL
+
//
// To accomplish this in a no-throw way, we have to touch each and every page
// and see if it is in memory or not.
}
return 1;
+#endif // !DACCESS_COMPILE && FEATURE_PAL
}