summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAditya Mandaleeka <adityam@microsoft.com>2016-01-14 12:38:45 -0800
committerAditya Mandaleeka <adityam@microsoft.com>2016-01-14 12:44:21 -0800
commita1cbc293fe66e33fbb815b018c5f3e5da76a7dfc (patch)
tree919ab3cd2954808e5f547171a3703d34b7626771 /src
parentdb743bc4103e78484bd0dac54a1b887da63a7059 (diff)
downloadcoreclr-a1cbc293fe66e33fbb815b018c5f3e5da76a7dfc.tar.gz
coreclr-a1cbc293fe66e33fbb815b018c5f3e5da76a7dfc.tar.bz2
coreclr-a1cbc293fe66e33fbb815b018c5f3e5da76a7dfc.zip
Add hardware exception handling back to Read/WriteProcessMemory
Diffstat (limited to 'src')
-rw-r--r--src/pal/src/debug/debug.cpp1197
1 files changed, 602 insertions, 595 deletions
diff --git a/src/pal/src/debug/debug.cpp b/src/pal/src/debug/debug.cpp
index fa8aa3848f..9a9fefcdb0 100644
--- a/src/pal/src/debug/debug.cpp
+++ b/src/pal/src/debug/debug.cpp
@@ -547,600 +547,6 @@ SetThreadContext(
return ret;
}
-/*++
-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
- )
-{
- 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;
- 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)
- {
- 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;
- }
-
-#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;
- }
- // 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)
- {
- 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;
- }
- memcpy((LPSTR)lpBuffer + numberOfBytesRead, data + offset, bytesToRead);
- numberOfBytesRead.Store(numberOfBytesRead.Load() + bytesToRead);
- lpBaseAddressAligned = (int*)((char*)lpBaseAddressAligned + VIRTUAL_PAGE_SIZE);
- nSize -= bytesToRead;
- offset = 0;
- }
- 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)
- {
- InternalFree(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
-
-See MSDN doc.
---*/
-BOOL
-PALAPI
-WriteProcessMemory(
- IN HANDLE hProcess,
- IN LPVOID lpBaseAddress,
- IN LPCVOID lpBuffer,
- IN SIZE_T nSize,
- OUT SIZE_T * lpNumberOfBytesWritten
- )
-
-{
- 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;
- 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)
- {
- 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;
- }
-
- 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))
- {
-#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)
- {
- InternalFree(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;
- }
-
- LOGEXIT("WriteProcessMemory returns BOOL %d\n", ret.Load());
- PERF_EXIT(WriteProcessMemory);
- return ret;
-}
-
#if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
/*++
Function:
@@ -1815,4 +1221,605 @@ PAL_DeleteExecWatchpointExit:
return dwError;
}
-} // extern "C"
+// 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
+ )
+{
+ 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;
+ 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)
+ {
+ 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;
+ }
+
+#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;
+ }
+ // 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)
+ {
+ 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;
+ }
+ memcpy((LPSTR)lpBuffer + numberOfBytesRead, data + offset, bytesToRead);
+ numberOfBytesRead.Store(numberOfBytesRead.Load() + bytesToRead);
+ lpBaseAddressAligned = (int*)((char*)lpBaseAddressAligned + VIRTUAL_PAGE_SIZE);
+ nSize -= bytesToRead;
+ offset = 0;
+ }
+ 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)
+ {
+ InternalFree(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
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+WriteProcessMemory(
+ IN HANDLE hProcess,
+ IN LPVOID lpBaseAddress,
+ IN LPCVOID lpBuffer,
+ IN SIZE_T nSize,
+ OUT SIZE_T * lpNumberOfBytesWritten
+ )
+
+{
+ 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;
+ 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)
+ {
+ 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;
+ }
+
+ 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))
+ {
+#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)
+ {
+ InternalFree(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;
+ }
+
+ LOGEXIT("WriteProcessMemory returns BOOL %d\n", ret.Load());
+ PERF_EXIT(WriteProcessMemory);
+ return ret;
+}
+
+} // extern "C" \ No newline at end of file