summaryrefslogtreecommitdiff
path: root/src/pal/src/debug/debug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/debug/debug.cpp')
-rw-r--r--src/pal/src/debug/debug.cpp1087
1 files changed, 36 insertions, 1051 deletions
diff --git a/src/pal/src/debug/debug.cpp b/src/pal/src/debug/debug.cpp
index 5461ac6265..2f7d17cabe 100644
--- a/src/pal/src/debug/debug.cpp
+++ b/src/pal/src/debug/debug.cpp
@@ -92,29 +92,6 @@ static const char PAL_OUTPUTDEBUGSTRING[] = "PAL_OUTPUTDEBUGSTRING";
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" {
/*++
@@ -566,457 +543,6 @@ SetThreadContext(
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
- sprintf(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
@@ -1240,605 +766,64 @@ PAL_DeleteExecWatchpointExit:
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, &param)
- {
- 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, &param)
- {
- 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"